分布式系统:RPC

如何做到可靠的RPC

  • RPC可能会遇到什么故障?

    • 包丢失、断网、服务器太慢、服务器崩溃(crash)
  • 客户端没有收到回复,就可以认为是出错了

    • 但是它无法区分到底服务器执行了命令没有。
    • 可能服务器没有见到请求
    • 可能服务器没有执行请求就崩溃了
    • 可能服务器执行完请求,还没有来得及发回复就崩溃了。
  • 没有收到回复的时候,RPC可以选择实现这几种语义:

    • 不重发(Go RPC)
    • 尽最大努力"best effort":简单地重试几次。服务器端会收到重复请求。
    • 最多一次(at most once):服务器端记录并分辨重复请求。
    • 恰好一次(exactly once):比较复杂!

“best effort”

  • 最简单的处理办法是: “best effort”(尽最大努力)

    • Call() 等待答复,等一段时间
    • 如果超时了,就重新发送
    • 如此反复几次
    • 还是没用,就放弃并返回error
    • 附注:ZeroMQ的手册里面,给这个再普通不过的方法起了个很神秘的名字:Lazy Pirate Client
  • “尽最大努力”有些时候是不对的。服务器有会收到重复的请求。

    • 比如:客户端执行
      Put("k", 10);
      Put("k", 20);
    • 两条命令都成功。照理说状态应该是 k = 20
    • 但是如果第一条执行时有超时重发。成功了。再执行第二条,等第二条执行完了,第一条又再次被收到。(有重发就有可能收到2次)
    • 如果服务器不加区分,又再次执行第一条。此时状态就变成 k = 10,与客户端想达到的效果不同。
  • “尽最大努力”有时候是足够的。

    • 只做读的操作
    • 总之就是多次执行与一次执行效果一样的。

最多一次(at most once)

  • 第二种方法是“最多一次”(at most once)
  • idea: 服务器端检测重复的请求
    如果发现重复的,就返回之前相同请求的回复消息
  • 如何发现重复请求?——给请求加编号!
  • 编号有两种:(1)用一个大的随机数、(2)顺序编号1、2、3……。

过往的rpc记录要保存多久才够安全?

  • idea:
    • 每个客户端有唯一ID(可以用大随机数)
    • 每个客户端各自对rpc进行序列编号
    • 客户端的每个rpc请求中,加入"已经见过所有编号小于X的reply“的信息
    • 很像TCP协议的编号和确认机制。(也就是sliding window?)
      或者:只允许客户端一个请求成功收到答复,才能发下一个。
      那么,收到x+1序号的请求,就可以丢弃所有编号小于等于x的旧rpc记录。
      注:一种是类似tcp,为了扩大吞吐量,客户端可以发多个请求。比较复杂,要用sliding window。另一种类似TFTP的stop and wait。

如果原来的rpc还未执行完,就收到重复请求怎么办?

  • idea: 在rpc请求中加上一个"pending"标志。让客户端选择是要直接丢弃还是等待结果。

如何处理服务器端的崩溃和重启

  • idea:
  • 去重信息应该记录在磁盘(记录在内存重启就丢失了)
  • 副本服务器也要对去重信息做副本。

Go RPC(不重发)

  • Go RPC采取的是“绝不重发”。如果RPC返回错误,可能是:
    • TCP超时
    • 服务器没有收到请求
    • 服务器已经处理完请求,但是返回消息没有传回客户端(由于网络问题,或者服务器挂了)。

恰好一次

  • 最理想的是实现恰好一次(exactly once),但是不容易做到。
  • 无限重试 + 去重检测 + 服务端的故障容忍(Lab3)

原文链接:

https://pdos.csail.mit.edu/6.824/notes/l-rpc.txt

你可能感兴趣的:(分布式系统:RPC)