MIT6.824 第二节课RPC部分

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: “最大努力”对应用程序来说容易处理吗?

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值