Skip to content

Commit

Permalink
polish readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ipipman committed Apr 20, 2024
1 parent 7e4b991 commit 436c091
Showing 1 changed file with 56 additions and 93 deletions.
149 changes: 56 additions & 93 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,133 +1,96 @@
##### 从零开始,手写RPC框架
# 从零开始,手写RPC框架


#### 引言
### 引言
RPC概念与价值:简述远程过程调用(RPC)的基本概念、工作原理及其在构建分布式系统中的重要作用。
手写RPC框架的意义:探讨自研RPC框架对于深入理解分布式通信原理、定制化需求满足、技术栈掌握提升等方面的价值。

##### 总体设计
### 总体设计
架构概览:介绍RPC框架的整体架构,包括客户端、服务端、网络传输层、序列化层、注册中心、负载均衡策略等核心组件及其相互关系。
技术选型:阐述所选用的编程语言、网络库、序列化库、注册中心实现、日志库、测试工具等关键依赖。

##### 核心功能实现
### 核心功能实现
1. 客户端
服务发现:说明如何通过注册中心获取服务列表,以及实现服务订阅与更新机制。
请求发送:阐述构建RPC请求、选择服务提供者、封装网络请求、发送请求的具体步骤。
响应处理:介绍响应接收、反序列化、异常处理与结果返回的过程。
- 服务发现:说明如何通过注册中心获取服务列表,以及实现服务订阅与更新机制。
- 请求发送:阐述构建RPC请求、选择服务提供者、封装网络请求、发送请求的具体步骤。
- 响应处理:介绍响应接收、反序列化、异常处理与结果返回的过程。
2. 服务端
服务注册:讲解服务提供者如何向注册中心注册服务,包括服务信息的定义与发布。
请求接收:描述服务端如何监听并接收客户端请求,包括网络端口绑定、请求解析等环节。
请求处理与响应:详解服务端对请求的业务逻辑处理、结果序列化及响应发送过程。
- 服务注册:讲解服务提供者如何向注册中心注册服务,包括服务信息的定义与发布。
- 请求接收:描述服务端如何监听并接收客户端请求,包括网络端口绑定、请求解析等环节。
- 请求处理与响应:详解服务端对请求的业务逻辑处理、结果序列化及响应发送过程。
3. 网络传输层
协议设计:定义RPC通信协议,包括消息头、消息体结构、错误码等规范。
网络通信:采用何种网络库实现HTTP/TCP/UDP通信,如何处理连接管理、心跳检测、超时重试等问题。
- 协议设计:定义RPC通信协议,包括消息头、消息体结构、错误码等规范。
- 网络通信:采用何种网络库实现HTTP/TCP/UDP通信,如何处理连接管理、心跳检测、超时重试等问题。
4. 序列化层
序列化方案:选择合适的序列化库(如JSON、Protobuf、Thrift等),描述其优点及在框架中的应用。
编解码实现:详细说明请求与响应数据的编码、解码逻辑。
- 序列化方案:选择合适的序列化库(如JSON、Protobuf、Thrift等),描述其优点及在框架中的应用。
- 编解码实现:详细说明请求与响应数据的编码、解码逻辑。
5. 注册中心
注册中心选型:介绍采用的注册中心类型(如Zookeeper、Etcd、Consul等)及其特性。
服务注册与发现机制:详细描述服务提供者注册服务、消费者发现服务的具体实现。
6. 负载均衡
负载均衡策略:列举支持的负载均衡算法(如轮询、随机、权重、一致性哈希等),并解释其实现原理。
策略选择与实现:描述如何在框架中集成并切换不同的负载均衡策略。
7.
##### 高级特性与优化
服务治理:介绍熔断、降级、限流、隔离等服务治理功能的设计与实现。
容错与高可用:探讨如何实现服务端的故障检测、自动恢复、主备切换,以及客户端的重试、失败快速反馈等高可用机制。
性能优化:分享在网络传输、序列化效率、并发处理等方面的优化实践与技巧。
- 注册中心选型:介绍采用的注册中心类型(如Zookeeper、Etcd、Consul等)及其特性。
- 服务注册与发现机制:详细描述服务提供者注册服务、消费者发现服务的具体实现。
6. 负载均衡
- 负载均衡策略:列举支持的负载均衡算法(如轮询、随机、权重、一致性哈希等),并解释其实现原理。
- 策略选择与实现:描述如何在框架中集成并切换不同的负载均衡策略。

##### 测试与部署
单元测试与集成测试:描述如何编写覆盖各模块功能的测试用例,以及进行端到端的集成测试。
部署与运维:提供框架的部署指南,包括环境准备、配置说明、服务启动与停止等操作步骤,以及日志监控、故障排查等运维建议。
### 高级特性与优化
1. 服务治理:介绍熔断、降级、限流、隔离等服务治理功能的设计与实现。
2. 容错与高可用:探讨如何实现服务端的故障检测、自动恢复、主备切换,以及客户端的重试、失败快速反馈等高可用机制。
3. 性能优化:分享在网络传输、序列化效率、并发处理等方面的优化实践与技巧。

### 测试与部署
1. 单元测试与集成测试:描述如何编写覆盖各模块功能的测试用例,以及进行端到端的集成测试。
2. 部署与运维:提供框架的部署指南,包括环境准备、配置说明、服务启动与停止等操作步骤,以及日志监控、故障排查等运维建议。


#### Provider Server IO框架的选择与性能的评估

##### 1.Provider Server 性能分布火焰图
### Provider Server IO框架的选择与性能的评估

我的框架本身没有任何业务处理逻辑,由此通过火焰图分析框架性能损耗分布,能更好的帮助我优化Latency.
### 1.Provider Server 性能分布火焰图

关键信息:
1. 框架无业务处理逻辑,火焰图用于分析框架性能损耗分布,以优化Latency。
2. 火焰图显示大部分损耗集中在IO操作上。
3. 结论:高性能RPC框架需选择高性能IO通信框架。

从火焰图表现上看,大部分损耗都在IO上,那么就可以得出一个结论 “一个高性能的RPC框架,必须选择一个高性能的IO通信框架”

<img src="https://ipman-blog-1304583208.cos.ap-nanjing.myqcloud.com/rpcman/2024-03-24-153134.png" alt="image-20240324222246295" style="width:600px;" />



##### 2 用SpringBoot做Provider Server的性能

wrk压测工具

> wrk http://localhost:8088/?id=101
```java
Running 10s test @ http://localhost:8088/?id=101
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 10.83ms 27.35ms 284.50ms 94.92%
Req/Sec 0.98k 428.99 2.09k 69.90%
19210 requests in 10.02s, 3.10MB read
Requests/sec: 1916.85
Transfer/sec: 316.70KB
```

压测结果: 1900/qps



Arthas分析工具:

>monitor -c 5 consumer.cn.ipman.rpc.core.RpcInvocationHandler invoke "#cost>10"
<img src="https://ipman-blog-1304583208.cos.ap-nanjing.myqcloud.com/rpcman/2024-03-24-140239.png" alt="image-20240324220234729" />

`压测性能: 24ms/RT`
### 2 使用SpringBoot作为Provider Server的性能

压测工具: wrk <br>
命令: wrk http://localhost:8088/?id=101 <br>

压测结果:<br>
请求速率(Req/Sec): 1916.85 <br>
吞吐量(Transfer/sec): 316.70KB <br>

##### 3. 用Netty做Provider Server的性能

wrk压测工具

> wrk http://localhost:8088/?id=101
```java
Running 10s test @ http://localhost:8088/?id=101
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 8.78ms 32.87ms 334.38ms 96.57%
Req/Sec 1.82k 599.35 2.78k 70.10%
35218 requests in 10.02s, 5.68MB read
Requests/sec: 3516.08
Transfer/sec: 580.95KB
```



Arthas分析工具:

> monitor -c 5 consumer.cn.ipman.rpc.core.RpcInvocationHandler invoke "#cost>10"
Arthas分析:<br>
监控命令: monitor -c 5 consumer.cn.ipman.rpc.core.RpcInvocationHandler invoke "#cost>10" <br>
平均响应时间(RT): 24ms <br>

<img src="https://ipman-blog-1304583208.cos.ap-nanjing.myqcloud.com/rpcman/2024-03-24-140101.png" alt="image-20240324220054409" />

`压测性能: 28ms/RT`



##### 4 总结 Provider Server IO 框架选型

从压测数据来看,用Netty Server的吞吐量,要比 Spring Boot (内嵌Tomcat) 的性能表现好不少. 准确的说, 这次对比是拿了Tomcat 和 Netty 做了一次对比.

其实呢, 两者都是支持NIO的框架, 不管我们去深究Tomcat (Container、Connector) 的架构 ,还是探索Nettty的 (B/C、EventLoop)的特性,两者对于一个RPC框架来说,意义都没有那么大,除非是性能相差天大地别,已经到了不能忍受的地步.

那么我们应该换个角度看问题, 从RPC框架的角度, 看下他们两者的集成性、扩展性:
### 3 总结 Provider Server IO 框架选型

- 关于扩展,不用质疑Netty要比Tomcat支持的协议多的多, 因为两者的使命不同, Tomcat主要是作为一个web http容器, 它的战场大部分还是在web开发项目上. 如果我们RPC框架要考虑以下两个问题时, 那么Netty会是首选;
- 如果我们传输协议不是HTTP, 而是TCP时?
- 如果我们传输体不是Body, 而是需要自定义编解码时?
- 关于集成, RPC框架的受众是在业务开发同学, 基本上大家业务同学都用的Spring系列的框架. 往往这些框架本身就已经内嵌了Tomcat容器, 那么我们再选择 Spring Boot (内嵌Tomcat) 作为RPC的IO框架, 就会很容易造成Spring的版本冲突、IOC冲突、Servlet冲突等等问题. 所以在RPC框架里, 选择像Netty这种相对独立的IO框架, 也更能被RPC使用者接受.
在深入探讨RPC框架的IO组件选型时,首先从压测数据出发,我们发现Netty Server展现出显著的性能优势,其吞吐量远超采用Spring Boot(内嵌Tomcat)的方案。本次对比的核心即为Tomcat与Netty这两款同样支持NIO的通信框架之间的较量。尽管对两者内部架构(如Tomcat的Container、Connector机制与Netty的Bootstrap/Channel、EventLoop设计)进行详尽剖析对于理解其工作原理具有重要意义,但在实际应用于RPC框架的场景中,若性能差距未达到显著影响系统可接受程度的程度,这些底层特性的差异并不构成决定性因素。
然而,当我们从RPC框架设计与应用的角度重新审视,Tomcat与Netty在集成性和扩展性方面的差异则显得尤为重要。以下几点值得着重考量:<br>

**扩展性** <br>
Netty的优势在于其对多种协议的广泛支持。相较于专注于Web服务的Tomcat,Netty的设计初衷旨在构建高效、灵活的网络通信解决方案,使其能够轻松应对各种非HTTP协议的需求,如TCP、UDP、WebSocket等。这对于RPC框架而言尤为关键,因为RPC调用往往涉及定制化通信协议及编解码过程:<br>
1. 非HTTP协议支持:当RPC框架采用非HTTP作为传输协议时,Netty凭借其丰富的协议库与高度可配置性,能够无缝对接,无需额外开发工作,确保通信效率与稳定性。
2. 自定义编解码需求:在RPC场景中,传输的数据结构可能与HTTP Body的标准形式大相径庭,需要特定的序列化与反序列化逻辑。Netty提供了强大的编解码器体系,使得用户能够便捷地实现自定义编解码逻辑,以适应复杂的RPC数据交互需求。

**集成性** <br>
考虑到RPC框架的用户群体主要为业务开发人员,他们普遍采用Spring系列框架进行开发,而这些框架通常已内嵌了Tomcat容器。在这种背景下,选择Spring Boot(内嵌Tomcat)作为RPC框架的IO组件可能会引发一系列问题:<br>
1. 版本冲突:若RPC框架强行引入特定版本的Tomcat,可能导致与项目中已存在的Spring版本不兼容,增加维护复杂度。
2. IOC冲突:Spring Boot对Bean的管理方式与RPC框架可能存在冲突,导致依赖注入(Dependency Injection, DI)混乱,影响应用的正常运行。
3. Servlet冲突:在RPC框架中直接使用Tomcat可能导致Servlet容器层面的冲突,例如路由规则、过滤器配置等,给应用部署与调试带来困扰。
鉴于上述集成性挑战,选用如Netty这样相对独立、轻量级的IO框架,更有利于降低与现有业务环境的摩擦,提升RPC框架对用户友好性与易用性。开发者可以更为顺畅地将RPC框架融入既有项目,减少不必要的适配工作与潜在风险,从而专注于核心业务逻辑的实现与优化。<br>
综上所述,在设计RPC框架时,虽然Tomcat与Netty在底层NIO支持上存在共性,但Netty凭借其卓越的扩展性(尤其在支持非HTTP协议与自定义编解码方面)以及良好的集成性(避免与Spring生态产生冲突),成为构建高性能、易用RPC框架的理想IO组件选择。<br>

#### 模拟全流程的单元测试代码覆盖率

Expand Down

0 comments on commit 436c091

Please sign in to comment.