海量併發下充電業務優化實踐

摘要

目前在進行充電業務開發時,面對的是充電終端上報的海量併發數據。訪問緩存的TPM可達120w,訪問數據庫的TPM在3w左右,高峯時段面對的是近二十萬終端上傳的百萬條併發的實時數據。在這樣的場景下有些無傷大雅的小漏洞最終釀成了生產環境的大問題,正所謂千里之堤毀於蟻穴,面對這樣的場景,必須深刻理解系統所使用的技術並對於常見問題有必備運維經驗和分析能力。本文針對這些問題及解決過程進行分析,總結過往,以饗將來。html

海量併發時遇到的問題

本文中以問題爲驅動,以故障分析爲軸線。在分析問題的過程當中總結海量併發場景中對於充電業務的優化實踐經驗。這些問題的產生緣由大多並不複雜,可是正如諺語所說:會者不難,難者不會。若是沒有合適的分析手段,每每對於故障問題一籌莫展。但願在閱讀完本文後,能夠對於之後可能發生的問題有些分析手段和分析方向有些許幫助。數據庫

首先來看下本文中所涉及的生產環境問題:編程

  1. 服務器CPU持續太高
  2. 訪問存儲的頻率太高
  3. 高併發時的數據亂序
  4. 其餘致使實時數據處理能力降低的問題

服務器CPU太高

服務器的CPU使用率是重要的性能指標。通常的狀況下,CPU在10~20%足以應對數據處理的須要,可是在生產環境中屢次發生CPU由於某種緣由持續超過75%而且沒法自行降低的狀況。CPU異常高企經常會致使數據處理能力降低的問題。針對這種狀況有必要進行深刻分析,查找問題緣由並採起有效措施防止相似事故的發生。緩存

首先須要排除因爲上傳數據的波動引發的性能變化。若是物聯網設備離網又上線,雲端首先須要獲取一些數據進行初始化的工做,批量涌入的數據會致使服務器的性能壓力問題,但一般不須要人爲干預便可恢復正常。服務器

解決辦法:針對這個問題的分析須要強大的監控圖表的支持,使用監控圖還原故障發生時的場景並針對海量數據的突變規模和業務系統的影響程序進行分析。固然如何進行數據接口的實時監控也是個很大的問題,若是這個作不到,故障現場就沒法恢復,緣由分析也就無從談起。對於海量數據的監控是足以寫一篇論文的,在此再也不展開,有興趣的讀者能夠看下influxDB(參考資料5)和grafana的相關資料。架構

其次須要檢查的是相關的服務運行是否正常。若是雲端的後臺是由一系列的微服務構成,而服務之間是經過同步的RPC調用相互串聯起來的,那麼在涌入海量數據時因爲某些服務的響應速度問題,形成實時數據處理模塊的大量線程被佔用,在.NET中若是有大量線程被喚醒,同時在進行業務處理的話,也是頗有可能會形成CPU的升高問題。併發

解決辦法:針對這個問題的分析辦法是抓取程序的dump,最好能間隔1~2分鐘連續抓取多個dump,並經過dump分析線程池中的線程堆棧,並經過堆棧查找致使線程積壓的緣由(參考資料2),是調用別的服務?仍是查詢數據庫?等等。找到線程大量積壓的緣由,基本上就成功了大半了。app

最後的辦法是檢查性能計數器。性能計數器經常被人忽略,可是其在分析CPU問題時經常能起到意想不到的巨大幫助。運維

案例一:某次實時數據處理程序CPU預警,排除掉前文所述的可能緣由後,針對.NET CLR計數器進行分析,發如今CPU高企的階段# of Exceps Thrown/Sec這個指標也相應的升高,而該指標表明的是某個時刻的程序拋出異常的統計。後來經過統計日誌,也印證了前文所述,確實在那個時刻的異常很是多。微服務

CPU和該指標的關係:

CPU(%) 指標值(%)
45 5
16 5
73 11
82 11
66 7
32 5

MSDN的解釋以下(參考資料3):

顯示每秒引起的異常的數目。它包括.NET異常和轉換成.NET 異常的非託管異常。 例如,從非託管代碼返回的HRESULT轉換爲託管代碼中的異常。
此計數器包括已處理和未經處理的異常。此計數器不是一段時間內的平均值;它顯示在最後兩個樣本(以取樣間隔持續時間來劃分)中觀察到的值之間的差別。

案例二:某次實時數據處理程序CPU預警,排除掉前文的可能緣由並排除異常相關指標後,在針對.NET CLR計數器的分析過程當中發現,在CPU高企的階段% Time in GC這個指標也比較高,該指標表明GC時間在整個CPU時間中的佔比。在發生預警的時段內,該指標的值基本上位於30%~60%的區間內,而非預警時段該指標的值在10%左右。

MSDN的解釋以下(參考資料3):

顯示自上次垃圾回收週期後執行垃圾回收所用運行時間的百分比。此計數器一般指示垃圾回收器表明該應用程序爲收集和壓縮內存而執行的工做。只在每次垃圾回收結束時更新此計數器。此計數器不是一個平均值;它的值反映了最近觀察所得值。

針對GC形成的性能問題,首先須要經過dump分析是不是因爲程序自己致使了GC過於頻繁,好比不合適的字符串操做,頻繁分配大對象等等。

若是從dump中沒法得知GC頻繁的緣由,能夠嘗試使用Server GC模式(參考資料4)。經過壓力測試發現,在使用Server GC先後,程序的處理能力相差超過一倍,例如,假設原來的時候單節點TPM200會致使CPU高企,那麼在使用Server GC後,TPM達到450時CPU也不到40%,相對於之前的表現有很大改善。所以使用Server GC能夠有效緩解GC過於頻繁致使的性能問題,顯著提高程序的數據處理能力。

訪問存儲媒介的頻率太高

通過統計,在充電高峯期,處理實時狀態的程序訪問緩存的TPM能夠達到120w,訪問數據庫的TPM在3w左右。這個數據比其餘全部模塊的總和還要高。特別是訪問緩存的頻率很是高,致使對於緩存性能的依賴很是強,在緩存性能不穩定時很是容易影響到實時數據處理模塊的性能表現。

形成該問題的緣由是多方面的,總結起來有如下幾個方面的緣由:

一、程序架構緣由。由於終端數據上傳至雲端後,是隨機分配到不一樣的服務器上的程序進行處理,所以在處理數據以前必須進行上下文的恢復工做,致使訪問存儲的頻率太高。

二、物聯網通信協議緣由。受到通信協議的限制,終端只能上傳當前時刻狀態的數據,而沒有采用重要狀態轉化的事件通知機制,沒法表達數據自己所表明的業務含義。致使雲端的程序必須經過查詢終端以前的相關數據獲知數據的準確意圖。

三、業務邏輯的須要。充電終端上傳的數據是分類按照不一樣頻率上傳的,在處理這些實時數據的過程當中,常常涉及到狀態轉化相關的邏輯處理。若是須要判斷狀態轉化則必須知道是由什麼狀態轉換到當前狀態的,因此須要常常性的從緩存或數據庫中查詢相關數據。

針對以上各類緣由,能夠採起以下辦法:

一、優化架構設計。經過適當的方法,保證終端數據能穩定傳輸到某個運算節點。能夠有效利用服務器自己的資源緩存終端的相關數據,避免每次都須要恢復上下文。

二、優化物聯網協議。減小依賴實時數據的狀態轉化判斷邏輯,而採用事件通知機制確保重點狀態的處理過程,對於實時數據則更多的用於狀態監控而不是業務邏輯判斷。

海量併發時的數據亂序

終端上傳數據是隨機分配到不一樣的服務器由不一樣的線程進行處理,所以不能保證數據的處理順序跟數據的上傳順序保持一致。所以就致使了實時數據的亂序問題,便可能新的數據被老數據覆蓋的問題。目前在生產環境中使用的實時數據處理程序是運行在Thrift上的,當其比較繁忙,特別是CPU佔用較高時,常常出現數據延遲和數據亂序的問題,並所以致使了嚴重的程序邏輯錯誤。

對於該問題有兩個備選方案:

方案一:經過嚴格保證數據處理的串行化來避免該問題的發生。可是這個辦法有個最大的問題是致使了程序性能的降低,原本能夠並行處理的業務被迫串行化實際上對於性能影響比較大。

方案二:優化通信協議,在物聯網傳輸的報文都應該增長時間戳,經過檢查時間戳判斷當前數據是否有效並採起相關邏輯。該方法的最大好處是不影響業務數據的處理性能。固然該方案也有壞處,那就是在確保程序併發時還須要保證邏輯的正確性,所以須要在併發編程方面投入更多的精力。

實時數據處理能力降低

儘管CPU繁忙會致使數據處理能力降低,可是本章節所述內容與此無關。有時候雖然CPU佔用率並不高,內存也很充足,可是數據處理能力莫名其妙的降低,並致使了許多業務方面的問題。

該問題的緣由比較隱蔽,經過對於業務模塊的分析,發現該問題與對外推送業務有關。

正常的流程推送是:

終端數據變化->實時數據處理模塊->互聯互通模塊->第三方

而問題的出現與第三方服務接口響應較慢有關,其傳導過程以下:

第三方接口響應慢
    ->互聯互通大量線程等待HTTP返回結果
    ->互聯互通模塊線程池無可用線程
    ->實時數據處理模塊的線程同步等待互聯互通模塊的返回結果
    ->實時數據處理模塊線程池也逐步用光
    ->數據處理能力降低

當實時數據處理模塊斷定狀態狀態變化時會經過互聯互通模塊進行對外推送,部分外部接口沒法承接巨大的推送量而出現了訪問超時等問題。因爲互聯互通模塊設計對外推送時設置的超時時間是60s,致使大量的線程在等待外部接口的返回結果。而線程池的數量時有限制的,當互聯互通模塊的線程池用光後,沒法再處理外部的請求,因此請求都積壓在互聯互通模塊的數據隊列中得不處處理,而因爲實時數據處理模塊當時是直接同步調用互聯互通模塊進行推送,致使其自己的大量線程也在等待互聯互通接口的返回結果,進而形成由外而內的傳導效應。當實時數據處理模塊線程池可用線程用完,也就無法處理新來的實時數據並致使了嚴重的性能問題。

對於該問題的解決辦法也至關簡單,經過dump徹底能夠看到線程的堆棧,經過堆棧肯定了問題緣由後,推送方和接收方使用消息隊列相互解耦,最終避免了此類事故的再次發生。

總結

  • # of Exceps Thrown / Sec指標較高(>5)時,很容易致使CPU出現性能問題;
  • 在比較繁忙的業務中使用拋出異常的方式要慎重;
  • % Time in GC指標持續較高(>10)時,很容易致使CPU出現性能問題;
  • 使用Server GC有助於緩解GC致使的性能問題;
  • 在處理實時數據的場景中,數據必須包含時間戳;
  • 在處理實時數據的場景中,頻繁恢復數據的上下文會致使較高的壓力;
  • 在處理實時數據的場景中,不推薦使用無狀態的處理機制;
  • 數據推送的兩端有最好能經過MQ進行解耦,減小相互影響;

參考資料

  1. Lock and Thread Performance Counters
  2. 網站High CPU分析
  3. Performance Counters in the .NET Framework
  4. <gcServer> Element
  5. 互聯網級監控系統必備-時序數據庫之Influxdb技術
  6. 互聯網級監控系統必備-時序數據庫之Influxdb集羣及踩過的坑
相關文章
相關標籤/搜索