鱼皮项目简易版 RPC 框架开发(一)
本文为笔者阅读鱼皮的项目 《简易版 RPC 框架开发》的笔记,如果有时间可以直接去看原文
引用:
1. 简易版 RPC 框架开发
RPC框架的简单理解
一、基本概念
什么是 RPC?
RPC(Remote Procedure Call,远程过程调用)是一种允许运行在一台计算机上的程序调用另一台计算机上子程序的技术。这种技术屏蔽了底层的网络通信细节,使得程序间的远程通信如同本地调用一样简单。RPC机制使得开发者能够构建分布式计算系统,其中不同的组件可以分布在不同的计算机上,但它们之间可以像在同一台机器上一样相互调用。
一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用程序中的对象一样。
比较正式的描述是:一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
关键特性:
-
透明性:调用远程服务与本地方法体验一致
-
解耦:服务消费者与提供者物理隔离
-
跨语言:可通过统一协议实现多语言通信(如 gRPC/Thrift)
2. 为什么需要 RPC?
场景示例:
-
系统 A(点餐服务)提供下单接口
-
系统 B(订单系统)需调用该接口
无 RPC 的痛点:
// 手动构造 HTTP 请求(繁琐且易错) String url = "http://api.yupi.icu/order"; OrderRequest req = new OrderRequest(itemId, userId, count); HttpResponse res = httpClient.post(url).body(req).execute(); Long orderId = parseResponse(res);
有 RPC 的优势:
// 像调用本地方法一样简单 Long orderId = orderService.order(itemId, userId, count);
核心价值:降低分布式系统开发复杂度,提升协作效率。
二、RPC 框架实现思路
基本设计
RPC 框架为什么能帮我们简化调用?如何实现一个 RPC 框架呢?
其实很简单,开局一张图,有服务消费者和服务提供者两个角色:
消费者想要调用提供者,就需要提供者启动一个 web 服务
,然后通过 请求客户端
发送 HTTP 或者其他协议的请求来调用。
比如请求 yupi.icu/order
地址后,提供者会调用 orderService 的 order 方法:
但如果提供者提供了多个服务和方法,每个接口和方法都要单独写一个接口?消费者要针对每个接口写一段 HTTP 调用的逻辑么?
其实可以提供一个统一的服务调用接口,通过 请求处理器
根据客户端的请求参数来进行不同的处理、调用不同的服务和方法。
可以在服务提供者程序维护一个 本地服务注册器
,记录服务和对应实现类的映射。
举个例子,消费者要调用 orderService 服务的 order 方法,可以发送请求,
参数为 service=orderService,method=order
,
然后请求处理器会根据 service 从服务注册器中找到对应的服务实现类,并且通过 Java 的反射机制调用 method 指定的方法。
需要注意的是,由于 Java 对象无法直接在网络中传输,所以要对传输的参数进行 序列化
和 反序列化
。
为了简化消费者发请求的代码,实现类似本地调用的体验。可以基于代理模式,为消费者要调用的接口生成一个代理对象,由代理对象完成请求和响应的过程。
所谓代理,就是有人帮你做一些事情,不用自己操心。
至此,一个最简易的 RPC 框架架构图诞生了:
上图中的虚线框部分,就是 RPC 框架需要提供的模块和能力。
扩展设计
1、服务注册发现
问题 1:消费者如何知道提供者的调用地址呢?
我们需要一个 注册中心
,来保存服务提供者的地址。消费者要调用服务时,只需从注册中心获取对应服务的提供者地址即可。
架构图如下:
一般用现成的第三方注册中心,比如 Redis、Zookeeper 即可。
2、负载均衡
问题 2:如果有多个服务提供者,消费者应该调用哪个服务提供者呢?
我们可以给服务调用方增加负载均衡能力,通过指定不同的算法来决定调用哪一个服务提供者,比如轮询、随机、根据性能动态调用等。
架构图如下:
3、容错机制
问题 3:如果服务调用失败,应该如何处理呢?
为了保证分布式系统的高可用,我们通常会给服务的调用增加一定的容错机制,比如失败重试、降级调用其他接口等等。
架构图如下:
4、其他
除了上面几个经典设计外,如果想要做一个优秀的 RPC 框架,还要考虑很多问题。
比如:
- 服务提供者下线了怎么办?需要一个失效节点剔除机制。
- 服务消费者每次都从注册中心拉取信息,性能会不会很差?可以使用缓存来优化性能。
- 如何优化 RPC 框架的传输通讯性能?比如选择合适的网络框架、自定义协议头、节约传输体积等。
- 如何让整个框架更利于扩展?比如使用 Java 的 SPI 机制、配置化等等。
所以,完成 RPC 项目并不难,但做一个完美的 RPC 项目却是难于上青天啊!
总结一下,我们可以通过做一个 RPC 项目学习到网络、序列化、代理、服务注册发现、负载均衡、容错、可扩展设计等知识,相信完成项目后会收获满满。