中国人自己的框架——蚂蚁金服RPC框架结构分析
螞蟻金服近期開源了研發多年的SOFA一籃子框架,其中就有一個非常核心的RPC框架,它叫SOFA-BOLT。小編今天花了近一天的時間仔細閱讀研究它的源碼,閱讀過程中遇到了不少問題,螞蟻金服的相關技術人員都非常耐心的及時解答了我的疑難。這里將我從中學到的知識點一并分享給大家。
SOFA-BOLT基于開源的Netty框架,同時提供了服務器和客戶端的實現。它的源碼非常值得一讀,結構簡單,考慮周全,絕不是一個普通的玩具。它沒有濫用設計模式,源碼閱讀起來比較直接,沒有太多繞來繞去的復雜結構。
一個節點既可以同時既是RPC服務器又是客戶端,作為客戶端該節點需要其它節點提供服務,作為服務器它可以為其它節點提供服務。不過上面這張圖并不是合理的結構,因為兩個服務相互耦合了,我需要你,你也需要我,就成了雞蛋問題。比較合理的結構一般如下圖所示,它們之間不構成環。
通訊協議
通訊協議是客戶端和服務器之間交流的語言,SOFA定義了自己的一套通訊協議,它的編碼解碼分為二層,第一層是消息體對象的二進制序列化,這部分默認由開源的Hession協議庫序列化完成,第二層是負責給序列化的消息體增加一系列包裝字段,形成一個完整的消息。包括請求ID、消息體的長度、協議版本號和CRC32校驗位等等
如果希望進一步優化網絡性能,SOFA還提供了Snappy壓縮協議,可以在現有的兩層協議基礎上增加第三層,能顯著降低網絡傳輸負擔。壓縮是時間換空間,提升網絡性能的同時,它也會加重CPU計算,所以在使用時需要適當進行權衡。
連接池
客戶端和服務器之間一般需要建立多個連接,但是也不能每個請求都建立一個連接。一般是通過維護一個連接池,限定最大連接數。客戶端通過有限的連接來和服務器進行通信。
我們在使用Jedis客戶端和Redis服務器進行通信時,也是通過連接池來獲取連接的。Jedis的連接必須是線程獨占的,因為它不是線程安全的。從連接池中獲取連接時,其它線程就暫時拿不到這個連接了,待當前線程處理完畢后,要將連接歸還給線程池,這樣其它線程才可以繼續使用這個連接。
Redis的客戶端請求和應答是順序性的,一問一答,所以請求和應答不需要唯一ID就可以建立起關聯。
Bolt不一樣,它的問答是亂序的,問和答之間是必須通過請求的唯一ID來建立起關聯。Bolt的客戶端是線程安全的,它可以同時傳遞多個請求,連接對象會維護一個正在處理的RPC請求對象字典。當客戶端想要發起RPC請求時,它不是從連接池中摘出一個獨占連接,而是隨意選擇一個連接來傳遞自己的請求,這個連接也可以被其它線程同時使用。
負載均衡
客戶端提供了多種復雜均衡的實現,阿里默認使用帶權重的隨機算法(RandomLoadBalancer),此外還有
服務器線程模型
服務器采用傳統netty多線程模型,一個acceptor線程專門用來接收連接,然后扔給io線程處理讀消息并解碼成請求
對象,最后扔給業務線程池進行處理。
心跳
客戶端和服務器之間會有定時心跳檢測連接的存活,默認30s來一次。tcp的關閉是通過FIN包來通知對方的,如果因為網絡問題,對方連FIN包都收不到,那么即使一邊關閉了套接字,另一邊可能還以為連接正常。所以心跳檢測存活機制在長連接應用里非常普遍。如果客戶端連續發了三次心跳都沒有收到服務器的回復,那么就認為連接已經關閉。服務器也會有連接存活檢測,如果一個客戶端連接90s內沒有任何消息進來,那么也認為該連接已經斷開。服務器不會主動發送心跳消息。
雙工通信
RPC一般是由客戶端向服務器發起一個請求,然后收到服務器的應答。Bolt的RPC是雙工通信,服務器也可以向客戶端主動發起請求,它們共享一個TCP連接。TCP連接本身就是雙工的,所以這也不算什么奇跡。只是服務器在什么業務場景需要向客戶端主動發起請求,這個螞蟻并沒有進行詳細說明。
客戶端作為主動連接方,它要負責重連和發起心跳消息。服務器作為被動方,它不需要處理重連,如果連接斷開,它就直接將連接從集合中移除就行,不需要做特殊的處理,但是它會檢測心跳消息,如果在一定時間內連接通道沒有任何消息到來,它就會主動關閉。
重連
客戶端的重連策略是一個單獨的模塊,有兩個地方會成為重連的入口。一個是正常連接斷開觸發channelInActive回調,另一個就是重連連接不能建立成功時需要進行重試。Bolt有一個單獨的重連線程,所有需要重連的連接會被包裝成一個任務塞進這個線程的任務隊列,該線程不斷地從隊列里拿任務進行重連處理,如果重連失敗會嘗試再將任務重新包裝進隊列延后繼續處理。默認是1s鐘處理一個重連任務。
RPC連接是延遲建立的,它在第一次客戶端發送RPC請求時嘗試進行連接,如果連接失敗,它會立即繼續重連最多默認兩次。如果三次嘗試連接后還是沒有建立成功,就向上層爆出異常。它不需要包裝一個重連任務塞進ReconnectManager,因為后續客戶端請求會繼續觸發連接。
單向消息
RPC通常是一應一答,客戶端可以同步等待響應,也可以提供回調接口等待結果通知。Bolt除了提供應答模式之外,還提供了oneway單向消息,這種消息服務器收到后不用回復,客戶端發送請求之后就立即返回了也不需要等待結果。
oneway消息一般用于不那么重要的日志類消息,它不能保證服務器一定能收到,所以此種業務消息應該是那種允許丟失的消息,形式上類似于UDP,它在犧牲可靠性的前提下能大幅提升消息的吞吐量。
在此我向大家推薦一個架構學習交流群。交流學習群號:575745314 里面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化、分布式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
消息追蹤
Bolt提供了回調接口,方便監控系統可以對請求的調用狀況進行分析。監控的客戶端可以通過實現該接口,注冊進RPC的客戶端和服務器進行打點收集日志,然后發送到日志分析系統。
總結
Bolt是一個成熟的比較復雜的RPC系統,這篇小文章只講解了其中一部分,內部還有大量的實現細節有待去挖掘。
注:關注微信公眾號:《JAVA爛豬皮》解鎖更多精彩內容
總結
以上是生活随笔為你收集整理的中国人自己的框架——蚂蚁金服RPC框架结构分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MHDD硬盘坏道检测修复教程(转)
- 下一篇: 刺激战场幽默的名字(一提刺激消费)