【远程调用框架】如何实现一个简单的RPC框架(五)优化三:软负载中心设计与实现

【如何实现一个简单的RPC框架】系列文章:web

【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计 
【远程调用框架】如何实现一个简单的RPC框架(二)实现与使用 
【远程调用框架】如何实现一个简单的RPC框架(三)优化一:利用动态代理改变用户服务调用方式 
【远程调用框架】如何实现一个简单的RPC框架(四)优化二:改变底层通讯框架 
【远程调用框架】如何实现一个简单的RPC框架(五)优化三:软负载中心设计与实现 
第一个优化以及第二个优化修改后的工程代码可下载资源 如何实现一个简单的RPC框架缓存

 

 

1.前言

在博客【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计中咱们介绍了“服务注册查找中心”,负责服务信息的管理即服务的注册以及查找,在目前为止的实现中,咱们采用web应用的方式,以http协议接口的方式为服务发布者以及调用者提供使用接口。服务发布者在发布服务的同时须要将服务的信息注册到“服务注册查找中心”,供服务调用者进行查询。可是这种方式,有一个很大的弊端就是:没法正确及时感知服务的上线与下线,并及时将服务信息的更改推送到服务调用端。 
所以这里咱们将“服务注册查找中心”改形成一个“软负载中心”来代替“服务注册查找中心”的职责。软负载中心主要负责服务地址等信息的聚合与管理,同时能正确进行服务上下线的感知并推送给服务的订阅者。 
本博客内容部分摘自《大型网站系统与Java中间件实践》数据结构

2.主要功能与结构

2.1 软负载中心的主要功能

2.1.1 聚合地址信息

不管是服务框架中须要用到的服务提供者地址,仍是消息中间件系统中的消息中间件应用的地址,都须要由软负载中心去聚合地址列表,造成一个可供服务调用者及消息的发送者、接收者直接使用的列表。框架

2.1.2 生命周期感知

软负载中心须要能对服务的上下线自动感知,而且根据这个变化去更新服务地址数据,想成新的地址列表后,把数据传给须要数据的调用者活着消息的发送者接收者。socket

2.2 软负载中心的结构

软负载中心包括两部分(1)软负载中心的服务端;(2)软负载中心的客户端ide

2.2.1 服务端

服务端主要负责:性能

  • (1)感知提供服务的机器是否在线。与服务发布者保持长链接,感知服务存活状态,并即便更新服务地址信息;
  • (2)聚合提供者的机器信息。对地址信息进行管理;
  • (3)而且负责把数据传给使用数据的应用。当某一个服务的地址信息有变化时,及时将信息推送给该服务的订阅者

2.2.2 客户端

客户端承载了两个角色,优化

  • (1)做为服务提供者,客户端负责与软负载中心创建长链接,把服务提供者提供服务的具体信息主动传给服务端,而且随着提供服务的变化去更新数据;
  • (2)做为服务使用者,客户端负责与软负载中心创建长链接,向服务端告知本身所须要使用的数据并负责接收服务端的推送,更新数据,还要进行本地的数据缓存,经过本地的数据缓存,使得每次去请求服务获取列表都是一个本地操做,从而提高效率和性能。

3.设计

3.1 软负载中心维护的三类重要数据

软负载中心须要管理服务地址等信息供服务调用者查询使用,同时须要保存服务的订阅关系信息,在服务地址信息发生变化时,将最新结果推送给订阅该服务的相关客户端用户,同时也要维护软负载中心与服务发布端/调用端的链接。所以,软负载中心内部有三部分重要的数据:网站

3.1.1 聚合数据

就是聚合后的地址信息列表。spa

3.1.2 订阅关系

在软负载中心,须要数据的应用(服务使用者等)把本身须要的数据信息高速软负载中心,这就是一个订阅关系,订阅的粒度和聚合数据的粒度是一致的。当聚合数据有变化时,也是经过订阅关系的数据找到须要通知的数据订阅者,而后去进行数据更新的通知。 
3.1.3 链接数据 
是指链接到软负载中心的节点和软负载中心已经创建的链接的管理。采用的是长链接的方式,当订阅的数据产生变化时,经过订阅关系找到须要通知的使用者id,在链接数据这里就能找到对应的链接,而后进行数据的发送,完成对应用的数据更新。

3.2 软负载中心工做模式

这里写图片描述
- (1)服务发布者须要进行服务注册时,主动与软负载中心创建socket长链接,发送服务注册信息DO,同时经过发送心跳包保持与软负载中心的长链接; 
- (2)软负载中心在收到服务发布者发送的心跳包后更新该服务地址的最后更新时间,以此来判断服务是否存活,实时更新服务的地址列表; 
- (3)服务调用者在进行服务调用时会查询本地缓存获取服务的地址列表,而调用者也会与软负载中心创建长链接,实时更新本地缓存; 
- (4)全部聚合数据有变的状况下,都要根据订阅关系,即时讲服务的最新信息推送给该服务的订阅者

3.3 软负载中心设计

3.3.1 通讯数据结构设计

  • (1)客户端向服务端发送的请求数据包DO 
    数据包DO表明服务发布端以及服务调用端与软负载中心服务端长链接中传递的数据包数据结构。长链接中客户端向服务端传送的数据主要包含四种类型,服务发布者发送的注册服务信息以及为了保持长链接发送的心跳数据、服务调用端发送的服务地址查询信息以及为了保持长链接发送的心跳数据。数据结构以下图所示: 
    这里写图片描述
  • (2)服务端向客户端发送的响应数据包DO 
    服务端接收到客户端的请求进行相应的处理后,响应给客户端的数据结构包括:对于心跳包的响应、服务地址查询结果、服务注册结果。数据结构以下图所示: 
    这里写图片描述

3.3.2 服务端维护三种数据结构设计

  • (1)聚合数据:Map类型数据结构,key为服务惟一标识,value为ServiceInfoDO数据类型;
  • (2)订阅关系:Map类型数据结构,key为服务惟一标识,value为订阅该服务的链接惟一标识列表;
  • (3)链接数据:Map类型数据结构,key为链接惟一标识,value为socket长链接对象;
  • (4)链接数据:Map类型数据结构,key为链接惟一标识,value为该链接的ObjectOutputStream;

3.3.3 客户端接口设计

  • (1)做为服务发布者:a 注册服务,与软负载中心保持长链接,发送心跳包;b 关闭链接,中止服务;
  • (2)做为服务调用者:a 订阅服务,与软负载中心保持长链接,查询服务地址,并接收软负载中心发送数据,更新本地缓存;b 查询服务信息(查询本地缓存); c 关闭链接,删除订阅关系 
    本地缓存:map类型的数据结构,key为服务惟一标识,value为服务地址列表。

4.实现与使用

4.1 资源下载

软负载中心的工程代码,可访问 实现一个简单的软负载中心 进行下载;

4.2 使用示例

pom中写上对软负载中心客户端的依赖,以下:

<dependency>
    <groupId>whu.edu.lcrpc.configserver</groupId>
    <artifactId>configserver-client</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

4.2.1 服务发布

使用方式以下代码:

//软负载中心客户端的帮助类
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() + "]注册失败");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

4.2.3 服务订阅

使用方式以下代码:

//软负载中心客户端提供的辅助类
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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4.2.4 效果

  • (1)运行软负载中心,开启监听,以下图所示 
    这里写图片描述

  • (2)发布服务,以下图分别为软负载中心接收到服务注册请求后的效果、服务发布者输出效果 
    这里写图片描述 
    这里写图片描述

  • (3)服务订阅,以下图分别为软负载中心接收到服务订阅请求后的效果、服务订阅者输出效果 
    这里写图片描述
    软负载中心检测到服务增长了一个订阅者 
    这里写图片描述
  • (4)关闭服务发布后,软负载中心以及服务发布端的输出以下图所示 
    这里写图片描述
    软负载中心监测到服务已经下线,所以会将该服务的更新信息推送给该服务的订阅者。 
    这里写图片描述  服务调用端接收到软负载中心的推送后,更新了本地缓存,更新了该服务的地址列表信息
相关文章
相关标签/搜索