RPC原理与实现| 青训营笔记

145 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天 

本文是对于掘金课程的课程笔记,针对课程内容的一些重难点、本人在学习RPC框架知识时候进行的简单记录。

一、本堂课的重点内容

  1. 基本概念
  2. 分层设计
  3. 关键指标
  4. 企业实践

二、详细知识点介绍

基本概念

本地函数调用 VS 远程函数调用

RPC需要解决的问题:

  • 函数映射
  • 数据转换成字节流(本地只需要从栈中取出参数即可)
  • 网络传输

RPC概念模型:由五个部分组成,user;user-stub;rpc-runtime;server-stub;server

一次RPC的完整过程

  • IDL文件:约定描述文件,通过一种中立的方式来描述接口
  • 生成代码,通过编译器工具把IDL文件转换成语言对应的静态库
  • 编解码
  • 通信协议:规范数据在网络中的传输内容和格式
  • 网络传输(TCP/UDP)

RPC的好处

  • 单一职责,有利于分工协作和运维
  • 可扩展性强,资源使用率更优(压力大的时候可以独立扩充资源,比如双十一压力大可以扩充资源)
  • 故障隔离,可靠性高(某一个服务发生故障不会影响整体)

RPC带来的问题

  • 服务宕机,对方如何处理
  • 如何保证消息的可达性
  • 请求量突增导致服务无法及时处理,有哪些措施

分层设计

编解码层

客户端与服务端会依赖同一份IDL文件

数据格式:

  • 语言特定的格式(例如java有java.io.Serializable)
  • 文本格式(json,xml,csv等,有可读性)
  • 二进制编码(用的多,跨语言,高性能,thrift的binaryProtocol)

二进制编码-TLV编码

  • Tag:可以理解为类型
  • Length:长度
  • Value:值

编码选型

  • 兼容性
  • 通用性
  • 性能

协议层

  • 特殊结束符:一个特殊字符作为每个协议单元结束的标识
  • 变长协议

协议构造:

  • LENGTH:数据包大小
  • HEADER MAGIC:标识版本信息
  • SEQUENCE NUMBER:数据包的seqID,可用于多路复用
  • HEADER SIZE:头部长度
  • PROTOCOL ID:编解码方式,有binary和compact两种
  • TRANSFORM ID:压缩方式,有zlib和snappy
  • INFO ID:传递一些定制的meta信息
  • PAYLOAD:消息体

协议解析 MagicNumber -> PayLoadCodec -> Payload

网络通信层

通过Sockets AIP(介于应用层与传输层之间,传输层用TCP或者UDP)

可以使用封装好的网络库

  • 提供易用API:封装底层Sockets API
  • 功能:TCP UDP UDS协议支持等
  • 性能:应用层BUFFER减少拷贝

关键指标

稳定性

保障策略:

  • 熔断:保护调用方(A调用B,B调用C,C响应超时,B也无法响应A)
  • 限流:保护被调用方(防止大流量把服务压垮)
  • 超时控制:避免浪费资源在不可用节点上

提高请求成功率

  • 负载均衡(均匀调用服务的节点)
  • 重试

长尾请求:使用Backup Request

如何实现这些策略?注册中间件!

易用性

  • 开箱即用:合理的默认参数、丰富的文档
  • 周边工具:生成代码工具,脚手架工具

扩展性

  • Middleware
  • Option
  • 编解码层
  • 协议层
  • 网络传输层
  • 代码生成工具插件扩展

观测性

  • Log日志,Metric监控,Tracing链式跟踪
  • 内置观测性服务

高性能

目标:高吞吐,低延迟

场景:

  • 单机多机
  • 单连接多连接
  • 单/多 client
  • 不同大小的请求包
  • 不同请求类型

手段:

  • 连接池(提高复用率)
  • 多路复用(提高复用率)
  • 高性能编解码协议
  • 高性能网络库

企业实践

整体架构

  • Kitex Core
  • Kitex Byted
  • Kitex Tool

自研网络库

为什么要自研网络库? 背景:

  • 原生库无法感知连接状态
  • 原生库存在goroutine暴涨的风险

Netpoll:

  • 解决上述两个背景问题(引入epoll感知链接状态,建立goroutine池)
  • 引入nocopy buffer提升性能

扩展性设计

支持多协议,也支持灵活的自定义协议扩展

性能优化

  • 调度优化:epoll_wati调度控制,gopool重用goroutine降低同时运行的协程数
  • LinkBuffer:读写并行无锁;nocopy buffer优化
  • Pool:引入内存池和对象池,减少GC开销

编解码优化:

  • Codegen:预计算并分配内存,Inline减少函数调用次数,自研 Thrift IDL解析和代码生成器
  • JIT:just in time,即时编译

合并部署

问题:微服务过微,传输和序列化开销越来越大

将亲和性强的服务实例尽可能调度到同一个物理机,远程RPC调用优化为本地IPC调用

三、课后个人总结

RPC框架是非常重要的概念,本节课从本地函数调用引出RPC概念,进而介绍了RPC框架的核心三层——编解码层、协议层和网络传输层,然后介绍了RPC框架的核心指标,最后介绍了字节的高性能RPC框架Kitex,让我对RPC的相关知识有了系统性的掌握,也为我大项目的部署打下了基础。