張鵬飛
(四川大學計算機學院,成都 610065)
隨著互聯網浪潮風起云涌,互聯網行業發展非常迅速。在一個不斷發展的大型應用中,新的業務功能和需求不斷增加,技術也在不斷演進,不同團隊構建的功能和子系統采用的技術構成五花八門,子系統之間開發、部署和運維也存在較大差異。如果企業內部沒有統一的服務框架進行技術層面的拉通,開發和運維都將會受到很大的約束。
傳統垂直架構的核心就是要對應用進行服務化,服務化改造使用到的核心技術就是分布式服務框架。
分布式服務框架包括服務提供者、服務消費者、服務注冊發現、序列化、服務通信、負載均衡、日志管理等組件。

圖1
其中,服務提供端是分布式服務框架最重要的組成部分,通過將本地服務注冊到服務注冊中心上來發布可用的服務。包含IoC組件、流量控制組件、服務發布組件等。IoC組件提供了依賴注入功能,將對象從對象提供者和使用者之間分離開來,由IoC容器管理對象依賴關系和生命周期。
序列化:序列化是將對象轉化為字節序列的過程。反序列化是序列化的逆過程。序列化幫助我們解決了幾個問題。第一、使不共享內存通過網絡連接的系統之間可以進行對象的傳輸。第二、解決遠程接口調用JVM之間內存無法共享的問題。
日志管理:記錄重要的框架層日志、異常鏈數據,同時將日志的接口暴露出來,讓業務層的程序員能根據日志來調試程序,解決潛在的問題。
服務配置:支持配置文件方式配置,能夠集成主流框架,能夠在框架運行時根據不同的業務場景來調整服務的參數和配置。
服務通信:提供NIO的同步請求響應模式和基于消息的一異步通信方式。
負載均衡:負載均衡的目的是將請求按照某種策略分布到多臺機器上,使系統能夠實現橫向擴展。
框架運行具體流程為:
服務提供端啟動服務器,框架將服務提供者信息(服務主機IP地址、端口號、提供的服務接口信息等)注冊到服務注冊中心。服務消費端將服務提供信息從服務注冊中心讀取到本地緩存中,同時將服務消費者的信息上傳到服務注冊中心去。服務消費端使用系統提供的幾種軟負載均衡算法的某一種來選擇某一個服務提供者,發起服務調用命令。服務提供端收到來自服務消費端的請求,使用數據序列化方案將調用數據序列化為可以在網絡中傳輸的字節數組,發送給服務消費端來完成服務的調用。
大多數使用Java來進行開發的系統都會用Spring來作為組件的容器,開發人員也很熟悉Spring的配置。本文為了提高分布式服務框架的易用性,實現了該框架和Spring的集成,使用Spring管理服務的發布和引入,進而使遠程服務發布Bean與遠程調用編程界面與本地Bean方法調用一致,屏蔽了遠程調用服務與本地方法調用的差異性。
服務端利用Java注解的方式將服務接口用@Rpc-Service標注出來,在框架初始化的時候,框架掃描本地包,將被標注為@RpcService的類加入到容器Map

服務端啟動代碼:


服務請求消息的實體是Resquest類,該類封裝了請求消息ID、請求版本號、請求接口名、請求方法名等信息。服務消費端使用動態代理的設計模式思想,客戶端調用方法時就像該方法實現的類在本地一樣,Java動態代理讀取客戶端請求的方法信息封裝成Request類,啟動網絡連接,將Request發送到服務端去,當調用結果正常返回或者超時發生異常時候,返回該結果。服務消費端初始化和一次服務調用代碼如下:

服務注冊中心是分布式服務框架的目錄服務器,相比于傳統的目錄服務器,它有如下幾個特點。第一,支持數據持久化,支持集群。第二,集群中所有客戶端應該看到同一份數據,不能出現讀或者寫數據不一致。第三,當注冊中心的數據發生變更時(增加、刪除、修改)需要能將及時變化的數據通知客戶端。本文使用Zookeeper來設計服務注冊中心。Zookeeper是Apache Hadoop的一個子項目,它主要用來解決分不少應用中經常遇到的一些數據管理問題,如統一命名服務、狀態同步服務、集群管理等。
Zookeeper是采用樹型目錄結構的,本文定義的注冊中心節點樹如圖2所示。
第一層節點Key用來唯一標識一個應用,可以看作是該應用的一個命名空間。第二層節點Service用來存粗實現服務的信息。第三層節點用來區分服務消費端和服務提供端。最后一層存儲服務消費端或者服務提供端主機IP與服務端口號。其中Key和Service是持久節點,其他節點是臨時節點。Zookeeper持久節點被創建后,就會一直存在于Zookeeper服務器上,直到有刪除操作來主動刪除這個節點。而臨時節點的生命周期和客戶端會話綁定在一起,客戶端會話失效,則這個節點就會被自動清除。這樣就實現了服務的自動上線和下線,當提供服務的服務提供端關閉時,該服務信息也會在注冊中心自動下線。

圖2
無論是服務提供端接受調用方法,還是返回調用結果,都需要通過網絡來進行傳輸。這是本地調用與遠程調用最主要的區別。網絡模塊是影響分布式服務框架性能的關鍵模塊。本文使用來Netty來構建網絡模塊。Netty是著名的NIO開源框架,提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。Netty的線程模型是基于Reactor設計的,如圖3所示。
本文設計了Netty服務端和Netty客戶端。Netty服務端的作用是服務端業務邏輯處理器和編碼解碼處理器。Netty服務端接收客戶端發起的請求字節數組,然后通過解碼器NettyDecodeHandler將字節數組解碼為對應的Java請求對象。然后根據解碼得到的Java請求對象確定服務提供者接口以及方法,最后通過使用Java反射技術來發起調用。

圖3
Netty客戶端發起一次服務調用,并得到調用結果,整個過程如下。第一,獲取服務提供者列表,通過某種軟負載均衡算法選擇一個服務提供者。第二,根據服務提供者信息在Netty連接池中獲取對應的Channel連接。第三,將服務請求數據對象通過某種序列化協議編碼成字節數組,通過Channel發送到服務端。第四,同步等待服務返回調用結果。
本文設計實現了一個輕量級的分布式服務框架,涉及通信、服務調度等。該框架能提供簡潔高效的RPC調用服務,對整個業務系統不會造成任何入侵;實現了序列化與反序列化引擎,軟負載均衡算法引擎,能讓用戶根據業務場景選擇最優的解決方案。功能上,該框架使用同步調用、異步調用,傳輸經過序列化的對象,當請求正常返回和異常返回時都做了相應的處理;性能上,該框架可用讓用戶根據業務場景選擇合適的序列化方案、負載均衡方案,使用Netty提供了針對大量消費端連接的解決方案。但是該框架存在一些不足,例如可用在TCP協議之上自定義協議族,可提高系統的安全性。
參考文獻:
[1]ZHOU Wan-lei.Supporting Fault-tolerant and Open Distributed Processing Using RPC[D].Australia:Deakin University,1996.
[2]李林鋒.分布式服務框架:原理與實踐[M].北京:電子工業出版社,2006.1
[3]查駿.基于NIO的遠程調用框架的設計與實現[D].上海:復旦大學,2012.
[4]劉禮鳴.基于本體的服務治理平臺研究[D].上海:上海交通大學,2011
[6]A.L.Ananda.B.H.Tay,E.K.Koh.A Survey of Asynchronous Remote Procedure Calls[D].ACM SIGOPS Operating Systems Review,1992.
[7]XIAO Xin-xiao,JIA Rui-xiang.Distributed Monitoring and Control System for Energy Saving Based on RPC[D].Qindao:Qilu University of Technology,2014.