<SOFA:Channel/>,有趣實用的分佈式架構頻道。
回顧視頻以及 PPT 查看地址見文末。歡迎加入直播互動釘釘羣 : 30315793,不錯過每場直播。
你們好,我是本期 SOFAChannel 的分享講師丞一,來自螞蟻集團,是 SOFABolt 的開源負責人。今天咱們來聊一下螞蟻集團開源的網絡通訊框架 SOFABolt 的框架解析以及功能介紹。本期分享將從如下四個方面展開:git
相信你們都知道 SOFAStack,SOFAStack(Scalable Open Financial Architecture Stack)是一套用於快速構建金融級雲原生架構的中間件,也是在金融場景裏錘鍊出來的最佳實踐。程序員
SOFABolt 則是 SOFAStack 中的網絡通訊框架,是一個基於 Netty 最佳實踐的輕量、易用、高性能、易擴展的通訊框架,他的名字 Bolt 取自迪士尼動畫《閃電狗》。他一開始是怎麼在螞蟻集團內部產生的,咱們能夠類比一下 Netty 的產生緣由:github
這些年,在微服務與消息中間件在網絡通訊上,螞蟻集團解決過不少問題、積累了不少經驗並持續進行着優化和完善,咱們把總結的解決方案沉澱到 SOFABolt 這個基礎組件裏並反饋到開源社區,但願可以讓更多使用網絡通訊的場景受益。目前該組件已經運用在了螞蟻集團中間件的微服務 (SOFARPC)、消息中心、分佈式事務、分佈式開關、以及配置中心等衆多產品上。編程
同時,已有數家企業在生產環境中使用了 SOFABolt,感謝你們的確定,也但願 SOFABolt 能夠給更多的企業帶來實踐價值。安全
以上企業信息根據企業用戶 Github 上反饋統計 — 截止 2020.06。網絡
SOFABolt:https://github.com/sofastack/sofa-bolt架構
SOFABolt 總體能夠分爲三個部分:併發
下面,咱們分別介紹一下 SOFABolt 每一個部分的具體能力。框架
如上圖所示,SOFABolt 有多種通訊模型,分別爲:oneway、sync、future、callback。下面,咱們介紹一下每一個通訊模型以及他們的使用場景。異步
oneway 調用的場景很是明確,當調用方不須要拿到調用結果的時候就可使用這種模式,可是當須要處理調用結果的時候,選擇使用同步的 sync 仍是使用異步的 future 和 callback?都是異步調用,又如何在 future、callback 兩種模式中選擇?
顯然同步能作的事情異步也能作,可是異步調用會涉及到線程上下文的切換、異步線程池的設置等等,較爲複雜。若是你的場景比較簡單,好比整個流程就一個調用並處理結果,那麼建議使用同步的方式處理;若是整個過程須要分幾個步驟執行,能夠拆分不一樣的步驟異步執行,給耗時的操做分配更多的資源來提高系統總體的吞吐。
在 future 和 callback 的選擇中,callback 是更完全的異步調用,future 適用於須要協調多個異步調用的場景。好比須要調用多個服務,而且根據多個服務端響應結果執行邏輯時,能夠採用 future 的模式給多個服務發送請求,在統一對全部的 future 進行處理完成協同操做。
在上一部分的通訊模型中,除了 oneway 以後,其餘三種(sync、future、callback)都須要進行超時控制,由於用戶須要在預期的時間內拿到結果。超時控制簡單來講就是在用戶發起調用後,在預期的時間內若是沒有拿到服務端響應的結果,那麼此次調用就超時了,須要讓用戶感知到超時,避免一直阻塞調用線程或者 callback 永遠得不到執行。
在通訊框架中,超時控制必需要知足高效、準確的要求,由於通訊框架是分佈式系統的基礎組件,一旦通訊框架出現性能問題,那麼上層系統的性能顯然是沒法提高的。超時控制的準確性也很是重要,好比用戶預期一次調用最多隻能執行3秒,由於超時控制不許確致使用戶調用時線程被阻塞了4秒,這顯然是不能接受的。
SOFABolt 的超時控制採用了 Netty 中的 HashedWheelTimer,其原理如上圖。假設一次 tick 表示100毫秒,那麼上面的時間輪 tick 一輪表示800毫秒,若是須要在300毫秒後觸發超時,那麼這個超時任務會被放到'2'的 bucket 中,等到 tick 到'2'時則被觸發。若是一個超時任務須要在900毫秒後觸發,那麼它會被放到如'0'的 bucket 中,並標記 task 的 remainingRounds=1,當第一次 tick 到'0'時發現 remainingRounds 不等於0,會對 remainingRounds 進行減1操做,當第二次 tick 到'0',發現這個任務的 remainingRounds 是0,則觸發這個任務。
若是將時間輪的一次 tick 設置爲1秒,ticksPerWheel 設置爲60,那麼就是現實時鐘的秒針,走完一圈表明一分鐘。若是一個任務須要再1分15秒後執行,就是標記爲秒針走一輪以後指向第15格時觸發。關於時間輪的原理推薦閱讀下面這篇論文:
《Hashed and Hierarchical Timing Wheels: data structures to efficiently implement a timer facility》。
超時控制機制能夠保證客戶端的調用在一個預期時間以後必定會拿到一個響應,不管這個響應是由服務端返回的真實響應,仍是觸發了超時。若是由於某些緣由致使客戶端的調用超時了,而服務端在超時以後實際將響應結果返回給客戶端了會怎麼樣?
這個響應結果在客戶端會被丟棄,由於對應的請求已經由於超時被釋放掉,服務端的這個響應會由於找不到對應的請求而被丟棄。既然響應在請求超時以後返回給客戶端會被丟棄,那麼在肯定請求已經超時的狀況下服務端是否能夠不處理這個請求而直接返回超時的響應給客戶端?——這就是 SOFABolt 的快速失敗機制。
快速失敗機制能夠減輕服務端的負擔,使服務端儘快恢復服務。好比由於某些外部依賴的因素致使服務端處理一批請求產生了阻塞,而此時客戶端還在將更多的請求發送到服務端堆積在 Buffer 中等待處理。當外部依賴恢復時,服務端由於要處理已經在 Buffer 中的請求(實際這些請求已經超時,處理這些請求將沒有業務意義),而致使後續正常的請求排隊阻塞。加入快速失敗機制後,在這種狀況下能夠將 Buffer 中的請求進行丟棄而開始服務當前新增的未超時的請求,使的服務能快速的恢復。
快速失敗機制的前提條件是能判斷出一個請求已經超時,而判斷超時須要依賴時間,依賴時間則須要統一的時間參照。在分佈式系統中是沒法依賴不一樣的機器上的時間的,由於網絡會有延遲、機器時間的時間會有誤差。爲了不參照時間的不一致(機器之間的時鐘不一致),SOFABolt 的快速失敗機制只依賴於服務端機器自身的時鐘(統一的時間參照),判斷請求已經超時的條件爲:
System.currentTimestamp - request.arriveTimestamp > request.timeout
request.arriveTimestamp 爲請求達到服務端時的時間,request.timeout 爲請求設置的超時時間,由於請求從客戶端發出到服務端須要時間,因此當以到達時間來計算時,若是這個請求已經超時,那麼這個請求在客戶端側必然已經超時,能夠安全的將這個請求丟棄。
具體分佈式系統中時間和順序等相關的文件推薦閱讀《Time, Clocks, and the Ordering of Events in a Distributed System》,Lamport 在此文中透徹的分析了分佈式系統中的順序問題。
SOFABolt 中包含的協議命令如上圖所示。在 RPC 版本的協議命令中只包含兩類:RPC 請求/響應、心跳的請求/響應。RPC 的請求/響應負責攜帶用戶的請求數據和響應數據,心跳請求用於鏈接的保活,只攜帶少許的信息(通常只包含請求 ID 之類的必要信息便可)。
有了命令以後,還須要有命令的編解碼器和命令處理器,以實現命令的編解碼和處理。RemotingCommand 的處理模型以下:
整個請求和響應的過程設計的核心組件如上圖所示,其中:
客戶端側:
服務端側:
SOFABolt 除了提供基礎通訊能力外,內置了私有協議的實現,能夠作到開箱即用。內置的私有協議實現是通過實踐打磨的,具有擴展性的私有協議實現。
在 SOFABolt 中實現私有協議的關鍵是實現編解碼器(CommandEncoder/CommandDecoder)及命令處理器(CommandHandler)。
上面是爲了在 SOFABolt 中實現自定義私有協議鎖須要編寫的類。SOFABolt 將編解碼器及命令處理器都綁定到 Protocol 對象上,每一個 Protocol 實現都有一組本身的編解碼器和命令處理器。
在編解碼器中實現自定義的私有協議。在設計私有協議時必定要考慮好協議的可拓展性,以便在將來進行功能加強時不會出現協議沒法兼容的狀況。
完成編解碼以後剩餘工做就是實現處理器。處理器分爲兩塊:命令處理入口 CommandHandler 及具體的業務邏輯執行器 RemotingProcessor。
完成以上工做後,使用 SOFABolt 實現自定義私有協議通訊的開發工做基本完成了,可是在實際編寫這部分代碼時會遇到種種困難及限制,主要體如今如下一些方面:
整體而言,當前 SOFABolt 提供了很是強大的通訊能力和多年沉澱的協議設計。若是用戶須要去適配本身當前已經在運行的私有協議還有能夠完善的地方,根本緣由仍是在於設計之初是貼合這 RPC 框架來設計的(從不少代碼的命名上也能看出來),因此在協議和框架的分離上能夠作的更好。
本次分享從 SOFABolt 總體框架的實現開始,介紹了 SOFABolt 的基礎通訊模型、超時控制以及快速失敗機制,着重分析了私有協議實現的示例,總結而言 SOFABolt 提供了:
歡迎 Star SOFABolt:https://github.com/sofastack/sofa-bolt
以上就是本期分享的主要內容。由於直播時間有限,關於 SOFABolt 更詳細的介紹,能夠閱讀「剖析 SOFABolt 框架」系列文章,由 SOFABolt 團隊以及開源社區同窗共同出品:
「剖析 SOFABolt 框架」解析:https://www.sofastack.tech/blog/ 點擊 tag 「剖析 | SOFABolt 框架」
SOFABolt 目前也存在能夠提高完善的地方,在嘗試實現徹底自定義的私有協議時是相對困難的,須要對代碼作一些繼承改造。
針對這個現狀,咱們在「阿里巴巴編程之夏」活動中提交了一個 SOFABolt 的課題:「拆分 SOFABolt 的框架和協議」,但願先經過拆分框架和協議,以後再進行模塊化的處理,使 SOFABolt 成爲一個靈活的、可拓展的通訊框架最佳實踐!
歡迎你們一塊兒共建來解決這個問題,讓 SOFABolt 變得更好:
https://github.com/sofastack/sofa-bolt/issues/224
SOFAStack 也歡迎更多開源愛好者加入社區共建,成爲社區 Contributor、Committer
SOFACommunity:https://www.sofastack.tech/community/