面试官顺着一个 RPC 项目继续问,问题很快就会落到具体实现上:

TCP 只有字节流,粘包、半包怎么处理?

同一条长连接发出多个请求,响应回来后怎么找到对应的调用方?

服务实例上下线以后,客户端怎样及时拿到新地址?

请求超时后,CompletableFuture 和在途请求 Map 怎么清理,复用的 Channel 要不要关闭?

CompletableFuture

新增一种序列化方式,为什么不应该继续往 switch 里加分支?

switch

只记住“RPC 让远程调用像本地调用一样简单”,遇到这些追问很难往下讲。《手写 RPC 框架》围绕一个可以运行的 Java 项目,把动态代理、网络通信、自定义协议、序列化、注册中心、负载均衡、异步调用和异常处理串在一起。

如果你还不熟悉 RPC 的概念和调用流程,可以先阅读 JavaGuide 的免费文章:RPC 远程过程调用详解。

RPC 远程过程调用详解

项目介绍

项目介绍

guide-rpc-framework 是一个面向学习和工程实践的轻量级 RPC 框架。项目保留了早期 Socket 版本,也提供了基于 Netty 的实现,方便对照 BIO 与 NIO 在连接、线程和请求处理方式上的差异。

guide-rpc-framework

项目地址(欢迎 Star):

GitHub:https://github.com/Snailclimb/guide-rpc-framework

https://github.com/Snailclimb/guide-rpc-framework

Gitee:https://gitee.com/SnailClimb/guide-rpc-framework

https://gitee.com/SnailClimb/guide-rpc-framework

项目代码完全开源。配套教程是 JavaGuide 知识星球内部小册,当前包含 15 篇正文,以及一篇简历写法和面试常见问题解答。

一次 RPC 调用经过了什么

一次 RPC 调用经过了什么

Guide RPC Framework 整体架构

以 @RpcReference 注入的服务接口为例,一次调用会经过这些环节:

@RpcReference
本地接口调用
    ↓
JDK 动态代理组装 RpcRequest
    ↓
ZooKeeper 服务发现
    ↓
一致性哈希选择服务实例
    ↓
建立或复用 Netty Channel
    ↓
协议编码、序列化与压缩
    ↓
服务端拆帧、解码并执行目标方法
    ↓
响应按 requestId 完成对应 CompletableFuture
本地接口调用
    ↓
JDK 动态代理组装 RpcRequest
    ↓
ZooKeeper 服务发现
    ↓
一致性哈希选择服务实例
    ↓
建立或复用 Netty Channel
    ↓
协议编码、序列化与压缩
    ↓
服务端拆帧、解码并执行目标方法
    ↓
响应按 requestId 完成对应 CompletableFuture

教程不会停在“客户端发送请求、服务端返回结果”这一层。协议字段怎样排列、服务端为什么不能在 I/O 线程里执行耗时方法、请求从排队到收到响应如何共用一个超时预算,这些问题都会结合当前代码说明。

当前项目实现了哪些能力

当前项目实现了哪些能力

模块当前实现网络通信Socket 与 Netty 两种传输实现,Netty 支持 Channel 复用和心跳检测通信协议16 字节固定头部,包含魔数、版本、完整长度、消息类型、编解码编号和请求编号消息边界基于长度字段拆帧,并限制帧及解压后消息体最大为 8 MiB序列化与压缩支持 Hessian、Kryo、Protostuff 和 Gzip,默认序列化方式为 Hessian服务注册发现使用 ZooKeeper 临时节点和 CuratorCache,支持本地地址缓存与会话恢复负载均衡默认使用一致性哈希,每个物理节点对应 160 个虚拟节点请求响应关联使用 requestId -> CompletableFuture 管理并发请求,处理超时、取消、断连和关闭清理调用方式提供同步代理和返回 CompletableFuture 的异步镜像接口扩展机制自定义命名 SPI,覆盖序列化、压缩、负载均衡、注册中心、服务发现和传输层Spring 集成使用 @RpcScan、@RpcService、@RpcReference 完成扫描、服务发布与代理注入错误处理使用 0~16 的稳定状态码区分参数错误、超时、资源耗尽、服务不可用和内部错误自动化测试共 82 项测试,覆盖配置、SPI、编解码、代理、传输、服务处理和 ZooKeeper 会话恢复

模块当前实现

模块

当前实现

网络通信Socket 与 Netty 两种传输实现,Netty 支持 Channel 复用和心跳检测

网络通信

Socket 与 Netty 两种传输实现,Netty 支持 Channel 复用和心跳检测

通信协议16 字节固定头部,包含魔数、版本、完整长度、消息类型、编解码编号和请求编号

通信协议

16 字节固定头部,包含魔数、版本、完整长度、消息类型、编解码编号和请求编号

消息边界基于长度字段拆帧,并限制帧及解压后消息体最大为 8 MiB

消息边界

基于长度字段拆帧,并限制帧及解压后消息体最大为 8 MiB

序列化与压缩支持 Hessian、Kryo、Protostuff 和 Gzip,默认序列化方式为 Hessian

序列化与压缩

支持 Hessian、Kryo、Protostuff 和 Gzip,默认序列化方式为 Hessian

服务注册发现使用 ZooKeeper 临时节点和 CuratorCache,支持本地地址缓存与会话恢复

服务注册发现

使用 ZooKeeper 临时节点和 CuratorCache,支持本地地址缓存与会话恢复

负载均衡默认使用一致性哈希,每个物理节点对应 160 个虚拟节点

负载均衡

默认使用一致性哈希,每个物理节点对应 160 个虚拟节点

请求响应关联使用 requestId -> CompletableFuture 管理并发请求,处理超时、取消、断连和关闭清理

请求响应关联

使用 requestId -> CompletableFuture 管理并发请求,处理超时、取消、断连和关闭清理

requestId -> CompletableFuture

调用方式提供同步代理和返回 CompletableFuture 的异步镜像接口

调用方式

提供同步代理和返回 CompletableFuture 的异步镜像接口

CompletableFuture

扩展机制自定义命名 SPI,覆盖序列化、压缩、负载均衡、注册中心、服务发现和传输层

扩展机制

自定义命名 SPI,覆盖序列化、压缩、负载均衡、注册中心、服务发现和传输层

Spring 集成使用 @RpcScan、@RpcService、@RpcReference 完成扫描、服务发布与代理注入

Spring 集成

使用 @RpcScan、@RpcService、@RpcReference 完成扫描、服务发布与代理注入

@RpcScan
@RpcService
@RpcReference

错误处理使用 0~16 的稳定状态码区分参数错误、超时、资源耗尽、服务不可用和内部错误

错误处理

使用 0~16 的稳定状态码区分参数错误、超时、资源耗尽、服务不可用和内部错误

自动化测试共 82 项测试,覆盖配置、SPI、编解码、代理、传输、服务处理和 ZooKeeper 会话恢复

自动化测试

共 82 项测试,覆盖配置、SPI、编解码、代理、传输、服务处理和 ZooKeeper 会话恢复

这仍然是一个教学和工程实践项目。自动重试、熔断、限流、TLS、调用方鉴权、远程取消、监控中心以及服务端有界任务队列尚未实现。教程会直接标出这些限制,避免把成熟 RPC 框架的能力套到当前代码上。

这套教程怎么讲

这套教程怎么讲

教程先用 Socket 和 JDK 动态代理搭出最小调用链,再逐步换成 Netty、自定义协议、可插拔序列化和 ZooKeeper。读者可以看到每次改造解决了哪个问题,而非直接面对一套已经组装好的代码。

源码分析部分按真实调用顺序展开。客户端怎样生成请求、服务发现怎样选择地址、编解码器怎样处理消息、服务端怎样执行方法、响应怎样完成 Future,都能在文章和代码之间对应起来。

后面的 SPI、负载均衡和测试章节继续处理扩展与失败场景。除了正常调用,也会讨论重复 requestId、响应晚到、请求超时、连接提前关闭、非法协议帧和 ZooKeeper 会话失效。

requestId

运行项目所需的环境、启动顺序和第一次 RPC 调用继续放在项目 README 的“快速开始”中维护,不再单独拆一篇重复文章。

配套教程内容安排

配套教程内容安排

RPC 基础与框架设计

RPC 基础与框架设计

01 什么是 RPC?原理是什么?:从本地调用与远程调用的差异出发,说明 RPC 的组成和一次调用的基本过程。

02 常见 RPC 框架介绍:对比 Dubbo、gRPC、Thrift、Motan 等常见方案,理解框架选型关注的因素。

03 如何自己实现一个 RPC 框架?:确定代理、传输、序列化、注册中心和负载均衡等模块的职责。

04 序列化介绍以及序列化协议选择:比较 JDK 序列化、Hessian、Kryo、Protostuff 等方案,并说明当前项目的接入方式。

网络通信、动态代理与 ZooKeeper

网络通信、动态代理与 ZooKeeper

05 Socket 网络通信实战:用最少的组件跑通远程请求,理解阻塞 I/O 版本的线程和连接模型。

06 Netty 网络通信实战:学习 EventLoop、Channel、Pipeline、Handler 以及长度字段拆帧。

07 静态代理、JDK 与 CGLIB 动态代理实战:理解代理对象怎样屏蔽请求组装和网络传输细节。

08 ZooKeeper 常用命令与 Curator 使用详解:掌握节点模型、临时节点、监听机制和 Curator 的基本用法。

RPC 框架源码分析

RPC 框架源码分析

09 网络传输模块:沿着客户端发送、协议编解码、Channel 复用、心跳和服务端处理器阅读代码。

10 注册中心模块:分析服务标识、服务发布、地址缓存、节点监听和会话恢复。

11 其他模块:继续说明代理、服务提供、本地服务容器、Spring 注解集成和异常处理。

异步调用、扩展机制与可靠性

异步调用、扩展机制与可靠性

12 使用 CompletableFuture 优化接收服务端返回结果:实现并发请求与响应关联,并说明超时、取消和资源清理。

13 RPC 框架的 SPI 扩展机制是如何实现的?:从硬编码工厂切换到命名 SPI,分析扩展发现、校验和三级缓存。

14 随机负载均衡与一致性哈希实战:理解两种算法的适用场景,重点分析项目当前使用的一致性哈希实现。

15 如何测试一个 RPC 框架?:使用 JUnit、Netty EmbeddedChannel 和 Curator TestingServer 验证并发、超时、断连、非法帧与会话恢复。

简历写法与面试准备

简历写法与面试准备

项目能运行只是第一步。写进简历以后,默认序列化方式、协议头长度、线程模型、超时范围和当前缺少的治理能力都可能被追问。

配套的《简历写法和面试常见问题解答》包含:

9 条后端项目经历推荐写法,以及适合一页简历的 6 条精简版。

当前可以直接核对的指标,例如 16 字节协议头、8 MiB 报文上限、160 个虚拟节点和 82 项测试。

一分钟项目介绍和 18 个常见追问。

容易写错的项目能力说明,例如默认 Hessian、随机负载均衡尚未接入当前 SPI 配置、没有 Spring Boot Starter,也没有完整的重试和熔断机制。

这部分不会教你凭空包装数据。没有压测报告,就不写“十万 QPS”;没有实现 Spring Boot Starter,也不会把 Spring 注解集成换个名字放进简历。

学完后应该能回答哪些问题

学完后应该能回答哪些问题

RPC 与 HTTP 调用有什么区别,为什么这个项目选择自定义二进制协议?

16 字节协议头分别保存什么,长度字段怎样解决粘包、半包?

为什么要同时限制压缩前帧大小和解压后的消息体大小?

多个并发请求复用一条 Channel 时,响应怎样找到对应的 CompletableFuture?

CompletableFuture

请求超时从哪个时间点开始计算,为什么要覆盖排队和服务发现?

自定义 SPI 与 JDK ServiceLoader、Dubbo SPI 分别有什么差异?

ServiceLoader

ZooKeeper 临时节点、CuratorCache 和会话恢复各自解决什么问题?

一致性哈希为什么需要虚拟节点,服务实例变化时哪些请求会重新映射?

服务端为什么要把业务执行移出 Netty I/O 线程,同一 Channel 上的方法能否并行?

这个框架距离生产可用还缺哪些能力,应该先补哪一项?

如果这些问题只能背结论,建议回到对应章节对照代码再走一遍。

适合谁学习

适合谁学习

已经学过 Java 基础、集合、反射和多线程,想把这些知识放进一个完整项目中使用。

接触过 Netty 或 ZooKeeper,但对它们在 RPC 调用链里的职责还比较模糊。

正在准备 Java 后端校招、社招,希望增加一个能深入讲协议、网络和分布式协作的项目。

平时会使用 Dubbo、Feign 等远程调用工具,想继续理解代理、协议、注册发现和响应关联是怎样实现的。

准备阅读 Dubbo、Netty 等框架源码,希望先用一个体量较小的项目建立整体认识。

第一次接触 RPC 没关系,但最好已经掌握 Java 基础语法、Maven 和基本的客户端/服务端概念。教程不会花大量篇幅重复这些前置知识。

建议学习顺序

建议学习顺序

按项目 README 准备 JDK 25、Maven 3.9 和 ZooKeeper 3.9.5,先跑通服务端与客户端。

阅读前 8 篇教程,自己完成 Socket、代理、Netty 和 ZooKeeper 的最小实现。

对照第 9~14 篇阅读当前源码,至少亲手改造一个扩展点,例如新增序列化器或负载均衡策略。

执行 mvn verify,再补一个超时、断连或非法帧测试,确认自己能解释失败后的资源清理。

mvn verify

最后整理简历并准备追问。没有亲手验证过的能力,不写进项目经历。

常见问题

常见问题

项目代码需要付费吗?

项目代码需要付费吗?

不需要。GitHub 和 Gitee 仓库中的代码完全免费开源,没有 Pro 版本。

配套教程在哪里阅读?

配套教程在哪里阅读?

配套教程是 JavaGuide 知识星球内部小册,通过语雀文档在线阅读,不单独对外出售。

教程是视频还是文字?

教程是视频还是文字?

教程以文字、源码分析和技术配图为主。阅读时可以直接在文章与代码之间切换,也方便后续检索某个协议字段、类或测试场景。

可以直接把项目写进简历吗?

可以直接把项目写进简历吗?

可以,但需要先跑通项目、读懂主要调用链,并完成至少一处自己的修改。面试官通常会从协议设计、Netty 线程模型、ZooKeeper 节点、一致性哈希或 CompletableFuture 继续追问,直接复制项目描述很难应对。

CompletableFuture

加入学习

加入学习

如果你只想阅读源码,直接访问开源仓库即可。如果你希望按调用链学习实现过程,同时准备简历写法和项目追问,可以加入 JavaGuide 知识星球 阅读完整教程。

JavaGuide 知识星球

星球内还提供一对一提问、简历修改、Java 面试资料、系统设计与场景题、源码阅读等内容,可以和这套 RPC 项目一起使用。

星球其他资源

星球其他资源

知识星球除了提供了 《Java 面试指北》 、 《Java 必读源码系列》(目前已经整理了 Dubbo 2.6.x 、Netty 4.x、SpringBoot2.1 的源码)、 《手写 RPC 框架》 、《Kafka 常见面试题/知识点总结》 等多个专属小册,还有读书活动、学习打卡、简历修改、免费提问、海量 Java 优质面试资源以及各种不定时的福利。

知识星球

知识星球专栏概览

星球 PDF 面试手册

下面是星球提供的部分服务(点击下方图片即可获取知识星球的详细介绍):

星球服务

下面是今年收到了部分好评,每一条都是真实存在的。我看到很多培训班或者机构通过虚构一些不存在的好评来欺骗他人购买高价服务(行业内非常常见),真的很难理解。

球友对星球的真实评价

我有自己的原则,不割韭菜,用心做内容,真心希望帮助到你! 如果你感兴趣的话,不妨花 3 分钟左右看看星球的详细介绍:JavaGuide 知识星球详细介绍 。

JavaGuide 知识星球详细介绍

加入星球(限时优惠)

加入星球(限时优惠)

已经坚持维护六年,内容持续更新,虽白菜价(0.4 元/天)但质量很高,主打一个良心!

目前星球正在做活动,两本书的价格,就能让你拥有上万培训班的服务!这里再提供一张 30 元的优惠卷(价格马上上调,老用户扫码续费半价 ):

知识星球30元优惠卷

🚀 入圈必做(干货满满,一定要看!):

星球使用指南

星球使用指南

优质主题汇总

优质主题汇总

无任何套路,无任何潜在收费项。用心做内容,不割韭菜!

不过, 一定要确定需要再进 。并且, 三天之内觉得内容不满意可以全额退款 。