【如何实现一个简单的RPC框架】系列文章:web
【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计
【远程调用框架】如何实现一个简单的RPC框架(二)实现与使用
【远程调用框架】如何实现一个简单的RPC框架(三)优化一:利用动态代理改变用户服务调用方式
【远程调用框架】如何实现一个简单的RPC框架(四)优化二:改变底层通讯框架
【远程调用框架】如何实现一个简单的RPC框架(五)优化三:软负载中心设计与实现
第一个优化以及第二个优化修改后的工程代码可下载资源 如何实现一个简单的RPC框架缓存
在博客【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计中咱们介绍了“服务注册查找中心”,负责服务信息的管理即服务的注册以及查找,在目前为止的实现中,咱们采用web应用的方式,以http协议接口的方式为服务发布者以及调用者提供使用接口。服务发布者在发布服务的同时须要将服务的信息注册到“服务注册查找中心”,供服务调用者进行查询。可是这种方式,有一个很大的弊端就是:没法正确及时感知服务的上线与下线,并及时将服务信息的更改推送到服务调用端。
所以这里咱们将“服务注册查找中心”改形成一个“软负载中心”来代替“服务注册查找中心”的职责。软负载中心主要负责服务地址等信息的聚合与管理,同时能正确进行服务上下线的感知并推送给服务的订阅者。
本博客内容部分摘自《大型网站系统与Java中间件实践》数据结构
不管是服务框架中须要用到的服务提供者地址,仍是消息中间件系统中的消息中间件应用的地址,都须要由软负载中心去聚合地址列表,造成一个可供服务调用者及消息的发送者、接收者直接使用的列表。框架
软负载中心须要能对服务的上下线自动感知,而且根据这个变化去更新服务地址数据,想成新的地址列表后,把数据传给须要数据的调用者活着消息的发送者接收者。socket
软负载中心包括两部分(1)软负载中心的服务端;(2)软负载中心的客户端ide
服务端主要负责:性能
客户端承载了两个角色,优化
软负载中心须要管理服务地址等信息供服务调用者查询使用,同时须要保存服务的订阅关系信息,在服务地址信息发生变化时,将最新结果推送给订阅该服务的相关客户端用户,同时也要维护软负载中心与服务发布端/调用端的链接。所以,软负载中心内部有三部分重要的数据:网站
就是聚合后的地址信息列表。spa
在软负载中心,须要数据的应用(服务使用者等)把本身须要的数据信息高速软负载中心,这就是一个订阅关系,订阅的粒度和聚合数据的粒度是一致的。当聚合数据有变化时,也是经过订阅关系的数据找到须要通知的数据订阅者,而后去进行数据更新的通知。
3.1.3 链接数据
是指链接到软负载中心的节点和软负载中心已经创建的链接的管理。采用的是长链接的方式,当订阅的数据产生变化时,经过订阅关系找到须要通知的使用者id,在链接数据这里就能找到对应的链接,而后进行数据的发送,完成对应用的数据更新。
- (1)服务发布者须要进行服务注册时,主动与软负载中心创建socket长链接,发送服务注册信息DO,同时经过发送心跳包保持与软负载中心的长链接;
- (2)软负载中心在收到服务发布者发送的心跳包后更新该服务地址的最后更新时间,以此来判断服务是否存活,实时更新服务的地址列表;
- (3)服务调用者在进行服务调用时会查询本地缓存获取服务的地址列表,而调用者也会与软负载中心创建长链接,实时更新本地缓存;
- (4)全部聚合数据有变的状况下,都要根据订阅关系,即时讲服务的最新信息推送给该服务的订阅者
软负载中心的工程代码,可访问 实现一个简单的软负载中心 进行下载;
pom中写上对软负载中心客户端的依赖,以下:
<dependency> <groupId>whu.edu.lcrpc.configserver</groupId> <artifactId>configserver-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
使用方式以下代码:
//软负载中心客户端的帮助类 IServiceProviderClient serviceProviderClient = new ServiceProviderClientImpl(); //定义一个服务信息的数据结构 ServiceInfoDO serviceInfoDO = new ServiceInfoDO(); serviceInfoDO.setInterfaceName("interfacename"); serviceInfoDO.setVersion("version"); serviceInfoDO.setIp("10.129.34.19"); serviceInfoDO.setImplClassName("implClassName"); //注册服务 if (serviceProviderClient.serviceRegistry(serviceInfoDO)){ System.out.println("服务[" + serviceInfoDO.getInterfaceName() + "_" + serviceInfoDO.getVersion() + "]注册成功"); }else { System.out.println("服务[" + serviceInfoDO.getInterfaceName() + "_" + serviceInfoDO.getVersion() + "]注册失败"); }
使用方式以下代码:
//软负载中心客户端提供的辅助类 ServiceConsumerClientImpl serviceConsumerClient = new ServiceConsumerClientImpl(); try { //订阅服务,服务的惟一标识为"interfacename_version" serviceConsumerClient.subscribeServiceInfo("interfacename_version"); //订阅服务完成后,查询服务的地址列表 Set<String> ips = serviceConsumerClient.queryServiceInfo("interfacename_version"); //输出该服务的地址列表 System.out.println("服务[" + "interfacename_version" + "]的地址列表为: " + ips); } catch (NoServiceFoundException noServiceFound) { System.out.println("服务[" + "interfacename_version" + "]未找到"); noServiceFound.printStackTrace(); }
(1)运行软负载中心,开启监听,以下图所示
(2)发布服务,以下图分别为软负载中心接收到服务注册请求后的效果、服务发布者输出效果