设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架
ccwgpt 2025-07-24 17:00 4 浏览 0 评论
为啥要开发RPC框架
事情是这样的,在开发这个RPC框架之前,我花费了不少时间算是对Dubbo框架彻底研究透彻了。
冰河在撸透了Dubbo2.x和Dubbo3.x的源码之后,本来想给大家写一个Dubbo源码解析的专栏。为此,我其实私下准备了一个多月:画流程图、分析源码、写测试Demo,自己在看Dubbo源码时,也为Dubbo源码添加了非常详细的注释。这里,就包含Dubbo2.x和Dubbo3.x的源码。
当我就这么熬夜肝文一个多月后,突然发现一个问题:Dubbo经过多年不断的迭代开发,它的源码已经非常多了,如果以文章的形式将Dubbo的源码面面俱到的分析到位,那还不知道要写到何年何月去了。当我写文章分析Dubbo的最新版本3.x时,可能写到专栏的中后期Dubbo已经更新到4.x、5.x,设置有可能是6.x、7.x了。
与其这么费劲吧咧的分析源码,还不如从零开始带着大家一起手撸一个能够在实际生产环境使用的、分布式、高性能、可扩展的RPC框架。这样,大家也能够直观的感受到一个能够在实际场景使用的RPC框架是如何一步步开发出来的。
相信大家在学完《RPC手撸专栏》后,自己再去看Dubbo源码的话,就相对来说简单多了。你说是不是这样的呢?
你能学到什么?
既然是整个专栏的开篇嘛,肯定是要告诉你在这个专栏中能够学习到哪些实用的技术的。这里,我就画一张图来直观的告诉你在《RPC手撸专栏》能够学到哪些技术吧。
相信小伙伴们看到《RPC手撸专栏》涉及到的知识点,应该能够了解到咱们这个从零开始的《RPC手撸专栏》还是比较硬核的吧?
另外,咱这RPC项目支持同步调用、异步调用、回调和单向调用。
- 同步调用:
- 异步调用:
- 回调:
- 单向调用
对,没错,咱们《RPC手撸专栏》最终实现的RPC框架的定位就是尽量可以在实际环境使用。通过这个专栏的学习,让大家深入了解到能够在实际场景使用的RPC框架是如何一步步开发出来的。
代码结构
我将这个bhrpc项目定位为可在实际场景使用的、分布式、高性能、可扩展的RPC框架,目前总体上已经开发并完善的功能达到60+个子项目,大家看图吧(可以点开看大图)。
项目大量使用了对标Dubbo的自定义SPI技术实现高度可扩展性,各位小伙伴可以根据自己的需要,按照SPI的设计要求添加自己实现的自定义插件。
显示效果
说了那么多,咱们一起来看看这个RPC框架的使用效果吧,因为咱们这个RPC框架支持的调用方式有:原生RPC调用、整合Spring(XML/注解)、整合SpringBoot、整合SpringCloud、整合SpringCloud Alibaba,整合Docker和整合K8S七种使用方式。
这里,咱们就以 整合Spring注解的方式 来给大家演示下这个RPC框架。
RPC核心注解说明
为了让大家更好的了解这个RPC框架,我先给大家看下RPC框架的两个核心注解,一个是RPC的服务提供者注解@RpcService,一个是RPC的服务调用者注解@RpcReference。
(1)服务提供者注解@RpcService的核心源码如下所示。
/**
* @author binghe
* @version 1.0.0
* @description bhrpc服务提供者注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface RpcService {
/**
* 接口的Class
*/
Class<?> interfaceClass() default void.class;
/**
* 接口的ClassName
*/
String interfaceClassName() default "";
/**
* 版本号
*/
String version() default "1.0.0";
/**
* 服务分组,默认为空
*/
String group() default "";
/**
* 延迟发布,预留
*/
int delay() default 0;
/**
* 是否导出rpc服务,预留
*/
boolean export() default true;
}
(2)服务调用者注解@RpcReference的核心源码如下所示。
/**
* @author binghe
* @version 1.0.0
* @description bhrpc服务消费者
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Autowired
public @interface RpcReference {
/**
* 版本号
*/
String version() default "1.0.0";
/**
* 注册中心类型, 目前的类型包含:zookeeper、nacos、etcd、consul
*/
String registryType() default "zookeeper";
/**
* 注册地址
*/
String registryAddress() default "127.0.0.1:2181";
/**
* 负载均衡类型,默认基于ZK的一致性Hash
*/
String loadBalanceType() default "zkconsistenthash";
/**
* 序列化类型,目前的类型包含:protostuff、kryo、json、jdk、hessian2、fst
*/
String serializationType() default "protostuff";
/**
* 超时时间,默认5s
*/
long timeout() default 5000;
/**
* 是否异步执行
*/
boolean async() default false;
/**
* 是否单向调用
*/
boolean oneway() default false;
/**
* 代理的类型,jdk:jdk代理, javassist: javassist代理, cglib: cglib代理
*/
String proxy() default "jdk";
/**
* 服务分组,默认为空
*/
String group() default "";
}
这里,我只列出了服务提供者注解@RpcService和服务调用者注解@RpcReference的部分源码,后续在RPC框架不断完善的过程中,大家就可以慢慢看到源码的全貌和其每个注解实现的功能。这里,我就不详细介绍了。
当然啦,在这个RPC框架实现的原生调用方式中,可以不用这些注解就能够实现远程调用。
效果演示
接口定义
定义两个接口,分别为HelloService和HelloPersonService,源码如下所示。
- HelloService接口源码
public interface HelloService {
String hello(String name);
String hello(Person person);
}
- HelloPersonService接口源码
public interface HelloPersonService {
List<Person> getTestPerson(String name,int num);
}
实现服务提供者demo
(1)创建HelloService接口和HelloPersonService接口的实现类HelloServiceImpl和HelloPersonServiceImpl,如下所示。
- HelloServiceImpl类源码
@RpcService(interfaceClass = HelloService.class, version = "1.0.0")
public class HelloServiceImpl implements HelloService {
@Override
public String hello(String name) {
return "Hello! " + name;
}
@Override
public String hello(Person person) {
return "Hello! " + person.getFirstName() + " " + person.getLastName();
}
}
可以看到,在HelloServiceImpl类上添加了RPC服务提供者注解@RpcService,表示将其发布为一个RPC服务。
- HelloPersonServiceImpl类源码
@RpcService(interfaceClass = HelloPersonService.class, version = "1.0.0")
public class HelloPersonServiceImpl implements HelloPersonService {
@Override
public List<Person> getTestPerson(String name, int num) {
List<Person> persons = new ArrayList<>(num);
for (int i = 0; i < num; ++i) {
persons.add(new Person(Integer.toString(i), name));
}
return persons;
}
}
可以看到,在HelloPersonServiceImpl类上添加了RPC服务提供者注解@RpcService,表示将其发布为一个RPC服务。
(2)创建服务提供者demo的配置类ServerConfig,在ServerConfig类中注入RegistryService注册中心接口的实现类,以及RPC服务提供者的核心类RpcServer,如下所示。
/**
* @author binghe
* @version 1.0.0
* @description 基于注解的配置类
*/
@Configuration
@ComponentScan(value = {"io.binghe.rpc.demo"})
@PropertySource(value = {"classpath:rpc.properties"})
public class SpringAnnotationProviderConfig {
@Value("${registry.address}")
private String registryAddress;
@Value("${registry.type}")
private String registryType;
@Value("${registry.loadbalance.type}")
private String registryLoadbalanceType;
@Value("${server.address}")
private String serverAddress;
@Value("${reflect.type}")
private String reflectType;
@Bean
public RpcSpringServer rpcSpringServer(){
return new RpcSpringServer(serverAddress, registryAddress, registryType, registryLoadbalanceType, reflectType);
}
}
(3)创建服务提供者demo的启动类ServerTest,如下所示。
/**
* @author binghe
* @version 1.0.0
* @description RPC整合Spring注解,服务提供者demo启动类
*/
public class ServerTest {
public static void main(String[] args){
new AnnotationConfigApplicationContext(SpringAnnotationProviderConfig.class);
}
}
实现服务调用者demo
(1)创建测试服务调用者的TestService接口,如下所示。
public interface TestService {
void printResult();
}
(2)创建TestService接口的实现类TestServiceImpl,在TestServiceImpl类上标注Spring的@Service注解,并在TestServiceImpl类中通过@RpcReference注解注入HelloService接口的实现类和HelloPersonService接口的实现类,并实现TestService接口的printResult()方法,源码如下所示。
/**
* @author binghe
* @version 1.0.0
* @description 测试RPC服务调用者
*/
@Service
public class TestServiceImpl implements TestService {
@RpcReference(version = "1.0.0", timeout = 3000, proxy = "javassist", isAsync = true)
private HelloService helloService;
@RpcReference(proxy = "cglib")
private HelloPersonService helloPersonService;
@Override
public void printResult() {
String result = helloService.hello("binghe");
System.out.println(result);
result = helloService.hello(new Person("binghe001", "binghe002"));
System.out.println(result);
System.out.println("=================================");
List<Person> personList = helloPersonService.getTestPerson("binghe", 2);
personList.stream().forEach(System.out::println);
}
}
通过TestServiceImpl类的源码我们可以看到,远程调用HelloService接口的方法时使用的是javassist动态代理,远程调用HelloPersonService接口时,使用的是cglib动态代理。
(3)创建服务调用者demo的配置类ClientConfig,如下所示。
@Configuration
@ComponentScan(value = {"io.binghe.rpc.*"})
@PropertySource(value = {"classpath:rpc.properties"})
public class ClientConfig {
}
(4)创建服务调用者demo的启动类ClientTest,如下所示。
public class ClientTest {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ClientConfig.class);
TestService testService = context.getBean(TestService.class);
testService.printResult();
context.close();
}
}
启动服务测试
(1)启动Zookeeper,这里,为了演示简单,就直接在我本机启动单机Zookeeper好了,启动后的效果如下图所示。
(2)启动服务提供者ServerTest类,启动后输出的日志信息如下所示。
13:43:36,876 INFO ConnectionStateManager:228 - State change: CONNECTED
13:43:36,905 INFO RpcClient:79 - use cglib dynamic proxy...
13:43:36,942 INFO CuratorFrameworkImpl:235 - Starting
13:43:36,943 INFO ZooKeeper:868 - Initiating client connection, connectString=127.0.0.1:2181
可以看到,服务提供者已经将发布的服务注册到了Zookeeper中。
(3)登录Zookeeper客户端查看Zookeeper中注册的服务,如下所示。
- 查看HelloService接口发布的服务信息
[zk: localhost:2181(CONNECTED) 5] get /binghe_rpc/io.binghe.rpc.test.client.HelloService#1.0.0/65eb0d7f-4bf7-4a0a-bafc-1b7e0e030353
{"name":"io.binghe.rpc.test.client.HelloService#1.0.0","id":"65eb0d7f-4bf7-4a0a-bafc-1b7e0e030353","address":"127.0.0.1","port":18866,"sslPort":null,"payload":{"@class":"io.binghe.rpc.center.meta.ServiceMeta","serviceName":"io.binghe.rpc.test.client.HelloService","serviceVersion":"1.0.0","serviceAddr":"127.0.0.1","servicePort":18866},"registrationTimeUTC":1656135817627,"serviceType":"DYNAMIC","uriSpec":null,"enabled":true}
- 查看HelloPersonService接口发布的服务信息
[zk: localhost:2181(CONNECTED) 7] get /binghe_rpc/io.binghe.rpc.test.client.HelloPersonService#1.0.0/882a5cdb-f581-4a83-8d56-800a8f14e831
{"name":"io.binghe.rpc.test.client.HelloPersonService#1.0.0","id":"882a5cdb-f581-4a83-8d56-800a8f14e831","address":"127.0.0.1","port":18866,"sslPort":null,"payload":{"@class":"io.binghe.rpc.center.meta.ServiceMeta","serviceName":"io.binghe.rpc.test.client.HelloPersonService","serviceVersion":"1.0.0","serviceAddr":"127.0.0.1","servicePort":18866},"registrationTimeUTC":1656135817274,"serviceType":"DYNAMIC","uriSpec":null,"enabled":true}
通过Zookeeper客户端可以看出,HelloService接口和HelloPersonService接口发布的服务都已经被注册到Zookeeper了。
(4)启动服务提供者ClientTest类,实现RPC调用,输出的日志信息如下所示。
13:56:47,391 INFO ConnectionStateManager:228 - State change: CONNECTED
13:56:47,488 INFO RpcClient:76 - use javassist dynamic proxy...
13:56:47,518 INFO ConnectionStateManager:228 - State change: CONNECTED
13:56:47,545 INFO RpcClient:79 - use cglib dynamic proxy...
13:56:48,253 INFO RpcConsumer:85 - connect rpc server 127.0.0.1 on port 18866 success.
Hello! binghe
Hello! binghe001 binghe002
=================================
0 binghe
1 binghe
可以看到,在ClientTest类的命令行输出了远程调用的结果信息。并输出了调用HelloService接口的远程方法使用的是javassist动态代理。调用HelloPersonService接口的远程方法使用的是cglib动态代理。
咱们一起手撸的RPC框架其实还有很多非常强大的功能,这里,就不一一演示了,后面咱们都会一起手撸来实现它。
相关推荐
- 腾讯开源框架TarsCpp-rpc设计分析-server(二)
-
2Tars协议2.1是什么借用官方说法:TARS编码协议是一种数据编解码规则,它将整形、枚举值、字符串、序列、字典、自定义结构体等数据类型按照一定的规则编码到二进制数据流中。对端接收到二进制数据流...
- 微服务调用为什么用RPC框架,http不更简单吗?
-
简单点,HTTP是协议,RPC是概念!实现RPC可以基于HTTP协议(Feign),TCP协议(Netty),RMI协议(Soap),WebService(XML—RPC)框架。传输过程中,也因为序列...
- go-zero:开箱即用的微服务框架(gin框架微服务)
-
go-zero是一个集成了各种工程实践的Web和rpc框架,它的弹性设计保障了大并发服务端的稳定性,并且已经经过了充分的实战检验。go-zero在设计时遵循了“工具大于约定和文档”的理...
- SOFARPC :高性能、高扩展性、生产级的 Java RPC 框架
-
#暑期创作大赛#SOFARPC是一个高性能、高扩展性、生产级的JavaRPC框架。在蚂蚁金服,SOFARPC已经使用了十多年,已经发展了五代。SOFARPC致力于简化应用程序之间的RPC...
- 自研分布式高性能RPC框架及服务注册中心ApiRegistry实践笔记
-
痛点1.bsf底层依赖springcloud,影响bsf更新springboot新版本和整体最新技术版本升级。2.eureka已经闭源,且框架设计较重,同时引入eureka会自行引入较多sprin...
- Rust语言从入门到精通系列 - Tonic RPC框架入门实战
-
Rust语言是一种系统级语言,被誉为“没有丧失性能的安全语言”。Rust语言的优势在于其内存安全机制,在编译时就能保证程序的内存安全。Tonic模块是Rust语言的一个RPC(RemoteProce...
- 腾讯开源框架TarsCpp-rpc设计分析-client(一)
-
前言Tars是腾讯开源的微服务平台,包含了一个高性能的rpc框架和服务治理平台,TarsCpp是其C++版本。对于以C++为主要开发语言,同时还想深入了解rpc和微服务框架具体实现的同学来说,Tars...
- 设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架
-
为啥要开发RPC框架事情是这样的,在开发这个RPC框架之前,我花费了不少时间算是对Dubbo框架彻底研究透彻了。冰河在撸透了Dubbo2.x和Dubbo3.x的源码之后,本来想给大家写一个Dubbo源...
- rpc框架使用教程,超级稳定好用,大厂都在使用
-
rpc是什么远程调用协议如何使用导入依赖<dependency><groupId>org.apache.dubbo</groupId><art...
- Layui 框架实战:动态加载 Select 与二级联动全解析
-
在现代Web开发中,下拉选择框(Select)是用户输入数据时不可或缺的组件。很多时候,我们需要的选项并非静态写死在HTML中,而是需要根据业务逻辑从后端动态获取。更有甚者,我们可能需要实现“...
- 15个能为你节省数百小时的前端设计神器,从UI库到文档生成
-
无论你是刚开始开发之旅的新手,还是疲于应付生产期限的资深程序员,有一个真理始终不变:正确的工具能彻底改变你的工作流程。多年来,我测试了数百个开发工具——有些实用,大多数平庸。但有一批免费网站经受住了时...
- Layui与WinForm通用权限管理系统全解析
-
嘿,小伙伴们,今天咱们来聊聊Layui和WinForm这两个框架在通用权限管理系统中的应用。别担心,我会尽量用简单易懂的语言来讲解,保证让大家都能跟上节奏!首先说说Layui。Layui是一个前端UI...
- 纯Python构建精美UI!MonsterUI让前端开发效率飙升
-
“无需CSS知识,告别类名记忆,11行代码实现专业级卡片组件”在传统Web开发中,构建美观界面需要同时掌握HTML、CSS、JavaScript三剑客,开发者不得不在多种语言间频繁切换。即使使用Boo...
- WebTUI:将终端用户界面(TUI)之美带到浏览器的CSS库
-
在当今Web技术飞速发展的时代,界面设计愈发复杂多样。然而,随着现代化工具的广泛使用,一些开发者开始回归极简风格,追求一种简洁而富有韵味的设计。WebTUI正是这样一款CSS库,它将经典的终...
- 人教版二年级下册生字描红汇总(拼音+笔顺+描红),可打印!
-
可定制内容,评论区留言。本次整理的为人教版二年级下册所有生字,共计300个;写字是小学阶段一项重要的基本功训练,把汉字写得正确、工整、美观,可以提高运用汉字这一交际工具的准确性和效率。对小学生进行写字...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 腾讯开源框架TarsCpp-rpc设计分析-server(二)
- 微服务调用为什么用RPC框架,http不更简单吗?
- go-zero:开箱即用的微服务框架(gin框架微服务)
- SOFARPC :高性能、高扩展性、生产级的 Java RPC 框架
- 自研分布式高性能RPC框架及服务注册中心ApiRegistry实践笔记
- Rust语言从入门到精通系列 - Tonic RPC框架入门实战
- 腾讯开源框架TarsCpp-rpc设计分析-client(一)
- 设计了一款TPS百万级别的分布式、高性能、可扩展的RPC框架
- rpc框架使用教程,超级稳定好用,大厂都在使用
- Layui 框架实战:动态加载 Select 与二级联动全解析
- 标签列表
-
- 框架图 (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)
- tornado框架 (48)
- 前端框架bootstrap (54)
- ppt框架 (48)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)