本文作者從事運營商計費系統工作18年,歷經計費2.8和BSS3.0,參與過計費2.8、BSS3.0等集團規范編制和入網測試,參與了多個運營商省級計費系統建設。
隨著運營商5G商用規模的不斷擴大,5G用戶比例不斷提高,計費系統話單數成幾何倍數快速增長。如果計費話單處理性能不能同步提升,涉及大量話單處理的業務場景都會出現嚴重問題。
計費應用無法及時處理高峰期的話單,導致話單大量積壓,影響流量提醒及時性,引發大面積用戶投訴。
當計費系統發生重大故障,系統恢復時間較長時,將會積壓大量話單。此時就需要強大的計費話單處理能力來進行追單處理,否則如果臨近月底話單還沒跑完,將會影響出帳,后果不堪設想。
計費系統對帳時,如果想對全省一個月的話單進行新老系統對帳,那么對帳人員需要耗費大量的時間在等待跑帳。按月話單數300億估算,如果話單處理能力只有6w tps,那么需要耗費將近6天時間才能跑完,不具備重新跑帳的時間。
導致性能問題的業務原因很明確,所產生問題的業務后果也明確,解決問題的緊迫性很強烈,本文就筆者近期在某項目實際優化工作中的探索總結進行分享。
性能調優,實際上就是不斷地針對遇到的性能問題,尋找解決方案并獲得突破,最終達成理想的優化效果。計費話單處理能力的性能問題到底在哪里呢?
我們在反復壓測和調優過程中,將遇到的性能問題分為三類:部署架構問題、業務流程問題和應用邏輯問題。
眾所周知,新一代的計費系統一般都采用“平臺+應用”的全新IT架構,在部署上應用和數據一般是分離的,優化前普遍采用的部署架構如下:

應用環節間采用消息中間件進行話單流轉,采預應用按用戶取模把話單分發給批價應用,批價應用按用戶關聯分組取模分發給實時優惠應用,實時優惠應用按用戶取模分發給提醒應用。
采預應用、批價應用、提醒應用跨主機遠程訪問分布式MDB集群的客戶資料。實時優惠應用每個應用容器部署一套MDB本地高速緩存,用于預加載客戶資料,實時優惠應用訪問應用容器內的本地高速緩存中的客戶資料。
這樣的部署架構粗看沒有問題,但是仔細分析后,存在三個致命的問題:客戶資料訪問問題、累積量扣減鎖沖突問題和MQ流量壓力問題。
1)對于采預應用、批價應用和提醒應用,由于都是跨主機遠程訪問分布式MDB集群的客戶資料,網絡交互耗時占比特別高。以批價應用為例,處理一條話單總耗時大概是10毫秒,其中查找客戶資料耗時占了7毫秒(需要查找多張表,且一張表需要查找多次),查找客戶資料的網絡交互耗時占了5毫秒。
2)對于實時優惠應用,雖然預加載客戶資料到本地高速緩存,但是由于每個應用容器都需要加載一份客戶資料,內存占用巨大,導致只能加載有限的客戶資料。
1)對于套餐共享累積量,一個套餐有多個用戶,不同用戶的話單如果在批價環節多進程并發處理,會導致不同進程同時扣減同一條累積量,導致批價扣減累積量的mdb鎖沖突,嚴重影響批價的并發處理性能。
2)由于采預應用給批價應用是按用戶取模分發的,所以對于共享套餐用戶話單,在批價環節并發處理的概率還是比較高的,特別是話單積壓場景下,這種并發沖突尤其嚴重。
1)計費流程環節間采用消息中間件MQ進行話單流轉,每個環節需要輸出話單到MQ,同時需要輸出上傳集團的信息點記錄到MQ,這兩塊對MQ的壓力都是巨大的。
2)根據某省準生產環境實際壓力測試數據,各應用主機占用網絡帶寬分別如下:采預應用主機為12Gb/s,批價應用主機為18Gb/s,實時優惠應用主機為17Gb/s,提醒應用主機為3Gb/s,各應用主機爭搶網絡帶寬資源,導致所有應用并發時,總體性能上不去。
新一代的計費業務流程基本上繼承了計費專業的傳統業務流程,主要如下:


1、當前的提醒流程,提醒應用通過合帳應用觸發,并在提醒應用內部再更新一份累積量數據。
2、這種方式可以提高提醒應用的獨立性,但是同時帶來了一些比較明顯的缺陷,主要如下:
由于提醒應用單獨維護的一份累積量數據,這份數據和批價應用產生的累積量數據由于時間差的原因,可能不完全一致。同時提醒應用單獨維護一份累積量數據,對提醒應用的存儲資源和應用性能也造成了一定的負面影響。
由于帳戶優惠并入合帳中進行實時優惠處理,導致對于大帳戶優惠用戶,流量提醒端到端總時長大大加長,無法達到集團1分鐘提醒的要求。
由于批價環節引入了產品累積量的應用邏輯,導致合帳應用通知提醒應用的消息量暴增,是正常話單量的3倍,提醒應用的性能處理壓力是批價的3倍。
合帳應用處理限額哈希時,代碼邏輯存在如下問題:申請5000條固定大小的哈希,按哈希大小循環遍歷哈希,反復對無效數據進行內存清理,導致合帳CPU消耗特別高,占用大量CPU資源,同時跟批價競爭CPU資源,嚴重影響批價性能。
想要提升計費話單處理能力,則必須針對性的解決以上的部署架構問題、業務流程問題和應用邏輯問題。至此,性能問題的原因也逐漸清晰。
想要解決部署架構問題,重點是解決客戶資料訪問問題、累積量扣減鎖沖突問題、MQ流量壓力問題。
通過Daemonset容器高速緩存,解決客戶資料訪問問題
計費應用在業務處理過程中,經常需要訪問客戶資料,如產品實例、銷售品實例等。這些客戶資料數據量非常大,放在MDB中供業務應用查詢。
MDB作為獨立的服務集群,和業務應用集群部署在不同的主機上,跨主機的網絡時延對資料的高頻訪問性能影響較大。但是,如果每個應用容器都部署一套MDB本地高速緩存,內存占用巨大,導致只能加載有限的客戶資料。
如果我們在每個業務應用主機單獨部署一個Daemonset容器,用于部署MDB高速緩存,業務應用支持跨容器訪問同主機共享內存中的客戶資料,這樣既可以避免跨主機訪問客戶資料的網絡耗時大的問題,又可以解決每個容器都部署一套高速緩存的內存占用大的問題。
通過Daemonset容器高速緩存,我們可以保存訪問比較頻繁的幾張表的全省客戶資料數據,業務應用跨容器通過IPC訪問MDB本地高速緩存,從而提高客戶資料查詢效率,降低網絡時延,如下圖所示:

前面我們提到了,應用多進程并發處理存在數據庫鎖沖突,總體性能上不去。以批價為例,目前按用戶維度進行分發,對于套餐共享累積量,不同的批價進程存在并發扣減同一條累積量,此時會導致數據庫鎖沖突,影響批價的總體處理性能。
運營商業務中的用戶不是一個完全獨立的個體,而是存在復雜的業務關聯性,比如通過套餐關聯、帳戶關聯、客戶關聯,這幾種關系甚至可以多層嵌套關聯。如果業務應用的并發沒有基于用戶的業務關聯關系,很容易導致數據庫鎖沖突。
分布式用戶分組技術,可以基于業務規則的動態分析,通過關聯分組算法對用戶進行關聯關系管理。業務應用可以基于用戶關聯關系實現并行處理,且不會引發并發數據庫鎖沖突問題。同時,由于關聯用戶在一個進程處理,如果關聯用戶的當前環節處理完成后,可以直接進入下一個環節,不用等待其它非關聯用戶處理完成,整個計費流程可以實現橫向擴展。
通過分布式用戶分組技術將客戶資料進行拆解細分之后,批價、實時優惠、提醒等應用按分布式用戶分組進行話單分發,如下圖所示:

批價、實時優惠、提醒等業務應用按用戶關聯分組進行話單事件分發,不同的進程實例處理不同的關聯分組用戶話單,同一個關聯分組用戶話單只會分發給一個應用進程實例處理,所以不同應用進程實例之間處理的話單就不再有關聯關系,也就不會再有數據庫操作的鎖沖突,并發處理性能可以得到極大的提升。
MQ壓縮技術,即對環節間交互的話單事件批量打包后,采用zlib庫壓縮數據后寫入MQ,可壓縮到原始數據的1/10~1/20,詳細如下圖:

這里MQ壓縮的效果主要取決于批量話單打包的效果,如果只有少量的話單事件打包成一個消息包,則MQ的壓縮效果就會比較差;反之,如果較多的話單事件打包成一個消息包,則MQ的壓縮效果就會比較好。
計費操作MQ的網絡流量主要來自兩個方面,一方面是計費流程的環節間交互話單通過MQ進行流轉,另一方面是計費流程需要吐出話單級信息點上傳集團。
(一)首先,我們來看計費流程的環節間交互話單。實際上計費流程每個環節都是批量話單處理的,如果能保證從MQ中的一個消息隊列獲取一批話單事件,業務處理完成后分發給下游環節時,還是分發到同一個消息隊列,則此時這批話單事件將會打包成同一個消息包,那么這個消息包包含的話單事件將會最多,MQ壓縮的效果將會達到最佳;反之,如果從一個消息隊列獲取的一批話單事件,被打散分發到下游環節的多個消息隊列,則這批話單事件將會打包成多個消息包,那么每個消息包包含的話單事件將會比較少,MQ的壓縮效果也會比較差。
所以我們想要獲得最佳的MQ壓縮效果,需要盡可能保證上下游環節的分發規則保持一致,則可確保從消息隊列獲取的一批話單事件,給下游環節分發時,不會被打散分發到多個消息隊列。
(二)其次,我們來看計費流程需要吐出的話單級信息點給MQ帶來的網絡流量壓力。這里的話單級信息點是所有環節都需要輸出的,而每個信息點本身的記錄長度比較小,但是信息點記錄數和話單數本身是一樣多的,所以如果壓縮效果不好的話,產生的網絡流量將是很可怕的。
這里的話單級信息點是為了生成文件上傳集團的,是由計費流程各業務應用模塊分發給信息點文件生成模塊的,對于分發規則本身沒有特別要求,原來是按話單標識分發的。按話單標識分發均衡性沒有問題,但是會導致從計費流程各應用模塊的一個消息隊列獲取的一批話單事件,會被打散分發到信息點文件生成模塊的所有消息隊列,就會導致一個消息包包含的話單事件很少,MQ的壓縮效果大打折扣。
為了提高MQ壓縮效果,我們調整了計費流程各業務應用模塊給信息點文件生成模塊的分發規則,改為按業務應用的應用實例標識分發,這樣子從計費流程各應用模塊的一個消息隊列獲取的一批話單事件,就會分發到信息點文件生成模塊的一個消息隊列中,從而保證這一批話單事件生成的信息點記錄打包成一個消息包,提升MQ的壓縮效果,極大的降低了MQ網絡流量壓力。
首先,我們回顧下前面提到的業務流程問題:
1)由于提醒應用單獨維護的一份累積量數據,這份數據和批價產生的累積量數據由于時間差的原因,可能不完全一致。同時提醒應用單獨維護一份累積量數據,對提醒應用的存儲資源和應用性能也造成了一定的負面影響。
2) 由于帳戶優惠并入合帳中進行實時優惠處理,導致對于大帳戶優惠用戶,流量提醒端到端總時長大大加長,無法達到集團1分鐘提醒的要求。
為了解決以上兩個問題,我們需要打通批價應用到提醒應用的流程,減少消息中轉流程,避免額外的累積量數據冗余,保證計費系統內部各模塊使用的累積量數據的一致性,從而提高整個提醒流程的處理效率,降低硬件資源的消耗。
詳細方案如下圖:

原來由合帳應用通知提醒應用,調整為由批價應用直接通知提醒應用,減少流量提醒途經環節數,提高提醒及時性。
原來提醒應用需要自己再更新一份累積量數據,現在直接使用批價的累積量數據進行提醒判斷,減少資源消耗,提升提醒應用處理性能。
應用邏輯問題主要如下:
由于批價環節引入了產品累積量的應用邏輯,導致合帳應用通知提醒應用的消息量暴增,是正常話單量的3倍,提醒應用的性能處理壓力是批價的3倍。
合帳處理限額哈希時,代碼邏輯按固定哈希大小刪除無效數據的問題,導致合帳CPU消耗特別高,占用大量CPU資源,同時跟批價競爭CPU資源,嚴重影響批價性能。
首先,針對提醒應用消息暴增問題,我們通過對通知提醒應用的話單事件按銷售品實例、累積量類型和用戶的維度進行合并,來降低提醒應用的實際處理話單量,從而解決提醒應用消息量暴增帶來的性能壓力;
其次,針對合帳CPU高問題,我們通過刪除一些不必要的處理邏輯來降低合帳的CPU消耗,即增加判斷邏輯,如果是無效數據,則不需要執行刪除操作。
除了以上兩點業務邏輯優化外,我們還針對每個業務模塊進行了分析,做了很多零散的改造優化,應用邏輯優化可以歸納為以下幾個策略:
應用緩存:通過緩存資料、量本等數據,減少應用遠程訪問MDB和數據庫次數。
邏輯優化:通過廢棄冗余邏輯,優化SQL語法、減少零費用話單處理等邏輯優化提升性能。
話單歸并:通過對批次內同樣銷售品實例、用戶和累積量類型的話單事件進行合并處理,減少提醒應用觸發量。
經過前面幾個性能問題的解決,計費話單處理能力得到了一個質的飛躍,不僅突破了原來的性能天花板,而且達到了20萬條話單/秒的高性能,這個性能遠超集團對于中等省份12萬條話單/秒的要求。
以下是在某省準生產環境實際壓測的性能數據:

從以上數據可以看出,除了清單入庫外,其他業務應用模塊均已經達到甚至超過了20萬條話單/秒的性能,清單入庫主要由于數據庫本身對于自增系列的處理性能達不到20萬條話單/秒的要求。
隨后,在其他項目的優化過程中,我們進一步對清單入庫進行了優化,把自增序列改造為業務應用自己獲取,不依賴于數據庫的自增序列,清單入庫性能從原來單進程500條話單/秒,提升至2000條話單/秒,性能提升4倍,總體性能遠超20萬條話單/秒。
性能問題持續永恒,性能優化永無止境。