【如何實現一個簡單的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)發佈服務,以下圖分別爲軟負載中心接收到服務註冊請求後的效果、服務發佈者輸出效果