淡 嘉,鄭 昊,徐 誠,宋雯雯
(四川省氣象服務(wù)中心,四川 成都 610072)
四川省氣象預(yù)警決策發(fā)布系統(tǒng)建于2013年,承擔(dān)全省黨政決策用戶和運(yùn)營商定制用戶的預(yù)警短信發(fā)布功能。系統(tǒng)在設(shè)計(jì)之初,采用傳統(tǒng)架構(gòu),沒有考慮負(fù)載均衡能力的建設(shè)。隨著2020年系統(tǒng)推廣至全省150余個(gè)市縣級(jí)氣象局,短信發(fā)布規(guī)模進(jìn)一步擴(kuò)大,其中黨政決策用戶增加到30萬,運(yùn)營商定制用戶穩(wěn)定在280萬。發(fā)布統(tǒng)計(jì)方面,系統(tǒng)在2018、2019、2020年分別發(fā)布預(yù)警短信6.3億、4億、5.4億條,3 a累積覆蓋決策用戶6.7億人次。
近年來,在汛期預(yù)警多發(fā)時(shí)期,大量的預(yù)警發(fā)布任務(wù)同時(shí)創(chuàng)建,高并發(fā)導(dǎo)致系統(tǒng)網(wǎng)站時(shí)常崩潰,數(shù)據(jù)庫阻塞導(dǎo)致性能下降,網(wǎng)關(guān)模塊大量待發(fā)任務(wù)堆積,嚴(yán)重影響預(yù)警短信的正常及時(shí)發(fā)布,應(yīng)急狀態(tài)下只能切換任務(wù)至備機(jī)系統(tǒng)釋放壓力,給值班工作帶來巨大挑戰(zhàn)。
白龍湖沉船、東方之星客船傾覆等重大事故提醒著全國氣象預(yù)警工作者責(zé)任之大、任務(wù)之重,作為預(yù)警的傳播通道,發(fā)布系統(tǒng)的高效穩(wěn)定對(duì)四川省氣象預(yù)警工作的開展具有重大的意義。
四川省氣象預(yù)警決策發(fā)布系統(tǒng)于2019年起進(jìn)行改造升級(jí),除網(wǎng)絡(luò)安全等相關(guān)升級(jí)外,本文介紹軟件層面的模塊重新設(shè)計(jì)思路,著重解決系統(tǒng)網(wǎng)站崩潰、數(shù)據(jù)庫讀取壓力大、網(wǎng)關(guān)發(fā)送任務(wù)堆積這3大問題,保障預(yù)警發(fā)布工作穩(wěn)定高效開展。
四川省氣象預(yù)警決策發(fā)布系統(tǒng)采用B/S架構(gòu),數(shù)據(jù)層部署SQL Server 2012版本數(shù)據(jù)庫,存儲(chǔ)決策用戶信息、發(fā)布內(nèi)容、狀態(tài)報(bào)告及系統(tǒng)日志等。應(yīng)用層部署Tomcat容器、運(yùn)行系統(tǒng)網(wǎng)站,供預(yù)警發(fā)布工作人員錄入預(yù)警任務(wù)、編輯決策用戶信息和查看發(fā)送記錄統(tǒng)計(jì)等。網(wǎng)關(guān)接入層對(duì)接運(yùn)營商短信網(wǎng)關(guān),通過模塊化組件提供發(fā)送預(yù)警任務(wù)、收集狀態(tài)報(bào)告、實(shí)現(xiàn)預(yù)警任務(wù)緩存等功能,系統(tǒng)架構(gòu)如圖1所示。
圖1 四川省氣象預(yù)警決策發(fā)布系統(tǒng)基礎(chǔ)架構(gòu)Fig.1 Infrastructure of Sichuan meteorological early warning and decision-making publishing system
從發(fā)布任務(wù)的時(shí)間分布角度分析,四川省氣象預(yù)警集中在汛期,以暴雨為主,預(yù)警任務(wù)的發(fā)布數(shù)量呈現(xiàn)“兩頭低中間高”的分布。系統(tǒng)在每年的5—9月處于負(fù)載高峰,面臨高并發(fā)的預(yù)警任務(wù)創(chuàng)建及發(fā)送。如2018年7月8日區(qū)域性的暴雨過程,全省大部分市縣在08時(shí)20分左右,集中提交預(yù)警發(fā)布任務(wù)307條,覆蓋超過300萬短信用戶。
從系統(tǒng)業(yè)務(wù)邏輯角度分析,如圖2所示,預(yù)警發(fā)布人員登錄網(wǎng)站頁面錄入預(yù)警任務(wù),審核提交后,網(wǎng)站后端直接訪問SQL Server數(shù)據(jù)庫提取待發(fā)布號(hào)碼,并創(chuàng)建發(fā)布任務(wù),存放在網(wǎng)關(guān)模塊的文件緩存中,網(wǎng)關(guān)模塊實(shí)時(shí)抓取緩存發(fā)送至運(yùn)營商網(wǎng)關(guān),同時(shí)新開線程監(jiān)聽狀態(tài)報(bào)告回執(zhí)并寫回?cái)?shù)據(jù)庫。
圖2 四川省氣象預(yù)警決策發(fā)布系統(tǒng)業(yè)務(wù)邏輯(升級(jí)前)Fig.2 Business logic of Sichuan meteorological early warning and decision-making publishing system (Before upgrade)
這樣的業(yè)務(wù)邏輯存在3個(gè)問題:①只有1個(gè)Tomcat容器,當(dāng)網(wǎng)站因?yàn)楦卟l(fā)等原因崩潰時(shí),預(yù)警發(fā)布人員無法及時(shí)登錄系統(tǒng)發(fā)布預(yù)警。②結(jié)合系統(tǒng)業(yè)務(wù)邏輯圖分析流量高峰時(shí)的情況,當(dāng)大量創(chuàng)建發(fā)布任務(wù)后,數(shù)據(jù)庫中用戶號(hào)碼表被頻繁讀取,百萬行數(shù)據(jù)短時(shí)間內(nèi)多次封裝輸出,而傳統(tǒng)數(shù)據(jù)庫面臨高并發(fā)時(shí)性能下降,導(dǎo)致輸出效率下降。實(shí)際應(yīng)用中,即使采用索引、分表優(yōu)化等措施,仍不可避免出現(xiàn)性能問題,問題根源在于傳統(tǒng)數(shù)據(jù)庫模式無法應(yīng)對(duì)高并發(fā)。③同樣是流量高峰的狀況下,大量待發(fā)任務(wù)堆積在網(wǎng)關(guān)模塊,因?yàn)槭褂梦募彺?,磁盤I/O效率持續(xù)變低,影響發(fā)布效率,嚴(yán)重時(shí)模塊崩潰,讀取在內(nèi)存中的部分任務(wù)會(huì)丟失,造成漏發(fā)。
升級(jí)后的系統(tǒng)業(yè)務(wù)邏輯如圖3所示,系統(tǒng)基礎(chǔ)架構(gòu)保持不變,增加了3層架構(gòu)中的業(yè)務(wù)模塊,調(diào)整了主要業(yè)務(wù)邏輯。
圖3 四川省氣象預(yù)警決策發(fā)布系統(tǒng)業(yè)務(wù)邏輯(升級(jí)后)Fig.3 Business logic of Sichuan meteorological early warning and decision-making publishing system (After upgrade)
針對(duì)之前業(yè)務(wù)邏輯中存在的3個(gè)問題,這次升級(jí)方案是:①在應(yīng)用層通過Nginx反向代理[1-4],3個(gè)Tomcat容器并行負(fù)載。②在數(shù)據(jù)層增加Redis用戶緩存作為中間層[5-7],創(chuàng)建任務(wù)請(qǐng)求不直接訪問數(shù)據(jù)庫。③在數(shù)據(jù)層和網(wǎng)關(guān)接入層通過消息隊(duì)列(RabbitMQ)管理并持久化任務(wù)列表[8-9],并在網(wǎng)關(guān)接入層增加到3個(gè)發(fā)送網(wǎng)關(guān)模塊對(duì)接運(yùn)營商短信網(wǎng)關(guān),發(fā)送網(wǎng)關(guān)中采用Redis任務(wù)緩存替代磁盤文件緩存。
下面分別從網(wǎng)站應(yīng)用層、數(shù)據(jù)層、網(wǎng)關(guān)接入層3方面詳細(xì)介紹系統(tǒng)負(fù)載均衡策略及性能優(yōu)化的實(shí)現(xiàn)[10-15]。
在網(wǎng)站應(yīng)用層進(jìn)行負(fù)載均衡優(yōu)化是為了解決因?yàn)楦卟l(fā)等原因?qū)е碌木W(wǎng)站崩潰問題,此次升級(jí)中,共部署3個(gè)Tomcat容器,獨(dú)立運(yùn)行網(wǎng)站,同時(shí)在前端設(shè)置Nginx服務(wù)實(shí)現(xiàn)Web層的負(fù)載均衡。這一過程通過反向代理來實(shí)現(xiàn),Nginx作為代理服務(wù)器,接受來自多個(gè)客戶端的請(qǐng)求,隨后將請(qǐng)求按照既定策略轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)中不同的服務(wù)應(yīng)用,同時(shí)將請(qǐng)求結(jié)果返回到客戶端。即使其中一個(gè)Web應(yīng)用崩潰,訪問請(qǐng)求也會(huì)被指向到剩余的其它Web應(yīng)用中。這里Nginx服務(wù)采用的負(fù)載均衡策略是輪詢發(fā)送,目標(biāo)IP的權(quán)重為1,最大連接失敗數(shù)為3,連接失敗時(shí)間為65 s。
請(qǐng)求會(huì)按照順序發(fā)送至3個(gè)Web應(yīng)用中進(jìn)行處理,預(yù)警錄入人員只需要訪問網(wǎng)站域名,無需關(guān)心IP、端口情況。當(dāng)某個(gè)應(yīng)用IP在65 s內(nèi)出現(xiàn)連接失敗3次,請(qǐng)求會(huì)被分配至其它IP,并且在接下來的65 s內(nèi)不會(huì)再次請(qǐng)求失敗的IP。Nginx反向代理服務(wù)的邏輯流程圖如圖4所示。
圖4 Nginx反向代理Fig.4 Reverse proxy by Nginx
系統(tǒng)升級(jí)前,Web應(yīng)用直接訪問數(shù)據(jù)庫生成發(fā)布任務(wù)。根據(jù)現(xiàn)代互聯(lián)網(wǎng)應(yīng)用的設(shè)計(jì)指南,直接高并發(fā)讀取數(shù)據(jù)庫會(huì)造成嚴(yán)重的性能問題。因此在升級(jí)設(shè)計(jì)中,增加了Redis緩存服務(wù)作為數(shù)據(jù)中間件。Redis作為K-V結(jié)構(gòu)的NoSQL數(shù)據(jù)庫,運(yùn)行在內(nèi)存中,采用多路復(fù)用I/O阻塞機(jī)制,讀取速度較傳統(tǒng)數(shù)據(jù)庫更快,針對(duì)高并發(fā)的支持更加穩(wěn)定。其次新增消息隊(duì)列和任務(wù)調(diào)度模塊,保障任務(wù)請(qǐng)求的順序執(zhí)行和本地持久化。
在Redis服務(wù)前增加任務(wù)請(qǐng)求隊(duì)列,預(yù)警發(fā)布人員在Web應(yīng)用中錄入發(fā)布任務(wù),任務(wù)會(huì)以消息對(duì)象的形式進(jìn)入請(qǐng)求隊(duì)列等待任務(wù)調(diào)度模塊處理。在這一步引入消息隊(duì)列主要基于3點(diǎn)考慮:①實(shí)現(xiàn)Web應(yīng)用層和數(shù)據(jù)層的解耦,方便維護(hù)和擴(kuò)展。②利用消息隊(duì)列中本地持久化特性,即使系統(tǒng)崩潰,已經(jīng)生成的發(fā)布任務(wù)也會(huì)緩存在本地磁盤,系統(tǒng)恢復(fù)時(shí)會(huì)自動(dòng)重新調(diào)度數(shù)據(jù)進(jìn)入隊(duì)列,構(gòu)成預(yù)警不漏發(fā)的第一道防線。③請(qǐng)求消息隊(duì)列采用公平分配策略,即同一個(gè)任務(wù)接收者,在任務(wù)處理完畢之前,不會(huì)接收到第2個(gè)任務(wù)分配,保證不會(huì)因?yàn)榉峙洳痪鶎?dǎo)致的任務(wù)堆積。
新增的任務(wù)調(diào)度模塊采用多線程設(shè)計(jì),T1~Tn線程同時(shí)處理來自請(qǐng)求隊(duì)列的多個(gè)任務(wù),而限定線程的數(shù)量也起到限流的作用,減輕數(shù)據(jù)層壓力。以單個(gè)線程為例,T1線程在接收到第1個(gè)任務(wù)后,訪問Redis用戶緩存提取手機(jī)號(hào)碼,并結(jié)合預(yù)警內(nèi)容生成待發(fā)布任務(wù),在存入Redis任務(wù)緩存確認(rèn)后,生成發(fā)送任務(wù)對(duì)象,提交到任務(wù)隊(duì)列等待網(wǎng)關(guān)接入層處理。之后T1線程發(fā)送確認(rèn)到請(qǐng)求隊(duì)列,刪除當(dāng)前任務(wù),并準(zhǔn)備接收下一組任務(wù)。任務(wù)調(diào)度模塊及請(qǐng)求隊(duì)列詳細(xì)的業(yè)務(wù)邏輯如圖5所示。
圖5 任務(wù)調(diào)度模塊及消息隊(duì)列業(yè)務(wù)邏輯Fig.5 Business logic of task scheduling module and message queue
因?yàn)檫\(yùn)營商短信網(wǎng)關(guān)開放的訪問速度(即短信下發(fā)速度)有限,預(yù)警高峰時(shí)期,發(fā)送任務(wù)在網(wǎng)關(guān)堆積無法避免,所以針對(duì)網(wǎng)關(guān)接入層升級(jí)的重點(diǎn)在于分散單個(gè)網(wǎng)關(guān)的發(fā)送壓力、增加讀取任務(wù)緩存效率、提升網(wǎng)關(guān)模塊緩存的穩(wěn)定性。
首先將負(fù)責(zé)與運(yùn)營商短信網(wǎng)關(guān)交互的發(fā)送網(wǎng)關(guān)增加至3個(gè),模塊間相互獨(dú)立。當(dāng)其中一個(gè)網(wǎng)關(guān)崩潰時(shí),其它兩個(gè)網(wǎng)關(guān)不會(huì)受到影響。其次將任務(wù)緩存的方式從磁盤文件更換成Redis服務(wù),之前方式的弊端在于網(wǎng)關(guān)讀取磁盤文件時(shí),數(shù)據(jù)會(huì)暫存在內(nèi)存中,此時(shí)任何異常中斷,都會(huì)導(dǎo)致內(nèi)存數(shù)據(jù)丟失引起漏發(fā)。升級(jí)后利用Redis本地持久機(jī)制可能保證數(shù)據(jù)的穩(wěn)定,提升整個(gè)接入網(wǎng)關(guān)層的可靠性。同時(shí)在3個(gè)網(wǎng)關(guān)前新增1個(gè)任務(wù)發(fā)送隊(duì)列,即使特殊情況下Redis數(shù)據(jù)緩存完全丟失,仍然可以通過任務(wù)隊(duì)列中的信息,重構(gòu)下發(fā)數(shù)據(jù),這些機(jī)制構(gòu)成預(yù)警不漏發(fā)的第二道防線。此外任務(wù)隊(duì)列的根據(jù)既定策略調(diào)度任務(wù),調(diào)整3個(gè)網(wǎng)關(guān)的流量,自動(dòng)分散壓力,降低網(wǎng)關(guān)因任務(wù)堆積而崩潰的可能性。網(wǎng)關(guān)接入層業(yè)務(wù)邏輯如圖6所示。
圖6 網(wǎng)關(guān)接入層業(yè)務(wù)邏輯Fig.6 Business logic of gateway access layer
在數(shù)據(jù)層經(jīng)過任務(wù)調(diào)度模塊的處理后,待發(fā)送的數(shù)據(jù)進(jìn)入Redis任務(wù)緩存,同時(shí)任務(wù)隊(duì)列在得到緩存確認(rèn)后,通知3個(gè)發(fā)送網(wǎng)關(guān)開始對(duì)接運(yùn)營商網(wǎng)關(guān)進(jìn)行下發(fā)。以單次任務(wù)下發(fā)為例,任務(wù)隊(duì)列首先確認(rèn)發(fā)送網(wǎng)關(guān)A的狀態(tài):①如果空閑,網(wǎng)關(guān)A會(huì)接收到第1個(gè)任務(wù)a,根據(jù)內(nèi)容在Redis任務(wù)緩存中提取需要下發(fā)的內(nèi)容,同時(shí)對(duì)接運(yùn)營商短信網(wǎng)關(guān)進(jìn)行下發(fā)。待下發(fā)完成后,確認(rèn)任務(wù)a并通知任務(wù)隊(duì)列將其刪除。②如果忙碌,任務(wù)隊(duì)列會(huì)依次確認(rèn)下一個(gè)發(fā)送網(wǎng)關(guān)的狀態(tài)。同理,如果網(wǎng)關(guān)A在下發(fā)任務(wù)a的過程中異常中斷,任務(wù)a沒有得到確認(rèn),任務(wù)隊(duì)列會(huì)分配任務(wù)a到下一個(gè)網(wǎng)關(guān)進(jìn)行處理。
發(fā)送網(wǎng)關(guān)與任務(wù)隊(duì)列的業(yè)務(wù)流程如圖7所示。
圖7 發(fā)送網(wǎng)關(guān)與任務(wù)隊(duì)列業(yè)務(wù)流程Fig.7 Business process of gateway and message queue
性能測(cè)試以同時(shí)提交500個(gè)任務(wù),平均每個(gè)任務(wù)包含6 000個(gè)決策號(hào)碼,共計(jì)300萬下發(fā)為例,與實(shí)際應(yīng)用不同,測(cè)試數(shù)據(jù)不對(duì)接運(yùn)營商網(wǎng)關(guān)。連續(xù)測(cè)試10次,基于同一套服務(wù)器配置,分別對(duì)比系統(tǒng)升級(jí)前后,單個(gè)任務(wù)創(chuàng)建完成平均耗時(shí)a和網(wǎng)關(guān)提取單個(gè)任務(wù)的平均耗時(shí)b,其中測(cè)試a主要指請(qǐng)求決策用戶信息構(gòu)建下發(fā)數(shù)據(jù),到網(wǎng)關(guān)緩存完畢這段耗時(shí),測(cè)試b考慮下發(fā)網(wǎng)關(guān)讀取任務(wù)緩存的耗時(shí)。
從測(cè)試結(jié)果(如圖8)可以看出,測(cè)試項(xiàng)目a中,升級(jí)前平均耗時(shí)2 370 ms,升級(jí)后為276 ms,可以清晰的看出,得益于Redis的內(nèi)存緩存機(jī)制,數(shù)據(jù)讀取效率極大提升。測(cè)試項(xiàng)目b中,升級(jí)前平均耗時(shí)277 ms,而升級(jí)后僅耗時(shí)79 ms。
圖8測(cè)試項(xiàng)目耗時(shí)對(duì)比Fig.8 Time comparison of test items
負(fù)載均衡方面,分析2020年7月的實(shí)際業(yè)務(wù)統(tǒng)計(jì)數(shù)據(jù),當(dāng)月共創(chuàng)建下發(fā)任務(wù)57 634次,發(fā)布預(yù)警決策短信近1億條,3個(gè)下發(fā)網(wǎng)關(guān)的負(fù)載情況如表1所示,之所以網(wǎng)關(guān)A負(fù)載更大,是因?yàn)樵诜歉叻逑掳l(fā)時(shí)段,任務(wù)會(huì)按照順序,優(yōu)先分配給網(wǎng)關(guān)A。當(dāng)多個(gè)任務(wù)同時(shí)進(jìn)入隊(duì)列時(shí),才會(huì)均勻負(fù)載到其它網(wǎng)關(guān)。
表1 3網(wǎng)關(guān)在2020年7月實(shí)際下發(fā)中的負(fù)載情況Tab.1 Actual load of three gateways in July 2020
四川省氣象預(yù)警決策發(fā)布系統(tǒng)在完成負(fù)載均衡和性能優(yōu)化后,提高了網(wǎng)站容錯(cuò)率、數(shù)據(jù)庫及網(wǎng)關(guān)的性能得到極大提升,同時(shí)系統(tǒng)穩(wěn)定性也在實(shí)際應(yīng)用得到驗(yàn)證,2020年沒有出現(xiàn)因?yàn)橄到y(tǒng)原因?qū)е碌臉I(yè)務(wù)中斷,保障了預(yù)警決策短信下發(fā)工作順利開展。
四川省氣象預(yù)警決策發(fā)布系統(tǒng)此次升級(jí),并沒有采用更加完善的數(shù)據(jù)庫集群和硬件級(jí)別的負(fù)載方案,數(shù)據(jù)同步機(jī)制也不夠及時(shí),如果負(fù)載進(jìn)一步提升,系統(tǒng)仍將面臨挑戰(zhàn)。