欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

MIT6.824 远程过程调用RPC使用

程序员文章站 2022-08-13 09:31:49
Remote Procedure Call (RPC) a key piece of distributed system machinery; all the labs use RPC goal: easy-to-program client/server communication hide details of network protocols convert data (strings, arrays, maps, &c) to "wire format"远程过.....
Remote Procedure Call (RPC)
  a key piece of distributed system machinery; all the labs use RPC
  goal: easy-to-program client/server communication
  hide details of network protocols
  convert data (strings, arrays, maps, &c) to "wire format"


远程过程调用(RPC)

分布式系统机械的关键部件;所有实验室都使用RPC

目标:易于编程客户机/服务器通信

隐藏网络协议的详细信息

将数据(字符串、数组、映射和c)转换为“有线格式”


RPC message diagram:
  Client             Server
    request--->
       <---response

Software structure
  client app        handler fns
   stub fns         dispatcher
   RPC lib           RPC lib
     net  ------------ net


Go example: kv.go on schedule page
  A toy key/value storage server -- Put(key,value), Get(key)->value
  Uses Go's RPC library
  Common:
    Declare Args and Reply struct for each server handler.
  Client:
    connect()'s Dial() creates a TCP connection to the server
    get() and put() are client "stubs"
    Call() asks the RPC library to perform the call
      you specify server function name, arguments, place to put reply
      library marshalls args, sends request, waits, unmarshalls reply
      return value from Call() indicates whether it got a reply
      usually you'll also have a reply.Err indicating service-level failure

调试分析以下这几段代码

package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"
	"sync"
)

//
// Common RPC request/reply definitions
//

const (
	OK       = "OK"
	ErrNoKey = "ErrNoKey"
)

type Err string

type PutArgs struct {
	Key   string
	Value string
}

type PutReply struct {
	Err Err
}

type GetArgs struct {
	Key string
}

type GetReply struct {
	Err   Err
	Value string
}

//
// Client
//

func connect() *rpc.Client {
	client, err := rpc.Dial("tcp", ":1234")
	if err != nil {
		log.Fatal("dialing:", err)
	}
	return client
}

func get(key string) string {
	client := connect()
	args := GetArgs{"subject"}
	reply := GetReply{}
	err := client.Call("KV.Get", &args, &reply)
	if err != nil {
		log.Fatal("error:", err)
	}
	client.Close()
	return reply.Value
}

func put(key string, val string) {
	client := connect()
	args := PutArgs{"subject", "6.824"}
	reply := PutReply{}
	err := client.Call("KV.Put", &args, &reply)
	if err != nil {
		log.Fatal("error:", err)
	}
	client.Close()
}

//
// Server
//

type KV struct {
	mu   sync.Mutex
	data map[string]string
}

func server() {
	kv := new(KV)
	kv.data = map[string]string{}
	rpcs := rpc.NewServer()
	rpcs.Register(kv)
	l, e := net.Listen("tcp", ":1234")
	if e != nil {
		log.Fatal("listen error:", e)
	}
	go func() {
		for {
			conn, err := l.Accept()
			if err == nil {
				go rpcs.ServeConn(conn)
			} else {
				break
			}
		}
		l.Close()
	}()
}

func (kv *KV) Get(args *GetArgs, reply *GetReply) error {
	kv.mu.Lock()
	defer kv.mu.Unlock()

	val, ok := kv.data[args.Key]
	if ok {
		reply.Err = OK
		reply.Value = val
	} else {
		reply.Err = ErrNoKey
		reply.Value = ""
	}
	return nil
}

func (kv *KV) Put(args *PutArgs, reply *PutReply) error {
	kv.mu.Lock()
	defer kv.mu.Unlock()

	kv.data[args.Key] = args.Value
	reply.Err = OK
	return nil
}

//
// main
//

func main() {
	server()

	put("subject", "6.824")
	fmt.Printf("Put(subject, 6.824) done\n")
	fmt.Printf("get(subject) -> %s\n", get("subject"))
}


示例:kv.go按计划页面

一个玩具键/值存储服务器——Put(key,value),Get(key)->value

使用Go的RPC库

普通:

为每个服务器处理程序声明参数和应答结构。

客户:

connect()的Dial()创建到服务器的TCP连接

get()和put()是客户端“存根”

Call()要求RPC库执行调用

指定服务器函数名、参数、放置回复的位置

库封送args、发送请求、等待、解组应答

Call()的返回值指示它是否得到回复

通常你也会有回答。错误指示服务级别故障


服务器:

Go要求服务器将方法声明为RPC处理程序的对象

然后,服务器向RPC库注册该对象

服务器接受TCP连接,并将其提供给RPC库

RPC库

读取每个请求

为此请求创建新的goroutine

解组请求

查找命名对象(在create by Register()表中)

调用对象的命名方法(dispatch)

马歇尔回复

在TCP连接上写入回复

服务器的Get()和Put()处理程序

必须锁定,因为RPC库为每个请求创建一个新的goroutine

读取参数;修改答复.


一些细节:

绑定:客户机如何知道要与哪个服务器计算机通信?

对于Go的RPC,服务器名/端口是要拨号的参数

大系统有某种名称或配置服务器

编组:将数据格式化为数据包

Go的RPC库可以传递字符串、数组、对象、映射和c

Go通过复制指向的数据来传递指针

无法传递通道或函数


C problem: what to do about failures?
e.g. lost packet, broken network, slow server, crashed server

What does a failure look like to the client RPC library?
Client never sees a response from the server
Client does *not* know if the server saw the request!
[diagram of losses at various points]
Maybe server never saw the request
Maybe server executed, crashed just before sending reply
Maybe server executed, but network died just before delivering reply

Simplest failure-handling scheme: "best effort"
Call() waits for response for a while
If none arrives, re-send the request
Do this a few times
Then give up and return an error

Q: is "best effort" easy for applications to cope with?


C问题:失败怎么办?

e、 包丢失,网络中断,服务器速度慢,服务器崩溃

对于客户端RPC库来说,失败是什么样子的?

客户端从未看到来自服务器的响应

客户机不知道服务器是否看到了请求!

【各点损失图】

也许服务器从来没有看到过这个请求

可能是服务器执行了,在发送回复之前崩溃了

可能服务器执行了,但网络在发送回复之前就死机了

最简单的故障处理方案:“尽力而为”

Call()等待一段时间的响应

如果没有收到,请重新发送请求

这样做几次

然后放弃并返回错误

Q: “最大努力”对应用程序来说容易处理吗?

本文地址:https://blog.csdn.net/wwxy1995/article/details/107978974

相关标签: 算法 rpc