celloworldNavigate back to the homepage

分布式系统笔记:RPC

hidaris
March 16th, 2019 · 1 min read

MIT 6.824中提到:

RPC ideally makes net communication look just like fn call

去年,我在和 wwj 实现 codelab adapter 时遇到了一个语义传递的问题:

  • 容易编写网络通信程序
  • 隐藏客户端与服务器通信的细节
  • 客户端调用更加像传统的过程调用
  • 服务端处理更加像传统的过程调用

我当时有语义学(程序语言)的学习背景,所以很自然的想到通过写一个解释器,在客户端用json编码AST并发送到服务端执行,后来我才知道这种设计等于重新发现了JSON RPC

RPC消息流程图:

1Client Server
2 request--->
3 work
4 <---response

软件架构

1client app handlers
2 stubs dispatcher
3RPC lib RPC lib
4   net ------------ net

使用上大概是这种感觉

1z = fn(x, y)
2
3def fn(x, y):
4 invote_remote_fn(x, y)

RPC设计目标是这种水平的透明度。

一些难点

  • 应该调用哪个服务器函数(handler)? 调用和被调用放生在不同的机器上,甚至不同的环境,操作系统
  • 序列化:格式化数据 数组,指针,对象等,还有一些语言特有的结构
  • 绑定:客户端如何知道该跟谁通信? 也许客户端使用服务器的 hostname。 也许使用命名服务
  • 线程: 客户端可能使用多线程,所以多于一个调用没有被处理,对应的处理器可能会是否缓慢,所以 服务器经常将每个请求放置在独立的线程中处理。

问题:怎么处理失败?

比如:丢包,网络断线,客户端崩溃,服务器运行缓慢,服务器崩溃。

错误对RPC客户端意味着什么?

  • 客户端没有获取到服务器的回复。
  • 客户端不知道服务器是否接收到请求!也许服务器的网络在发生请求前就失败了。

分区错误

在本地计算中,如果一个函数计算失败,那么整个调用就失败了,但是在分布式系统中,一个函数计算失败,这次调用只失败了一部分,原因在于不同机器之间不能感知到相互的失败,或者网络中断。

解决方法

(稻草人方法)使远程调用的行为类似于本地计算

  • 每次计算失败,我们都应该终止并重启整个系统。
  • 等待直到整个系统修复。

这个稻草人方法的问题在于,客户端会等待很久,而系统也不一定能恢复。 另一种方式是打破透明性 1. 正好一次:实际中不可能 2. 至少一次:只允许幂等操作 在客户端收到回复前,保持重发。 服务端对多次相同的操作产生一次正常执行的效果。 3. 至多一次:0次或1次 服务端可能会收到相同的请求两次… 必须重发之前的回复,并且不重新处理请求(意味着需要对于请求/回复进行缓存) 必须能对请求进行标识 稻草人: 记住全部处理的 RPC IDs. -> 需要无限的内存. 真实: 保持有效 RPC ID 的滑动窗口,按顺序拥有客户端编号。

参考

MIT 6.824 CMU 15-440

More articles from hidaris

分布式系统笔记:CAP定理

分布式系统中各个节点的状态如何同步是一个难题,CAP 定理是这个问题相关的定理,也是很多分布式系统设计的理论基础

March 8th, 2019 · 2 min read

为 emacs lsp python 添加 virtualenv 支持

emacs lsp-mode 不支持 virtualenv,在此分享我的解决方案

November 4th, 2018 · 1 min read
© 2016–2020 hidaris
Link to $https://twitter.com/zuodadaLink to $https://github.com/hidarisLink to $https://instagram.com/hidaris128