RPC(remote procedure call)
是一种计算机通信协议,允许调用不同进程的程序,而不必了解底层网络技术的协议。

基础

对比本地调用

本地调用:

def multiply(l, r):
    y = l * r
    return y

lvalue = 10
rvalue = 20
result = mutiply(lvalue, rvalue)

# 本地执行顺序:
# ① lvalue 和 rvalue 压栈
# ② 进入multiply函数,取出 lvalue rvalue,赋给lv
# ③ 计算,返回结果y
# ④ y值压栈,从函数返回
# ⑤ 从栈中取出值,赋给result

rpc调用:

result = call(serverAddr, multiply, lvalue, rvalue)
# 这里边除了函数multiply在server,其余都是client的。

client:
① 将⬆️的调用映射为call ID(假设用just str作ID)
② 将call ID,rvalue,lvalue序列化为二进制打包
③ 将②中得到的数据包发给serveraddr(需网络层传输)
④ 等server结果
⑤ if server调用成功,反序列化结果赋给result

server:
① 本地维护一个call ID到函数的map
② 等待请求
③ 得到请求后反序列化得到call ID
④ 查找map得到函数指针
⑤ lvalue,rvalue反序列化后本地调用multiply得到结果
⑥ 结果序列化后通过网络返回给client的result

如此看来,比起本地调用就是多了一层,将内容 序列化/反序列化的包装,以及网络层通信。那么这两个就是关键。

选择序列化的方式

好的可以提升封包解包性能。
要考虑时间、空间开销,以及兼容性。

常见的方式:
json,文本,空间开销大
hessian,二进制,性能✔︎,体积✔︎
protobuf,google的,体积✔︎✔︎,兼容性✔︎

提升网络通信性能

网络编程五个I/O模型:
同步阻塞BIO,同步非阻塞IO,I/O多路复用NIO,信号驱动,异步AIO

RPC主流用I/O多路复用

确定超时时间

依据:根据每个微服务TP99的请求耗时 + 业务场景
区分可重传/不可重传:看有无上下服务依赖

高级

注册中心

通信时client需要知道server地址。
但把server地址配置在client文件中,会出现一些时延、消息丢失等问题。

所以出现了注册中心。client和server都和此中心通信。
→ 新问题:如果server有故障,注册中心难知道
解决:
① 注册中心定时主动探测。但成本高
② server向注册中心发心跳。

注册中心问题:
① 单点 → 变集群
② 主从延迟导致all摘除 → 设置摘除下限
③ 通知风暴 → 扩容,设置阈值,单点变更则单点通知

负载均衡

完全由自身框架实现
策略:随机,hash,轮询

容错

重试、限流、降级、熔断、隔离

RPC vs REST

restf通过http实现。rpc是一种思想。
prc需要知道对方方法,专注业务逻辑,通常用于server之间通信。