答记者问之 - 从 0 到 1 手撕一个高可用 RPC 框架:架构、实现与实战
ccwgpt 2025-07-14 12:53 2 浏览 0 评论
大多数程序员都用过 Dubbo、gRPC、Spring Cloud 等成熟框架。但你是否想过:RPC 的本质到底是什么?
本文带你从零手撕一个具备通信、注册、负载均衡、限流熔断、监控告警、CI/CD 等完整能力的 RPC 框架,真正搞懂它的原理、设计思路和可落地的工程实现。
什么是 RPC?
orderService.createOrder(order);
你以为调用的是本地方法,其实请求已经通过网络,发到了远程机器上。
我们要实现一个什么样的 RPC 框架?
目标:打造一个高可用、模块化、具备生产级能力的轻量 RPC 框架:
特性包括:
基于 Netty 的通信能力
支持自定义协议编解码
支持服务注册与发现
支持多种负载均衡策略
实现限流熔断机制
实现调用链追踪(TraceId)
集成 Prometheus 监控 & 告警
支持 GitHub Actions + Docker + K8s 的 CI/CD
最终,你将收获一套真实可用、具备核心治理能力的 RPC 框架,并搞懂它的每一层实现原理。
一、框架架构总览
┌────────────┐ ┌────────────┐
│ Consumer │─────│ Provider │
└────────────┘ └────────────┘
│ │
▼ ▼
┌────────────────────────────────────┐
│ 通信层(Netty) │
│ 编解码层(自定义协议) │
│ 注册中心(ZK/Nacos) │
│ 路由负载均衡(轮询/Hash) │
│ 服务治理(限流、熔断、重试) │
│ 监控链路追踪(TraceId + Prom) │
└────────────────────────────────────┘
二、从底层开始:通信协议 & 编解码
我们设计一套简单的协议:
魔数 + 版本 + 消息类型 + 请求ID + 数据长度 + 请求体
使用 Netty 实现通信:
// 编解码器
class MessageEncoder extends MessageToByteEncoder<RpcRequest> { ... }
class MessageDecoder extends ByteToMessageDecoder { ... }
// Netty 服务端/客户端
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.childHandler(new ChannelInitializer<>() { ... });
支持心跳包、超时机制、自定义序列化(JSON / Protobuf)。
三、注册中心:服务注册 & 发现
我们用 Zookeeper 实现一个简单的服务注册中心:
/rpc-services/OrderService/providers/ip:port
- Provider 启动时向 ZK 注册临时节点
- Consumer 启动时订阅节点变化,动态维护 Provider 列表
可封装:
interface RegistryService {
void register(String serviceName, String ip, int port);
List<Endpoint> discover(String serviceName);
}
四、负载均衡策略
支持策略:
- 轮询(RoundRobin)
- 随机(Random)
- 一致性哈希(ConsistentHash)
- 最少连接数(LeastActive)
public interface LoadBalancer {
Endpoint select(List<Endpoint> endpoints);
}
五、服务治理:限流 + 熔断 + 重试
限流(令牌桶算法)
class TokenBucketLimiter {
int capacity = 100;
AtomicInteger tokens = new AtomicInteger(capacity);
...
}
熔断器状态图
CLOSED ——→ OPEN ——→ HALF-OPEN ——→ CLOSED
六、链路追踪 & 调用监控
每次 RPC 请求打上唯一 TraceId:
ThreadLocalContext.set("traceId", UUID.randomUUID().toString());
日志中统一打印:
[traceId=abc123] 调用 OrderService 耗时 48ms 成功
监控系统使用 Micrometer + Prometheus:
- QPS
- RT(响应时间)
- 错误率
- 在线 Provider 数量
结合 Grafana 做可视化展示。
七、CI/CD:从构建到部署
构建方式
- 使用 GitHub Actions 编译 + 打包 + Docker 镜像
- Docker 镜像推送到 Registry(如 Aliyun、Harbor)
- 使用 Helm 部署到 Kubernetes 集群
示例流程:
- name: Build
run: mvn clean package
- name: Docker Build
run: docker build -t my-rpc-service .
- name: Push to Registry
run: docker push my-rpc-service
- name: Deploy to K8s
run: helm upgrade --install ...
八、告警系统接入
- Prometheus + AlertManager 设置告警规则
- 支持钉钉 / 飞书 / 邮件 Webhook
- 典型告警场景:
- Provider 数量变为 0
- 错误率超过 10%
- 响应延迟高于 500ms
九、一套完整使用示例(业务开发者视角)
服务提供者:
@RpcService
public class OrderServiceImpl implements OrderService {
public void createOrder(Order order) {
...
}
}
服务消费者:
@RpcReference
private OrderService orderService;
orderService.createOrder(order); // 框架自动路由 + 远程调用
十、总结
模块 | 状态 | 技术 |
通信层 | 完成 | Netty |
编解码 | 完成 | Protobuf |
注册发现 | 完成 | Zookeeper |
负载均衡 | 多策略 | Hash、轮询 |
熔断限流 | 支持 | 自研限流器、熔断器 |
调用链追踪 | 完成 | TraceId |
监控告警 | 接入 | Prometheus + Grafana |
CI/CD 自动部署 | 集成 | GitHub Actions + Docker |
最后
写这个 RPC 框架不是为了“造轮子”,而是:
了解分布式通信的本质
训练系统设计能力
拥有架构思维
打开深入中间件开发的大门
相关推荐
- RACI矩阵:项目管理中的角色与责任分配利器
-
作者:赵小燕RACI矩阵RACI矩阵是项目管理中的一种重要工具,旨在明确团队在各个任务中的角色和职责。通过将每个角色划分为负责人、最终责任人、咨询人和知情人四种类型,RACI矩阵确保每个人都清楚自己...
- 在弱矩阵组织中,如何做好项目管理工作?「慕哲制图」
-
慕哲出品必属精品系列在弱矩阵组织中,如何做好项目管理工作?【慕哲制图】-------------------------------慕哲制图系列0:一图掌握项目、项目集、项目组合、P2、商业分析和NP...
- Scrum模式:每日站会(Daily Scrum)
-
定义每日站会(DailyScrum)是一个Scrum团队在进行Sprint期间的日常会议。这个会议的主要目的是为了应对Sprint计划中的不断变化,确保团队能够有效应对挑战并达成Sprint目标。为...
- 大家都在谈论的敏捷开发&Scrum,到底是什么?
-
敏捷开发作为一种开发模式,近年来深受研发团队欢迎,与瀑布式开发相比,敏捷开发更轻量,灵活性更高,在当下多变环境下,越来越多团队选择敏捷开发。什么是敏捷?敏捷是一种在不确定和变化的环境中,通过创造和响应...
- 敏捷与Scrum是什么?(scrum敏捷开发是什么)
-
敏捷是一种思维模式和哲学,它描述了敏捷宣言中的一系列原则。另一方面,Scrum是一个框架,规定了实现这种思维方式的角色,事件,工件和规则/指南。换句话说,敏捷是思维方式,Scrum是规定实施敏捷哲学的...
- 敏捷项目管理与敏捷:Scrum流程图一览
-
敏捷开发中的Scrum流程通常可以用一个简单的流程图来表示,以便更清晰地展示Scrum框架的各个阶段和活动。以下是一个常见的Scrum流程图示例:这个流程图涵盖了Scrum框架的主要阶段和活动,其中包...
- Mockito 的最佳实践(mock方法)
-
记得以前面试的时候,面试官问我,平常开发过程中自己会不会测试?我回答当然会呀,自己写的代码怎么不测呢。现在想想我好像误会他的意思了,他应该是想问我关于单元测试,集成测试以及背后相关的知识,然而当时说到...
- EffectiveJava-5-枚举和注解(java枚举的作用与好处)
-
用enum代替int常量1.int枚举:引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员,这种方法叫做int枚举模式。int枚举模式是类型不安全的,例如下面两组常量:性别和动物种...
- Maven 干货 全篇共:28232 字。预计阅读时间:110 分钟。建议收藏!
-
Maven简介Maven这个词可以翻译为“知识的积累”,也可以翻译为“专家”或“内行”。Maven是一个跨平台的项目管理工具。主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。仔...
- Java单元测试框架PowerMock学习(java单元测试是什么意思)
-
前言高德的技术大佬在谈论方法论时说到:“复杂的问题要简单化,简单的问题要深入化。”这句话让我感触颇深,这何尝不是一套编写代码的方法——把一个复杂逻辑拆分为许多简单逻辑,然后把每一个简单逻辑进行深入实现...
- Spring框架基础知识-第六节内容(Spring高级话题)
-
Spring高级话题SpringAware基本概念Spring的依赖注入的最大亮点是你所有的Bean对Spring容器的存在是没有意识的。但是在实际的项目中,你的Bean必须要意识到Spring容器...
- Java单元测试浅析(JUnit+Mockito)
-
作者:京东物流秦彪1.什么是单元测试(1)单元测试环节:测试过程按照阶段划分分为:单元测试、集成测试、系统测试、验收测试等。相关含义如下:1)单元测试:针对计算机程序模块进行输出正确性检验工作...
- 揭秘Java代码背后的质检双侠:JUnit与Mockito!
-
你有没有发现,现在我们用的手机App、逛的网站,甚至各种智能设备,功能越来越复杂,但用起来却越来越顺畅,很少遇到那种崩溃、卡顿的闹心事儿?这背后可不是程序员一拍脑袋写完代码就完事儿了!他们需要一套严谨...
- 单元测试框架哪家强?Junit来帮忙!
-
大家好,在前面的文章中,给大家介绍了以注解和XML的方式分别实现IOC和依赖注入。并且我们定义了一个测试类,通过测试类来获取到了容器中的Bean,具体的测试类定义如下:@Testpublicvoid...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- mfc框架 (52)
- abb框架断路器 (48)
- ui自动化框架 (47)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- ppt框架 (48)
- 内联框架 (52)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)