淡 嘉,鄭 昊,徐 誠,宋雯雯
(四川省氣象服務中心,四川 成都 610072)
四川省氣象預警決策發布系統建于2013年,承擔全省黨政決策用戶和運營商定制用戶的預警短信發布功能。系統在設計之初,采用傳統架構,沒有考慮負載均衡能力的建設。隨著2020年系統推廣至全省150余個市縣級氣象局,短信發布規模進一步擴大,其中黨政決策用戶增加到30萬,運營商定制用戶穩定在280萬。發布統計方面,系統在2018、2019、2020年分別發布預警短信6.3億、4億、5.4億條,3 a累積覆蓋決策用戶6.7億人次。
近年來,在汛期預警多發時期,大量的預警發布任務同時創建,高并發導致系統網站時常崩潰,數據庫阻塞導致性能下降,網關模塊大量待發任務堆積,嚴重影響預警短信的正常及時發布,應急狀態下只能切換任務至備機系統釋放壓力,給值班工作帶來巨大挑戰。
白龍湖沉船、東方之星客船傾覆等重大事故提醒著全國氣象預警工作者責任之大、任務之重,作為預警的傳播通道,發布系統的高效穩定對四川省氣象預警工作的開展具有重大的意義。
四川省氣象預警決策發布系統于2019年起進行改造升級,除網絡安全等相關升級外,本文介紹軟件層面的模塊重新設計思路,著重解決系統網站崩潰、數據庫讀取壓力大、網關發送任務堆積這3大問題,保障預警發布工作穩定高效開展。
四川省氣象預警決策發布系統采用B/S架構,數據層部署SQL Server 2012版本數據庫,存儲決策用戶信息、發布內容、狀態報告及系統日志等。應用層部署Tomcat容器、運行系統網站,供預警發布工作人員錄入預警任務、編輯決策用戶信息和查看發送記錄統計等。網關接入層對接運營商短信網關,通過模塊化組件提供發送預警任務、收集狀態報告、實現預警任務緩存等功能,系統架構如圖1所示。

圖1 四川省氣象預警決策發布系統基礎架構Fig.1 Infrastructure of Sichuan meteorological early warning and decision-making publishing system
從發布任務的時間分布角度分析,四川省氣象預警集中在汛期,以暴雨為主,預警任務的發布數量呈現“兩頭低中間高”的分布。系統在每年的5—9月處于負載高峰,面臨高并發的預警任務創建及發送。如2018年7月8日區域性的暴雨過程,全省大部分市縣在08時20分左右,集中提交預警發布任務307條,覆蓋超過300萬短信用戶。
從系統業務邏輯角度分析,如圖2所示,預警發布人員登錄網站頁面錄入預警任務,審核提交后,網站后端直接訪問SQL Server數據庫提取待發布號碼,并創建發布任務,存放在網關模塊的文件緩存中,網關模塊實時抓取緩存發送至運營商網關,同時新開線程監聽狀態報告回執并寫回數據庫。

圖2 四川省氣象預警決策發布系統業務邏輯(升級前)Fig.2 Business logic of Sichuan meteorological early warning and decision-making publishing system (Before upgrade)
這樣的業務邏輯存在3個問題:①只有1個Tomcat容器,當網站因為高并發等原因崩潰時,預警發布人員無法及時登錄系統發布預警。②結合系統業務邏輯圖分析流量高峰時的情況,當大量創建發布任務后,數據庫中用戶號碼表被頻繁讀取,百萬行數據短時間內多次封裝輸出,而傳統數據庫面臨高并發時性能下降,導致輸出效率下降。實際應用中,即使采用索引、分表優化等措施,仍不可避免出現性能問題,問題根源在于傳統數據庫模式無法應對高并發。③同樣是流量高峰的狀況下,大量待發任務堆積在網關模塊,因為使用文件緩存,磁盤I/O效率持續變低,影響發布效率,嚴重時模塊崩潰,讀取在內存中的部分任務會丟失,造成漏發。
升級后的系統業務邏輯如圖3所示,系統基礎架構保持不變,增加了3層架構中的業務模塊,調整了主要業務邏輯。

圖3 四川省氣象預警決策發布系統業務邏輯(升級后)Fig.3 Business logic of Sichuan meteorological early warning and decision-making publishing system (After upgrade)
針對之前業務邏輯中存在的3個問題,這次升級方案是:①在應用層通過Nginx反向代理[1-4],3個Tomcat容器并行負載。②在數據層增加Redis用戶緩存作為中間層[5-7],創建任務請求不直接訪問數據庫。③在數據層和網關接入層通過消息隊列(RabbitMQ)管理并持久化任務列表[8-9],并在網關接入層增加到3個發送網關模塊對接運營商短信網關,發送網關中采用Redis任務緩存替代磁盤文件緩存。
下面分別從網站應用層、數據層、網關接入層3方面詳細介紹系統負載均衡策略及性能優化的實現[10-15]。
在網站應用層進行負載均衡優化是為了解決因為高并發等原因導致的網站崩潰問題,此次升級中,共部署3個Tomcat容器,獨立運行網站,同時在前端設置Nginx服務實現Web層的負載均衡。這一過程通過反向代理來實現,Nginx作為代理服務器,接受來自多個客戶端的請求,隨后將請求按照既定策略轉發給內部網絡中不同的服務應用,同時將請求結果返回到客戶端。即使其中一個Web應用崩潰,訪問請求也會被指向到剩余的其它Web應用中。這里Nginx服務采用的負載均衡策略是輪詢發送,目標IP的權重為1,最大連接失敗數為3,連接失敗時間為65 s。
請求會按照順序發送至3個Web應用中進行處理,預警錄入人員只需要訪問網站域名,無需關心IP、端口情況。當某個應用IP在65 s內出現連接失敗3次,請求會被分配至其它IP,并且在接下來的65 s內不會再次請求失敗的IP。Nginx反向代理服務的邏輯流程圖如圖4所示。

圖4 Nginx反向代理Fig.4 Reverse proxy by Nginx
系統升級前,Web應用直接訪問數據庫生成發布任務。根據現代互聯網應用的設計指南,直接高并發讀取數據庫會造成嚴重的性能問題。因此在升級設計中,增加了Redis緩存服務作為數據中間件。Redis作為K-V結構的NoSQL數據庫,運行在內存中,采用多路復用I/O阻塞機制,讀取速度較傳統數據庫更快,針對高并發的支持更加穩定。其次新增消息隊列和任務調度模塊,保障任務請求的順序執行和本地持久化。
在Redis服務前增加任務請求隊列,預警發布人員在Web應用中錄入發布任務,任務會以消息對象的形式進入請求隊列等待任務調度模塊處理。在這一步引入消息隊列主要基于3點考慮:①實現Web應用層和數據層的解耦,方便維護和擴展。②利用消息隊列中本地持久化特性,即使系統崩潰,已經生成的發布任務也會緩存在本地磁盤,系統恢復時會自動重新調度數據進入隊列,構成預警不漏發的第一道防線。③請求消息隊列采用公平分配策略,即同一個任務接收者,在任務處理完畢之前,不會接收到第2個任務分配,保證不會因為分配不均導致的任務堆積。
新增的任務調度模塊采用多線程設計,T1~Tn線程同時處理來自請求隊列的多個任務,而限定線程的數量也起到限流的作用,減輕數據層壓力。以單個線程為例,T1線程在接收到第1個任務后,訪問Redis用戶緩存提取手機號碼,并結合預警內容生成待發布任務,在存入Redis任務緩存確認后,生成發送任務對象,提交到任務隊列等待網關接入層處理。之后T1線程發送確認到請求隊列,刪除當前任務,并準備接收下一組任務。任務調度模塊及請求隊列詳細的業務邏輯如圖5所示。

圖5 任務調度模塊及消息隊列業務邏輯Fig.5 Business logic of task scheduling module and message queue
因為運營商短信網關開放的訪問速度(即短信下發速度)有限,預警高峰時期,發送任務在網關堆積無法避免,所以針對網關接入層升級的重點在于分散單個網關的發送壓力、增加讀取任務緩存效率、提升網關模塊緩存的穩定性。
首先將負責與運營商短信網關交互的發送網關增加至3個,模塊間相互獨立。當其中一個網關崩潰時,其它兩個網關不會受到影響。其次將任務緩存的方式從磁盤文件更換成Redis服務,之前方式的弊端在于網關讀取磁盤文件時,數據會暫存在內存中,此時任何異常中斷,都會導致內存數據丟失引起漏發。升級后利用Redis本地持久機制可能保證數據的穩定,提升整個接入網關層的可靠性。同時在3個網關前新增1個任務發送隊列,即使特殊情況下Redis數據緩存完全丟失,仍然可以通過任務隊列中的信息,重構下發數據,這些機制構成預警不漏發的第二道防線。此外任務隊列的根據既定策略調度任務,調整3個網關的流量,自動分散壓力,降低網關因任務堆積而崩潰的可能性。網關接入層業務邏輯如圖6所示。

圖6 網關接入層業務邏輯Fig.6 Business logic of gateway access layer
在數據層經過任務調度模塊的處理后,待發送的數據進入Redis任務緩存,同時任務隊列在得到緩存確認后,通知3個發送網關開始對接運營商網關進行下發。以單次任務下發為例,任務隊列首先確認發送網關A的狀態:①如果空閑,網關A會接收到第1個任務a,根據內容在Redis任務緩存中提取需要下發的內容,同時對接運營商短信網關進行下發。待下發完成后,確認任務a并通知任務隊列將其刪除。②如果忙碌,任務隊列會依次確認下一個發送網關的狀態。同理,如果網關A在下發任務a的過程中異常中斷,任務a沒有得到確認,任務隊列會分配任務a到下一個網關進行處理。
發送網關與任務隊列的業務流程如圖7所示。

圖7 發送網關與任務隊列業務流程Fig.7 Business process of gateway and message queue
性能測試以同時提交500個任務,平均每個任務包含6 000個決策號碼,共計300萬下發為例,與實際應用不同,測試數據不對接運營商網關。連續測試10次,基于同一套服務器配置,分別對比系統升級前后,單個任務創建完成平均耗時a和網關提取單個任務的平均耗時b,其中測試a主要指請求決策用戶信息構建下發數據,到網關緩存完畢這段耗時,測試b考慮下發網關讀取任務緩存的耗時。
從測試結果(如圖8)可以看出,測試項目a中,升級前平均耗時2 370 ms,升級后為276 ms,可以清晰的看出,得益于Redis的內存緩存機制,數據讀取效率極大提升。測試項目b中,升級前平均耗時277 ms,而升級后僅耗時79 ms。

圖8測試項目耗時對比Fig.8 Time comparison of test items
負載均衡方面,分析2020年7月的實際業務統計數據,當月共創建下發任務57 634次,發布預警決策短信近1億條,3個下發網關的負載情況如表1所示,之所以網關A負載更大,是因為在非高峰下發時段,任務會按照順序,優先分配給網關A。當多個任務同時進入隊列時,才會均勻負載到其它網關。

表1 3網關在2020年7月實際下發中的負載情況Tab.1 Actual load of three gateways in July 2020
四川省氣象預警決策發布系統在完成負載均衡和性能優化后,提高了網站容錯率、數據庫及網關的性能得到極大提升,同時系統穩定性也在實際應用得到驗證,2020年沒有出現因為系統原因導致的業務中斷,保障了預警決策短信下發工作順利開展。
四川省氣象預警決策發布系統此次升級,并沒有采用更加完善的數據庫集群和硬件級別的負載方案,數據同步機制也不夠及時,如果負載進一步提升,系統仍將面臨挑戰。