定义
允许一台计算机上的程序通过网络调用另一台计算机上程序中的子程序(即远程过程),并获取返回值,从而实现分布式计算。
一直困扰我的点
都说rpc可以远程调用不同服务器上的函数,但是我也可以用http协议完成类似的操作。那么为何要有rpc呢?
网上解释的rpc和http的区别

我目前的理解
使用层面
使用rpc框架,可以直接像调用本地函数一样,只需要将目标地址和要调用的函数发送到rpc框架,他就会自动帮助封装协议,基本达到无感调用远程服务。
如果使用http,那么就需要我们自己封装好目标的url、端口等一切相关的协议字段,使用起来非常不方便。
使用场景
优先考虑 RPC 的场景:
- 大型微服务架构内部:当系统被拆分为多个服务,且主要由同一技术栈团队维护时,RFC在性能服务治理和开发效率上的优势非常明显。
- 对性能有极致要求:如高频交易、实时通信等,RFC的二进制协议和长连接能显著降低延迟。
优先考虑 HTTP 的场景:
- 需要对外提供API:比如开放给浏览器、移动端或第三方合作伙伴的接口。RESTful API的通用性和跨平台性是巨大优势。
- 跨多技术栈的异构系统:当系统由多种不同语言编写时,基于HTTP(特别是RESTful风格)的JSON交互是通用的"标准语言"。
- 快速原型或简单系统:项目初期或业务逻辑不复杂时,使用HTTP开发更快速直接。
工作原理

RPC 的目标是让远程调用像本地调用一样简单,其核心机制是代理(也叫存根,Stub)和序列化与网络通信。
存根
- 客户端存根 充当本地调用者的代理,负责将调用信息打包成网络消息。
- 服务端存根 则负责接收网络消息,解包并调用本地真正的服务实现。
工作流程
- 调用:客户端代码发起本地调用。
- 序列化:客户端存根将方法名、参数等信息序列化为可传输的格式。目的是为了增加传输的效率
- 传输:序列化后的数据通过网络发送给服务端。
- 反序列化与执行:服务端存根接收数据,反序列化后调用本地服务方法。
- 结果返回:服务端将执行结果序列化后传回客户端,客户端存根反序列化后返回给调用方。
序列化
考量的关键因素:
- 安全性:这是首要考虑因素。如果序列化协议存在安全漏洞(如某些反序列化漏洞),攻击者可能利用其入侵线上服务。
- 通用性与兼容性:这直接关系到服务调用的稳定性和可用性。
- 你需要关注序列化协议是否支持跨语言(如你的Python、Lua、Go服务能否无缝通信),以及在业务模型变更(如增加字段)时,新老版本协议能否良好兼容。
- 性能与效率:序列化/反序列化的速度会直接影响RPC调用的延迟和吞吐量。
空间开销:序列化后的数据体积越小,网络传输速度越快,带宽消耗也越小,这对RPC性能至关重要。通常二进制协议(如Protobuf)比文本协议(如JSON)体积小得多。
现有方案:

项目使用的
skynet自带的packstring。
网络传输

项目使用
skynet提供的cluster接口,底层是使用tcp协议
路由(重点)

服务发现
- 当前每个服务创建的时候都会自动注册到路由服务,然后rpc都是通过路由服务找到对应的节点信息。
- 每个服务的命名按照规定格式,例如x_1,x_2,这样可以通过哈希或者其他方式迅速找到路由信息?
容错设计
超时:创建rpc对象时,会设置一个定时器,到时间执行超时逻辑,一般都是记录超时日志,或者有些rpc有传回调函数,那么就要返回超时结果给回调函数。
错误重试:当前项目不支持,而是将错误抛到业务层,业务层自己定制自己的错误处理逻辑。
负载均衡
使用哈希计算服务的名称。FNVHash

rpc在分布式环境中面临的挑战
网络不可靠性
分布式环境中网络是不可靠的,可能面临:
- 网络延迟:不同节点间的网络延迟差异大
- 网络丢包:数据包可能在传输过程中丢失
- 网络分区:网络故障导致节点间无法通信
项目中通过设置超时机制(context.lua中定义了默认超时时间)来应对网络问题,但超时时间设置不当可能导致误判。
服务发现与路由复杂性
在分布式环境中,服务实例动态变化,需要:
- 动态服务发现:实时感知服务实例的增减
- 高效路由:快速找到目标服务实例
- 路由一致性:相同请求路由到相同服务实例
项目中通过router_c和router_s服务维护路由信息,使用哈希算法进行路由,但哈希值固定可能导致负载不均衡。
负载均衡挑战
如何将请求均匀分配到多个服务实例:
- 静态负载均衡:基于固定规则分配请求
- 动态负载均衡:根据服务实例负载动态调整
- 一致性哈希:保证相同请求路由到相同实例
容错与故障恢复
分布式环境中节点故障不可避免:
- 节点故障检测:快速发现故障节点
- 故障转移:将请求转移到健康节点
- 错误重试:处理临时故障
项目中通过心跳机制检测节点状态,但RPC框架本身不支持自动重试,需要业务方手动实现。
数据一致性问题
跨节点RPC调用可能导致数据不一致:
- 分布式事务:保证跨节点操作的原子性
- 最终一致性:在一定时间内达到一致状态
- 并发控制:处理并发请求导致的数据冲突
项目中未看到内置的分布式事务支持,需要业务方自行处理数据一致性问题。
性能与可扩展性
高并发下RPC性能面临挑战:
- 序列化开销:数据序列化和反序列化的性能
- 连接管理:大量连接的管理开销
- 可扩展性:随着节点增加,性能是否线性提升
项目使用Skynet框架的cluster模块进行通信,需要关注序列化开销和连接管理的性能。
安全性挑战
分布式环境中RPC调用的安全性:
- 身份认证:验证调用方身份
- 数据加密:防止数据泄露
- 访问控制:限制服务访问权限
调试与监控困难
分布式环境中RPC调用的调试和监控:
- 调用链追踪:跟踪请求的完整路径
- 性能监控:监控RPC调用的延迟和成功率
- 错误诊断:快速定位和诊断RPC错误