轉載RPC框架實現
RPC(Remote Procedure Call,遠程過程調用)框架是分布式服務的基石,實現RPC框架需要考慮方方面面。其對業務隱藏了底層通信過程(TCP/UDP、打包/解包、序列化/反序列化),使上層專注於功能實現;框架層面,提供各類可選架構(多進程/多線程/協程);應對設備故障(高負載/死機)、網絡故障(擁塞/網絡分化),提供相應容災措施。
監控是分布式服務中相當重要的一部分,其有助於我們了解業務發展狀況,出災時提供第一手分析資訊。分布式系統中的每一個模塊,都需要一些指標說明其服務狀況和服務質量,如調用總數、成功數、連接失敗數、調用平均耗時等,這些指標應該由RPC框架默認提供;對於業務相關的指標,例如查看附近的人的總人數、查看附近的人的男/女人數、扔漂流瓶的總人數等,RPC框架也應該提供接口,方便業務開發同學添加相關監控項。
下面我們就來了解實現RPC框架監控的一種方案。
id-key監控
首先我們來看如何對模塊監控,這里模塊由一組提供相同服務的設備組成,一個模塊對外提供統一的服務端口。
那么對一個模塊默認應該具備哪些監控項呢?除了以上提到的調用總數、調用成功數、連接失敗數、調用平均耗時外,還可以具備以下監控項:
- Server端所有接口耗時統計
- Client端所有接口耗時統計
- 請求包/響應包大小統計
- Server各階段處理統計
- Accept失敗
- 超過最大連接數
- 請求隊列滿
- Server端的重啟
- coredump統計
以上監控項中,既有Client端的上報數據,也有Server端自己的上報數據,通過服務提供方和服務使用方兩方面監控,確保監控數據的全面和准確。根據RPC框架的具體實現,Server各階段處理統計可以有不同的細分統計(例如從Accept Queue接收到fd到將請求包push到Inqueue的耗時統計),幫助我們從更細的角度觀察RPC框架內部。
有了監控的對象和目標,接着就是如何實現。從一個模塊對外提供一個服務端口這一點出發,可以實現基於id-key的分鍾級監控。id-key是存在於共享內存中的一個二維數組,具體表示如下:

id和key均為unsigned int類型,id的取值范圍為 0 ~ 64K-1,key的取值范圍為 0 ~ 63。兩塊共享內存,一塊用於讀,一塊用於寫,每分鍾切換這兩塊內存。這兩塊共享內存一共占用的內存大小為:64K * 64 * 4(bytes) * 2 = 32M。
模塊的端口可以映射為一個id,key對應於以上一個個監控項,在RPC框架層修改相關監控項(例如Client進行connect調用失敗時,對相應Server連接失敗的id-key加1)。通過每分鍾切換讀寫共享內存塊,我們得到每分鍾某個模塊單機的統計數據,我們可以將這些數據進行入庫。
但單機的緯度還不夠,我們經常需要了解一個模塊整體的服務情況,於是我們對每分鍾數據進行收集、聚合:

以分鍾為單元,將該模塊各台設備不同id-key的數據進行求和,我們就得到了該模塊各指標整體的分鍾級數據。RPC框架內置進程將統計數據寫入共享內存,從共享內存獲取數據並上傳進行合並可由另外的進程完成。
對於業務相關的數據,也可以通過id-key的方法實現監控,對某項業務我們可以申請id(注意避免與模塊的id沖突),自定義各項key的含義,然后在業務代碼中將相關指標上報到對應id-key。
調用關系
分布式系統中,我們經常需要看一個模塊的上下游關系,類似以下展現形式:

以模塊A為查詢對象,對應的可以找到其主調模塊x/y/z、被調模塊ß/ą/μ等模塊,同時顯示調用總數、系統失敗數等主被調的服務情況。
我們在框架中也可以實現調用關系數據的收集,每次RPC調用,以主調(SvrID,ModID)為key,被調(SvrID,ModID)為value入主調數據庫,另以被調(SvrID,ModID)為key,主調(SvrID,ModID)為value入被調數據庫。查看模塊A上游時查詢被調數據庫,查看模塊A下游時查詢主調數據庫。
調用關系方便我們檢查RPC框架中,一條鏈的調用情況,在更大的層面我們有時候希望看到調用網的情況,在一個更大維度觀察系統,出災時可以更直觀地看到異常模塊。關於分布式系統調用網監控,可以參考Google Dapper這篇文章。
小結
本文介紹了RPC框架中實現監控的id-key方案,id-key通過數據收集與聚合,在框架層默認為各個模塊提供調用總數、調用平均耗時等指標,同時可方便添加各種業務數據關聯的統計指標。分布式系統中,對某個業務定位分析問題時,經常需要查看該業務相關的調用鏈,分析一個模塊的主被調情況,這也需要在RPC框架層面提供支持。
