百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

答记者问之 - 从 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
  • 错误率高 → OPEN
  • 定时尝试恢复(半开)→ 成功后 CLOSE
  • 六、链路追踪 & 调用监控

    每次 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目标。为...

    大家都在谈论的敏捷开发&amp;Scrum,到底是什么?

    敏捷开发作为一种开发模式,近年来深受研发团队欢迎,与瀑布式开发相比,敏捷开发更轻量,灵活性更高,在当下多变环境下,越来越多团队选择敏捷开发。什么是敏捷?敏捷是一种在不确定和变化的环境中,通过创造和响应...

    敏捷与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...

    取消回复欢迎 发表评论: