天天看點

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

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

本文中以問題為驅動,以故障分析為軸線。在分析問題的過程中總結海量并發場景中對于充電業務的優化實踐經驗。這些問題的産生原因大多并不複雜,但是正如諺語所說:會者不難,難者不會。如果沒有合适的分析手段,往往對于故障問題束手無策。希望在閱讀完本文後,可以對于以後可能發生的問題有些分析手段和分析方向有些許幫助。

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

伺服器CPU持續過高

通路存儲的頻率過高

高并發時的資料亂序

其他導緻實時資料處理能力下降的問題

伺服器的CPU使用率是重要的性能名額。一般的情況下,CPU在10~20%足以應對資料處理的需要,但是在生産環境中多次發生CPU因為某種原因持續超過75%并且無法自行下降的情況。CPU異常高企常常會導緻資料處理能力下降的問題。針對這種情況有必要進行深入分析,查找問題原因并采取有效措施防止類似事故的發生。

首先需要排除由于上傳資料的波動引起的性能變化。如果物聯網裝置離網又上線,雲端首先需要擷取一些資料進行初始化的工作,批量湧入的資料會導緻伺服器的性能壓力問題,但通常不需要人為幹預即可恢複正常。

解決辦法:針對這個問題的分析需要強大的監控圖表的支援,使用監控圖還原故障發生時的場景并針對海量資料的突變規模和業務系統的影響程式進行分析。當然如何進行資料接口的實時監控也是個很大的問題,如果這個做不到,故障現場就無法恢複,原因分析也就無從談起。對于海量資料的監控是足以寫一篇論文的,在此不再展開,有興趣的讀者可以看下influxDB(參考資料5)和grafana的相關資料。

其次需要檢查的是相關的服務運作是否正常。如果雲端的背景是由一系列的微服務構成,而服務之間是通過同步的RPC調用互相串聯起來的,那麼在湧入海量資料時由于某些服務的響應速度問題,造成實時資料處理子產品的大量線程被占用,在.NET中如果有大量線程被喚醒,同時在進行業務處理的話,也是很有可能會造成CPU的升高問題。

解決辦法:針對這個問題的分析辦法是抓取程式的dump,最好能間隔1~2分鐘連續抓取多個dump,并通過dump分析線程池中的線程堆棧,并通過堆棧查找導緻線程積壓的原因(參考資料2),是調用别的服務?還是查詢資料庫?等等。找到線程大量積壓的原因,基本上就成功了大半了。

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

案例一:某次實時資料處理程式CPU預警,排除掉前文所述的可能原因後,針對.NET CLR計數器進行分析,發現在CPU高企的階段# of Exceps Thrown/Sec這個名額也相應的升高,而該名額代表的是某個時刻的程式抛出異常的統計。後來通過統計日志,也印證了前文所述,确實在那個時刻的異常非常多。

CPU和該名額的關系:

CPU(%)

名額值(%)

45

5

16

73

11

82

66

7

32

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

案例二:某次實時資料處理程式CPU預警,排除掉前文的可能原因并排除異常相關名額後,在針對.NET CLR計數器的分析過程中發現,在CPU高企的階段% Time in GC這個名額也比較高,該名額代表GC時間在整個CPU時間中的占比。在發生預警的時段内,該名額的值基本上位于30%~60%的區間内,而非預警時段該名額的值在10%左右。

針對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左右。這個資料比其他所有子產品的總和還要高。特别是通路緩存的頻率非常高,導緻對于緩存性能的依賴非常強,在緩存性能不穩定時非常容易影響到實時資料處理子產品的性能表現。

造成該問題的原因是多方面的,總結起來有以下幾個方面的原因:

1、程式架構原因。因為終端資料上傳至雲端後,是随機配置設定到不同的伺服器上的程式進行處理,是以在處理資料之前必須進行上下文的恢複工作,導緻通路存儲的頻率過高。

2、物聯網通訊協定原因。受到通訊協定的限制,終端隻能上傳目前時刻狀态的資料,而沒有采用重要狀态轉化的事件通知機制,無法表達資料本身所代表的業務含義。導緻雲端的程式必須通過查詢終端之前的相關資料獲知資料的準确意圖。

3、業務邏輯的需要。充電終端上傳的資料是分類按照不同頻率上傳的,在處理這些實時資料的過程中,經常涉及到狀态轉化相關的邏輯處理。如果需要判斷狀态轉化則必須知道是由什麼狀态轉換到目前狀态的,是以需要經常性的從緩存或資料庫中查詢相關資料。

針對以上各種原因,可以采取如下辦法:

1、優化架構設計。通過适當的方法,保證終端資料能穩定傳輸到某個運算節點。可以有效利用伺服器本身的資源緩存終端的相關資料,避免每次都需要恢複上下文。

2、優化物聯網協定。減少依賴實時資料的狀态轉化判斷邏輯,而采用事件通知機制確定重點狀态的處理過程,對于實時資料則更多的用于狀态監控而不是業務邏輯判斷。

終端上傳資料是随機配置設定到不同的伺服器由不同的線程進行處理,是以不能保證資料的處理順序跟資料的上傳順序保持一緻。是以就導緻了實時資料的亂序問題,即可能新的資料被老資料覆寫的問題。目前在生産環境中使用的實時資料處理程式是運作在Thrift上的,當其比較繁忙,特别是CPU占用較高時,經常出現資料延遲和資料亂序的問題,并是以導緻了嚴重的程式邏輯錯誤。

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

方案一:通過嚴格保證資料處理的串行化來避免該問題的發生。但是這個辦法有個最大的問題是導緻了程式性能的下降,本來可以并行處理的業務被迫串行化實際上對于性能影響比較大。

方案二:優化通訊協定,在物聯網傳輸的封包都應該增加時間戳,通過檢查時間戳判斷目前資料是否有效并采取相關邏輯。該方法的最大好處是不影響業務資料的處理性能。當然該方案也有壞處,那就是在確定程式并發時還需要保證邏輯的正确性,是以需要在并發程式設計方面投入更多的精力。

盡管CPU繁忙會導緻資料處理能力下降,但是本章節所述内容與此無關。有時候雖然CPU占用率并不高,記憶體也很充足,但是資料處理能力莫名其妙的下降,并導緻了許多業務方面的問題。

該問題的原因比較隐蔽,通過對于業務子產品的分析,發現該問題與對外推送業務有關。

正常的流程推送是:

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

當實時資料處理子產品判定狀态狀态變化時會通過互聯互通子產品進行對外推送,部分外部接口無法承接巨大的推送量而出現了通路逾時等問題。由于互聯互通子產品設計對外推送時設定的逾時時間是60s,導緻大量的線程在等待外部接口的傳回結果。而線程池的數量時有限制的,當互聯互通子產品的線程池用光後,無法再處理外部的請求,是以請求都積壓在互聯互通子產品的資料隊列中得不到處理,而由于實時資料處理子產品當時是直接同步調用互聯互通子產品進行推送,導緻其本身的大量線程也在等待互聯互通接口的傳回結果,進而造成由外而内的傳導效應。當實時資料處理子產品線程池可用線程用完,也就沒法處理新來的實時資料并導緻了嚴重的性能問題。

對于該問題的解決辦法也相當簡單,通過dump完全可以看到線程的堆棧,通過堆棧确定了問題原因後,推送方和接收方使用消息隊列互相解耦,最終避免了此類事故的再次發生。

<code># of Exceps Thrown / Sec</code>名額較高(&gt;5)時,很容易導緻CPU出現性能問題;

在比較繁忙的業務中使用抛出異常的方式要慎重;

<code>% Time in GC</code>名額持續較高(&gt;10)時,很容易導緻CPU出現性能問題;

使用Server GC有助于緩解GC導緻的性能問題;

在處理實時資料的場景中,資料必須包含時間戳;

在處理實時資料的場景中,頻繁恢複資料的上下文會導緻較高的壓力;

在處理實時資料的場景中,不推薦使用無狀态的處理機制;

資料推送的兩端有最好能通過MQ進行解耦,減少互相影響;

Lock and Thread Performance Counters

網站High CPU分析

Performance Counters in the .NET Framework

<code>&lt;gcServer&gt; Element</code>

網際網路級監控系統必備-時序資料庫之Influxdb技術

網際網路級監控系統必備-時序資料庫之Influxdb叢集及踩過的坑