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: “最大努力”对应用程序来说容易处理吗?
本文地址:https://blog.csdn.net/wwxy1995/article/details/107978974
上一篇: 直播怎么卖货,你必须掌握的三大要素
下一篇: HML串口屏与单片机通信
推荐阅读
-
使用nginx代理gogs遇到推送代码错误的问题(RPC failed; HTTP 413 curl 22 The requested URL returned error: 413)
-
MIT6.824 远程过程调用RPC使用
-
RPC原理与代码实现远程过程调用
-
RabbitMq 远程过程调用RPC(七)
-
RabbitMQ入门:远程过程调用(RPC)
-
Springboot整合RabbitMQ(六):远程过程调用(RPC)
-
RabbitMQ学习(六)之远程过程调用(RPC)
-
RabbitMQ教程远程过程调用RPC
-
RabbitMQ之远程过程调用(RPC)【译】
-
RabbitMQ (5) 远程过程调用(RPC)