1. 程式人生 > >【遠端呼叫框架】如何實現一個簡單的RPC框架(五)優化三:軟負載中心設計與實現

【遠端呼叫框架】如何實現一個簡單的RPC框架(五)優化三:軟負載中心設計與實現

【如何實現一個簡單的RPC框架】系列文章:

1.前言

在部落格【遠端呼叫框架】如何實現一個簡單的RPC框架(一)想法與設計中我們介紹了“服務註冊查詢中心”,負責服務資訊的管理即服務的註冊以及查詢,在目前為止的實現中,我們採用web應用的方式,以http協議介面的方式為服務釋出者以及呼叫者提供使用介面。服務釋出者在釋出服務的同時需要將服務的資訊註冊到“服務註冊查詢中心”,供服務呼叫者進行查詢。但是這種方式,有一個很大的弊端就是:無法正確及時感知服務的上線與下線,並及時將服務資訊的更改推送到服務呼叫端。
因此這裡我們將“服務註冊查詢中心”改造成一個“軟負載中心”來代替“服務註冊查詢中心”的職責。軟負載中心主要負責服務地址等資訊的聚合與管理,同時能正確進行服務上下線的感知並推送給服務的訂閱者。
本部落格內容部分摘自《大型網站系統與Java中介軟體實踐》

2.主要功能與結構

2.1 軟負載中心的主要功能

2.1.1 聚合地址資訊

無論是服務框架中需要用到的服務提供者地址,還是訊息中介軟體系統中的訊息中介軟體應用的地址,都需要由軟負載中心去聚合地址列表,形成一個可供服務呼叫者及訊息的傳送者、接收者直接使用的列表。

2.1.2 生命週期感知

軟負載中心需要能對服務的上下線自動感知,並且根據這個變化去更新服務地址資料,想成新的地址列表後,把資料傳給需要資料的呼叫者活著訊息的傳送者接收者。

2.2 軟負載中心的結構

軟負載中心包括兩部分(1)軟負載中心的服務端;(2)軟負載中心的客戶端

2.2.1 服務端

服務端主要負責:

  • (1)感知提供服務的機器是否線上。與服務釋出者保持長連線,感知服務存活狀態,並即使更新服務地址資訊;
  • (2)聚合提供者的機器資訊。對地址資訊進行管理;
  • (3)並且負責把資料傳給使用資料的應用。當某一個服務的地址資訊有變化時,及時將資訊推送給該服務的訂閱者

2.2.2 客戶端

客戶端承載了兩個角色,

  • (1)作為服務提供者,客戶端負責與軟負載中心建立長連線,把服務提供者提供服務的具體資訊主動傳給服務端,並且隨著提供服務的變化去更新資料;
  • (2)作為服務使用者,客戶端負責與軟負載中心建立長連線,向服務端告知自己所需要使用的資料並負責接收服務端的推送,更新資料,還要進行本地的資料快取,通過本地的資料快取,使得每次去請求服務獲取列表都是一個本地操作,從而提升效率和效能。

3.設計

3.1 軟負載中心維護的三類重要資料

軟負載中心需要管理服務地址等資訊供服務呼叫者查詢使用,同時需要儲存服務的訂閱關係資訊,在服務地址資訊發生變化時,將最新結果推送給訂閱該服務的相關客戶端使用者,同時也要維護軟負載中心與服務釋出端/呼叫端的連線。因此,軟負載中心內部有三部分重要的資料:

3.1.1 聚合資料

就是聚合後的地址資訊列表。

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>

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() + "]註冊失敗");
}

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();
}

4.2.4 效果

  • (1)執行軟負載中心,開啟監聽,如下圖所示
    這裡寫圖片描述

  • (2)釋出服務,如下圖分別為軟負載中心接收到服務註冊請求後的效果、服務釋出者輸出效果
    這裡寫圖片描述
    這裡寫圖片描述

  • (3)服務訂閱,如下圖分別為軟負載中心接收到服務訂閱請求後的效果、服務訂閱者輸出效果
    這裡寫圖片描述
    軟負載中心檢測到服務增加了一個訂閱者
    這裡寫圖片描述
  • (4)關閉服務釋出後,軟負載中心以及服務釋出端的輸出如下圖所示
    這裡寫圖片描述
    軟負載中心監測到服務已經下線,因此會將該服務的更新資訊推送給該服務的訂閱者。
    這裡寫圖片描述
    服務呼叫端接收到軟負載中心的推送後,更新了本地快取,更新了該服務的地址列表資訊