CSE_lecture5:Remote Procedure Call
Remote Procedure Call
RPC让文件系统变成远程,同时让远程服务器像运行在本地一样,相比于sockets api,RPC不必因为突然变成远程服务器而修改代码,即这个接口应当同时能访问本地和远程
为了不改应用的高层代码,将缺乏语义的共同部分打包成RPC stub
client stub做以下事情:发请求,接受响应,进行convert
server stub做以下事情:使用一个do forever不断接受请求,根据参数进行switch case,从而判断响应OK与否
其中message里面包括:
- service id
- service parameter
- marshal/unmarshal: 即保证object以序列化的形式传输,从而替代指针,收到消息后根据规则进行反序列化
RPC request message包括:
- Xid: 即transaction id,保证每个消息都有一个id,便于重发
- call/reply
- rpc version
- program #: 调用哪个程序(库文件)
- program version
- procedure #: 调用哪个函数
- auth staff
- arguments: 需要序列化
RPC reply message包括以下部分:
- Xid
- call/reply
- accepted?: 用于判定RPC version
- auth staff
- success?: 用于判定prog/proc
- results: 需要序列化
binding用于寻找服务器,这是依靠服务注册实现的
how to pass the data between client & server?
参数传递充满挑战性:
- 跨服务器无法pass by reference,因此需要转换成pointless
- 大小端的问题
- client和server的兼容性
为了表示数据,需要进行encoding,这一般不会是语言特化的
standard encoding有JSON, XML, CSV等等,好处是人类可读,缺点是可能有二义性、binary strings支持困难等等
而binary formats难以阅读,但更紧凑、更准确、性能更好
JSON每次传输时都要出现字段名,而Thrift和Protocol Buffers使用schema来将字段及其类型进行编号码,从而进行压缩
以Thrift为例:
压缩还可以进一步进行,需要将这些0去除,比如记录field tag的差值,将数字变为链表存储等等:
stub代码可以自动生成,这只需要头文件即可
marshal/unmarshal也有可能反而耗时,因此其适用于慢的网速,而网速快时反而不需要压缩(这里是说是否有必要利用marshal的压缩功能,对于指针参数,marshal是必要的)
when RPC meets failure
本地调用基本不会出错,但RPC却可能遇到各种各样的错误,而我们的目标为只需要一次调用,而现在有三种场景:
- at-least-once: 反复retry即可
- at-most-once: server记录Xid,出现retry时将过去的结果返回,但问题在于什么时候删除
- exactly-once: 很困难
需要区分幂等性(idempotent)和非幂等性,幂等的操作反复执行结果是一致的,配合at-least-once可以实现exactly-once