这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记
1. 基本概念
1.1 本地函数调用
- 对于参数和返回值放在栈/寄存器中,执行程序时在栈中读取相应的数据
- 在编译器优化后有可能不需要额外的存储而是将调用的函数进行inline操作
1.2 远程函数调用(RPC | Remote Procedure Calls)
- 在本地调用中,函数体是通过函数指针来指定的,我们调用哪个方法,编译器就找到相应的函数指针进行调用,这里将函数对应一个ID,通过ID找到相应的函数进行调用
- 传递参数:将参数序列化为一个字节流,传给服务端后,将字节流转化成自己能读取的格式,执行完相应逻辑后再通过相同的方式传回给客户端
- 所以RPC需要解决的问题主要是函数映射和数据传输
1.3 RPC如何解决函数映射和数据传输
- IDL(Interface Description Language)文件:IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
- 生成代码:通过编译器工具把IDL文件转换成语言对应的静态库,这里更像是一种约定。同一份IDL生成的文件支持的跨语言,通用性更强
- 编解码:将传输的数据序列化与反序列化
- 通信协议:规范了数据在网络中的传输内容和格式,除了必须的请求/响应数据外,通常还会包含额外的元数据
- 网络传输:通常基于成熟的网络库走TCP/UDP传输
- 调用流程:将参数及调用函数等序列化后通过特定协议使用TCP/UDP传输到服务端,服务端根据协议接收到相应数据进行反序列化后调用相应的函数并以相同的方式传回给客户端
1.3 RPC好处
- 单一职责, 有利于分协作和运维开发,还可采用不同的语言对服务逻辑进行实现,部署及运维都是独立的
- 可扩展性强, 资源使用率更优,压力大时可独立扩充资源
- 故障隔离, 服务的整体可靠性更高,某个服务挂掉不会影响整个系统的运行
1.4 RPC的问题
- 服务宕机,对方该如何处理
- 在调用过程中发生网络异常,如何保证消息的可达性
- 请求量突增导致服务无法及时处理,有哪些处理措施
2. 关键指标
2.1 稳定性-保障策略
- 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制:避免浪费资源在不可用节点上
2.2 稳定性-请求成功率
- 负载均衡:将流量尽可能分配在不同的服务结点上
- 重试:请求失败进行重试,需要限制重试次数,否则可能加大被调用服务的负载导致服务挂掉
2.3 稳定性-长尾请求
- 长尾请求指的是明显高于均值的那部分占比较小的请求,通常使用P99标准对均值进行定义
- 如果请求发出后超过定义的阈值没有返回响应结果,则发起一个重试请求,这样相当于同时有两个请求同时运行,然后等待第一个返回成功的结果就立即结束这次请求,这样来加速整个请求过程
2.4 稳定性-注册中间件
- 要实现以上的稳定性相关,可通过中间件的形式在代码中保证程序的稳定性
- 同时对服务进行检测,涉及到log、tracing、metric,在外部可对服务的状态进行监控,同时还可暴露服务的内部状态辅助监控
不得不说字节的基础架构还是非常厉害