1. 程式人生 > >記一次高並發場景下.net監控程序數據上報的性能調優

記一次高並發場景下.net監控程序數據上報的性能調優

埋點 異步 上下 沒有 表現 上線 部分 技術 求和

最近在和小夥伴們做充電與通信程序的架構遷移。遷移前的架構是,通信程序負責接收來自充電集控設備的數據實時數據,通過Thrift調用後端的充電服務,充電服務收到響應後放到進程的Queue中,然後在管理線程的調度下,啟動多線程進程數據處理。

技術分享圖片

隨著業務規模的不斷擴大和對系統可用性的逐步提高。現在這個架構存在很多的問題,比如:

1.充電服務重啟,可能會丟數據。

2.充電服務重啟會波及影響通信服務。

3.充電服務與通信服務面對的需求和變化是不一樣,強依賴的架構帶來很多的問題。

為了解決上述的這些問題,項目組決定借助Kafka對程序進行改造 。總體思路是,通信服務收到數據後,把數據存儲到kafka,然後通過一個異步任務處理框架實時消費Kafka數據,並調用業務插件處理。

通過上面思路我們可以看到,系統整體架構僅是引入了一個MQ中間件,業務邏輯並沒有發生本質的變化。但是在實際的壓測中,卻發現新架構下的程序性能比原來要慢很多。順便說一下,壓測場景是模擬10萬充電終端離網上下線,短時間內會生成大約32萬的消息量,遙信:10萬,遙測:10萬,電量10萬,其他:2萬。

通過ANTS分析相關進程,發現MonitorDataUploader.AddToLocalCache方法占用了78%左右的CPU。此方法不是業務方法,是為了監控程序的運行情況而加入的埋點監控。通過進一步分析看,在30多萬消息量下,會產生約1000萬甚至更高的監控消息。在如此高的並發下,這部分程序存在很嚴重的性能問題,導致系統的資源占用很高,系統運行變慢。

技術分享圖片

OK。既然問題已經清楚,那就開始優化吧。雖然可以把監控埋點屏蔽,臨時解決程序的性能問題。但是,這對一個互聯網應用來說是要不得的。沒有監控,系統的運行健康狀況就一無所知,這對一個SLA要求99.95%的系統來說,是不現實的。所以,必須全力優化監控程序在上報海量監控日誌上的性能問題。

為了便於驗證問題,寫了一個模擬程序.通過模擬程序,很容易的再現了CPU占用很高的情況。

技術分享圖片

技術分享圖片

代碼實現中,監控消息的存儲是通過BlockingCollection存儲的,並且設置了Collection大小為1000萬。

var cache = new BlockingCollection<MonitorData>(boundedCapacity);

技術分享圖片

通過閱讀BlockingCollection 的說明,可以看到空構造函數可以不設置Collection的上限。看到這個解釋,懷疑是限制了上線的Collection存在性能問題。與是把代碼中對BlockingCollection 的構造改成空構造,再次測試。測試結果大出意料,性能表現有了非常好的提升。

技術分享圖片

為了進一步驗證問題,把對BlockingCollection 的構造改了限制大小,並設置上線為1個億。測試時消息總量為5000萬,驗證一下是否是BlockingCollection 達到上限後,引起的嚴重性能問題。通過測試數據看,CPU消耗與不限制時基本一致。通過此可以確定,BlockingCollection 在設置了容量上限後,如果消息超過容量,性能將會非常差。

技術分享圖片

通過上面的調優,在發送5000萬監控消息的情況下,程序的CPU在60% 左右持續30s左右。雖然性能有所改善,但是還不是很盡如人意。 有沒有更好的解決方案呢?通過不算的思考和嘗試,終於找到了一個更好的解決方案:基於雙緩存+線程級多桶式Collection。此種模式下性能表現如下,CPU平均在30%左右,持續時間在15s左右。性能又有近一倍的提升。具體實現方案下次再分享。

技術分享圖片

記一次高並發場景下.net監控程序數據上報的性能調優