HSF全稱爲High-Speed Service Framework,旨在爲淘系的應用提供一個分佈式的服務框架,HSF從分佈式應用層面以及統一的發佈/調用方式層面爲你們提供支持,從而能夠很容易的開發分佈式的應用以及提供或使用公用功能模塊,而不用考慮分佈式領域中的各類細節技術,例如遠程通信、性能損耗、調用的透明化、同步/異步調用方式的實現等等問題。java
對象的序列化過程在RPC過程當中是很重要的一個環節,序列化對於遠程調用的響應速度、吞吐量、網絡帶寬消耗等一樣也起着相當重要的做用。
在HSF1.0時只支持兩種序列化方式:java 和 hessian,在HSF2.0以後就支持了五種序列化方式:java、hessian、hessian二、json、kyro。
可是目前版本中經常使用的序列化方式仍是java 和 hessian兩種。 若是想細緻的瞭解也能夠多作了解。web
對於消費方來講,所存在的只有一個接口,雖然底層的實現原理咱們知道,可是爲了在使用時的高度透明,在JAVA語言層面上的表現形式則是經過動態代理的方式實現的,不少的邏輯都在InvocationHandler 中處理的。關於如何實現動態代理,還動態代理的一些使用的細節也能夠稍做了解。編程
若是在網絡傳輸過程當中,採起普通的BIO,會有不少的問題存在,例如若是調用端有多個請求過來,那麼就得須要多個線程去處理,每一個線程都使用獨立的鏈接,在遠端的提供者端有對應的多個線程來執行相應的服務。這種方式會使得調用者和提供者之間創建大量的鏈接,並且是阻塞的方式,鏈接並不能獲得充分的利用(摘自《大型網站系統與JAVA中間件》)。採用NIO則就能夠避免這樣的損耗,可是HSF在使用時並非採用直接的NIO編程,而是經過第三方的框架Netty。json
從以上幾個問題出發,看下HSF的實現方式。緩存
從圖中能夠看出,HSF的實現方式能夠理解爲是C/S的架構,可是和傳統的C/S架構相比仍是有很大的不一樣,HSF沒有真正的服務器,每一個應用均可以成爲服務的調用方和提供方。具體工做方式以下:服務器
ConfigServer:遠程調用對端的地址就是由ConfigServer 來推送的,這樣用戶只須要配置本身的服務端或者消費端,不須要對本身的地址進行管理。網絡
Diamond:持久化的配置中心,用於配置服務調用的規則。架構
服務:服務是調用方和提供方交流的依憑,通常是一個接口,表示一個業務行爲以及相關的數據含義。經過使用HSFApiProviderBean可以暴露一個服務,將機器的地址註冊到configserver,而且可以經過12200端口進行服務提供,經過HSFApiConsumerBean可以包裝出一個客戶端,它是服務接口的一個代理,而且它從configserver上訂閱了服務的地址列表,可以在這個列表上完成隨機調用,作到負載均衡與HA((High Available,高可用性羣集)。負載均衡
網絡通訊:HSF的底層網絡通訊是使用netty框架實現的,是基於epoll的NIO的網絡通信框架,HSF在此使用的是長鏈接,經過合理的服務部署及負債均衡,基本不存在I/O方面的限制。框架
關於HSF的架構基本能夠理解爲C/S結構設計方式。(雖然HSF沒有本身的服務器)
Server端除了configServer外還有一個diamond用來保存一些持久化的配置信息,這裏不進行過多的介紹。
Client是HSF的重點,下面是各模塊的功能介紹:
Proxy:這一層主要負責接口的代理。基本上全部的RPC框架都會用到代理模式,相信你們不陌生。須要注意的是HSF的代理層還進行了軟負載和單元化的處理。
Remoting:這一層是HSF的應用層協議,定義了報文格式,各個字段的含義等信息,內容比較多,以後單獨寫一篇文章來介紹。
Processer:這一層主要是處理HSF自身的業務邏輯,包括埋點、限流、鑑權等。
Netty:上面三層會將一次服務調用或者服務返回包裝成一個報文,而後經過這層傳輸。
HSF調用流程
上圖是HSF整個的調用過程,從左向右看:
第一條線路至關於consumer進行服務調用的過程,首先通過proxy層,將請求通過代理類包裝出去;而後是Remoting層進行協議的包裝,(處理HSF自身的業務邏輯,包括埋點、限流、鑑權等)最後io層發送出去。
第二條線路至關於provider將結果返回後解析的過程,與上一流程恰好相反。
右邊的provider兩條調用流程相信你們都能按照上面的過程理解,就不一一講解了。
心跳檢測:
一、客戶端主動關閉鏈接:客戶端第一次與服務端創建連接後,就會週期性(27s)發送心跳包的callback調用,若是連續三次收不到服務端的心跳包迴應,客戶端主動關閉連接
二、服務端主動關閉鏈接:當鏈接59s沒有調用(對方網絡不可用,或者full gc過久),至關於兩次(2*27s)收不到心跳包的時間
從上圖能夠看出RPC要解決如下幾個問題:
如何解決網絡通訊問題,主要是經過在客戶端和服務器之間創建TCP鏈接,遠程過程調用的全部交換的數據都在這個鏈接裏傳輸。鏈接能夠是按需鏈接,調用結束後就斷掉,也能夠是長鏈接,多個遠程過程調用共享同一個鏈接。
如何解決尋址問題,客戶端如何找到制定的服務端,也就是保證準確有效的完成一次服務調用的前提。
參數的傳遞及服務端在收到客戶端請求後如何實現其具體功能並返回,因爲網絡傳輸協議是二進制的,內存中的參數值必需要解決序列化,反序列化,以及對半包,粘包的處理。
經過註冊中心,實現服務的註冊/註銷與服務的發現。當服務啓動後,會調用publish來將服務發佈到中心,而服務的消費者,經過調用訂閱接口傳入的監聽器來更新服務提供者列表。HSF提供了三種註冊中心實現,分別是ConfigServer,Zookeper,和配置文件模式。
這裏僅對Zookeper進行分析,ZookeeperMetadataAddressService 實現了上述接口,在初始化中實例化了一個ZookeeperRegistry來進行管理,其使用了一個封裝了zookeperclient的實例-ZkclientZookeeperClient,在註冊服務的時候根據url參數中的Constants.DYNAMIC_KEY來肯定建立Persistent節點仍是Ephemeral節點,Ephemeral節點生命週期與本機鏈接綁定,這樣就能夠實現本機離線後的服務自動註銷的功能。
HSF採用長鏈接方式進行通訊,相比短鏈接,長鏈接更具性能優點,避免鏈接重複建立與銷燬帶來的緩衝區申請與釋放。HSF抽象了鏈接AbstractClient(Client),並採用了netty框架做爲底層實現。netty是一個性能很是優秀的通訊框架,基於Reactor模式,內部採用了管線模式來解耦不一樣層次的邏輯之間的耦合問題。HSF爲了強化TCP鏈接的可用性,增長HeartBeat功能,使用了一個Netty提供的 HashedWheelTimer 的定時任務調度器來執行心跳包的發送(補充:此HashedWheelTimer原理採用輪片式的桶結構,避免每次操做對所有任務的迭代操做,只對將要到期的桶進行操做,此原理也可用於緩存系統設計,在須要進行垃圾回收的狀況下只須要按照桶爲單位進行內存回收)。
HSF最大優勢是非侵入性,它使用了JAVA的Proxy機制來實現這一特色,在經過xml配置文件配置Consumer的時候,其實是調用了 HSFApiConsumerBean ,在它的初始化方法中,讀取了配置的實現接口,並在ProcessComponent中用一個封裝了Proxy註冊功能,並實現了InvocationHandler接口的類HSFServiceProxy去管理。使用者在本身的代碼中無需作任何特殊處理,就像使用本地方法同樣去調用其方法。
這一特性能夠很靈活的幫助上線運營的服務在升級過程當中避免服務不可用的狀況。
能夠經過網頁可視化查看、管理、測試服務的可用。
能夠接入自動服務降級功能(熔斷) - 根據配置或服務的執行結果,在調用級控制服務是否調用執行,避免服務總體癱瘓,提高服務的可用性。
參考:
https://blog.csdn.net/qq_16681169/article/details/72512819