汪琳
(中國(guó)人民銀行南京分行,南京210004)
中間件是一種運(yùn)行在操作系統(tǒng)、網(wǎng)絡(luò)和數(shù)據(jù)庫(kù)管理系統(tǒng)之上,應(yīng)用軟件之下的軟件,其作用是為上層應(yīng)用軟件提供運(yùn)行支持和開(kāi)發(fā)環(huán)境,幫助用戶靈活、高效地進(jìn)行開(kāi)發(fā)和集成[1]。中間件依據(jù)提供服務(wù)的不同,可分為消息中間件、交易中間件、對(duì)象中間件、數(shù)據(jù)訪問(wèn)中間件以及安全中間件等[2]。隨著信息化的快速發(fā)展,消息中間件逐漸成為用戶的應(yīng)用重點(diǎn),在各類系統(tǒng)中隨處可見(jiàn)其身影[3]。傳統(tǒng)的消息推送中間件基于生產(chǎn)者-消費(fèi)者模式[4],即發(fā)布方首先通過(guò)網(wǎng)絡(luò)傳輸把數(shù)據(jù)寄存到消息隊(duì)列中,等待訂閱方從消息隊(duì)列中獲取數(shù)據(jù),當(dāng)隊(duì)列中的數(shù)據(jù)確認(rèn)被訂閱方獲取后,消息隊(duì)列中的該數(shù)據(jù)就會(huì)被移除。這里,隊(duì)列是數(shù)據(jù)傳輸?shù)摹熬彌_區(qū)”,使用隊(duì)列能實(shí)現(xiàn)交換數(shù)據(jù)的臨時(shí)寄存,支持?jǐn)?shù)據(jù)的即時(shí)或延時(shí)讀取,從而實(shí)現(xiàn)消息的同步或異步傳輸[5-6]。
隨著互聯(lián)網(wǎng)的發(fā)展,各行各業(yè)使用消息中間件進(jìn)行數(shù)據(jù)交換越發(fā)普遍,這對(duì)于深度依賴消息中間件的軟件產(chǎn)品而言,一旦某次消息推送服務(wù)出現(xiàn)異常,在第一時(shí)間精準(zhǔn)定位問(wèn)題并分析異常產(chǎn)生的原因是至關(guān)重要的。因此,對(duì)每一次推送的“消息”進(jìn)行有效的管理和監(jiān)控十分必要。
目前應(yīng)用比較廣泛的消息中間件有Apache的ActiveMQ、IBM的 RocketMQ、BEA的 Tuxedo等,這些消息中間件都有它們自身的特點(diǎn),如在性能、安全性、健壯性、穩(wěn)定性上都比較突出,然而這些消息中間件卻存在著無(wú)法快速定位異常信息、難以快速檢索某次服務(wù)信息以及難以兼容消息通訊雙方使用的不同通訊協(xié)議等問(wèn)題。針對(duì)上述問(wèn)題,本文基于Spring、Hibernate、Dubbo框架以及MySQL和Redis數(shù)據(jù)庫(kù),并以與發(fā)送方通訊協(xié)議異構(gòu)的第三方短信推送接口為例進(jìn)行整合,設(shè)計(jì)了一個(gè)消息中間件原型。
總體架構(gòu)主要分為:控制層、業(yè)務(wù)層和數(shù)據(jù)訪問(wèn)層,如圖1所示。
控制層主要通過(guò)兩種架構(gòu)實(shí)現(xiàn):
(1)Spring MVC 架構(gòu)。通過(guò) Bootstrap、jQuery、HT?ML等前端技術(shù)實(shí)現(xiàn)的Web頁(yè)面和用戶進(jìn)行交互。用戶通過(guò)Web頁(yè)面發(fā)出HTTP的請(qǐng)求首先被Spring Shiro框架實(shí)現(xiàn)的權(quán)限校驗(yàn)攔截器攔截,對(duì)配置文件以及數(shù)據(jù)庫(kù)中用戶信息進(jìn)行權(quán)限驗(yàn)證,如限驗(yàn)證通過(guò),則把HTTP請(qǐng)求發(fā)送給控制層Controller進(jìn)行處理,調(diào)用相應(yīng)的業(yè)務(wù)邏輯層代碼,最后返回結(jié)果給前端Web頁(yè)面。
(2)Dubbo架構(gòu)。外部系統(tǒng)通過(guò)遠(yuǎn)程調(diào)用的方式訪問(wèn)控制層,首先被Dubbo核心攔截,Dubbo核心通過(guò)匹配查找,找到相應(yīng)的控制層類和方法并進(jìn)行調(diào)用。控制層被調(diào)用后會(huì)對(duì)傳參的有效性進(jìn)行校驗(yàn),校驗(yàn)通過(guò)后,控制層調(diào)用業(yè)務(wù)邏輯層生成本次遠(yuǎn)程調(diào)用服務(wù)的唯一標(biāo)識(shí)號(hào),并作為參數(shù)繼續(xù)調(diào)用相應(yīng)業(yè)務(wù)的業(yè)務(wù)邏輯層代碼,最終控制層會(huì)把服務(wù)的簡(jiǎn)單描述結(jié)果以及唯一標(biāo)識(shí)號(hào)返回給外部系統(tǒng)。
業(yè)務(wù)邏輯層負(fù)責(zé)實(shí)現(xiàn)具體業(yè)務(wù)。包括生成每次遠(yuǎn)程調(diào)用服務(wù)唯一標(biāo)識(shí)號(hào)、生成調(diào)用參數(shù)的SHA1簽名、根據(jù)參數(shù)SHA1簽名查詢是否重復(fù)調(diào)用服務(wù)、第三方消息推送業(yè)務(wù)接口調(diào)用的具體邏輯,以及Web頁(yè)面檢索服務(wù)結(jié)果、管理推送服務(wù)的相關(guān)邏輯等。
數(shù)據(jù)訪問(wèn)層使用Hibernate框架將第三方業(yè)務(wù)接口將成功調(diào)用的結(jié)果持久化到數(shù)據(jù)庫(kù)中,而將調(diào)用過(guò)程中出現(xiàn)的異常信息輸出到日志文件。對(duì)于訪問(wèn)比較頻繁、數(shù)據(jù)時(shí)效性髙的熱點(diǎn)數(shù)據(jù),為加快數(shù)據(jù)的訪問(wèn)速度,該層使用Java API對(duì)Redis緩存數(shù)據(jù)庫(kù)中數(shù)據(jù)進(jìn)行存取。
圖1 系統(tǒng)整體架構(gòu)示意圖
對(duì)于消息推送服務(wù)中間件而言,能否兼容收、發(fā)端通訊協(xié)議不一致的情況是衡量中間件適用性的重要方面。本文設(shè)計(jì)的中間件發(fā)送端使用的是Dubbo框架集成的通訊協(xié)議,通過(guò)遠(yuǎn)程調(diào)用使用信息推送服務(wù)中間件服務(wù),接收端選用一個(gè)通訊協(xié)議與發(fā)送端不一致的第三方短信推送接口。該第三方短信接口可以根據(jù)請(qǐng)求參數(shù)的內(nèi)容,動(dòng)態(tài)改變短信模版內(nèi)容,然后發(fā)送給具體手機(jī)號(hào)碼。具體方法為:首先需要在平臺(tái)上預(yù)置短信模版,并賦予每個(gè)模板一個(gè)模版號(hào),將來(lái)作為請(qǐng)求參數(shù),告知服務(wù)器此次服務(wù)選擇的短信模版。短信模版可以設(shè)計(jì)為:“驗(yàn)證碼${code},您正在進(jìn)行${product}身份驗(yàn)證,打死也不要告訴別人哦!”,其中${code}、${product}為模板可變參數(shù),接口調(diào)用者在調(diào)用短信接口時(shí),傳入不同的替換參數(shù)即可實(shí)現(xiàn)發(fā)送短信內(nèi)容的動(dòng)態(tài)變化。
該第三方短信接口明確要求的請(qǐng)求發(fā)送參數(shù)為:
(1)PhoneNumbers:短信接收號(hào)碼,支持以逗號(hào)分隔的形式進(jìn)行批量調(diào)用,批量調(diào)用相對(duì)于單條調(diào)用在及時(shí)性方面稍有延遲,驗(yàn)證碼類型的短信推薦使用單條調(diào)用的方式。
(2)TemplateCode:短信模板號(hào),傳入的模板必須是在第三方平臺(tái)中預(yù)置的可用模板。
(3)TemplateParam:短信模板變量,傳參規(guī)則為{“key”:”value”}鍵-值對(duì),key的名字須和申請(qǐng)模板中的變量名保持一致,多個(gè)變量之間以逗號(hào)隔開(kāi)。如:針對(duì)模板“驗(yàn)證碼${code},您正在進(jìn)行${product}身份驗(yàn)證,打死也不要告訴別人哦!”,傳參時(shí)需傳入{"code":"1234","product":"alidayu"}
第三方短信接口返回的響應(yīng)參數(shù)為:
(1)RequestId:請(qǐng)求 ID。
(2)Code:返回結(jié)果。
(3)Message:狀態(tài)碼的描述。
(4)BizId:發(fā)送回執(zhí)ID,可根據(jù)該ID可查詢具體的發(fā)送狀態(tài)。
在信息推送服務(wù)中間件的服務(wù)周期中,不能保證每次服務(wù)都能正常執(zhí)行,當(dāng)出現(xiàn)異常時(shí),信息推送服務(wù)中間件的使用者重點(diǎn)關(guān)心的是異常描述,而在大量的日志記錄中,開(kāi)發(fā)者想要快速定位到對(duì)應(yīng)本次服務(wù)的異常信息,則需要給每一個(gè)異常信息加入一個(gè)可返回給調(diào)用端的唯一標(biāo)識(shí)號(hào)。如果消息推送成功完成,用戶若要從數(shù)據(jù)庫(kù)中快速檢索服務(wù)結(jié)果,也需要加入唯一的標(biāo)識(shí)號(hào)。唯一標(biāo)識(shí)號(hào)將與本次服務(wù)相關(guān)聯(lián),并加入到本次服務(wù)產(chǎn)生的異常信息或服務(wù)結(jié)果中,最終返回給外部系統(tǒng)以供查詢。
唯一標(biāo)識(shí)號(hào)的生成需要解決兩個(gè)問(wèn)題:
(1)在多線程髙并發(fā)環(huán)境中,避免生成同樣的標(biāo)識(shí)號(hào)。
(2)在信息推送服務(wù)中間件集群部署運(yùn)行中,避免生成同樣的標(biāo)識(shí)號(hào)。
對(duì)于第一個(gè)問(wèn)題,可使用Java原子類實(shí)現(xiàn),Java原子類實(shí)現(xiàn)了其變量的原子性,其提供的方法使用鎖機(jī)制保證其運(yùn)算的原子性。在每次的服務(wù)中,都對(duì)原子類變量進(jìn)行累加1,即可保證單機(jī)環(huán)境下,每次服務(wù)的唯一標(biāo)識(shí)號(hào)都不一樣。
對(duì)于第二個(gè)問(wèn)題,可利用數(shù)據(jù)庫(kù)系統(tǒng)(如MySQL)的自增id的特性,即在數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)記錄表,該表記錄了信息推送服務(wù)中間件每次啟動(dòng)后,首次提供服務(wù)的時(shí)間,該表中存在著一個(gè)自增的id列,將該id將作為信息推送服務(wù)中間件的唯一標(biāo)識(shí)。
為同時(shí)解決上述2個(gè)問(wèn)題,可將數(shù)據(jù)庫(kù)自增id和原子類對(duì)象值進(jìn)行組合作為最終的唯一標(biāo)識(shí)號(hào),組合規(guī)則可規(guī)定為:自增id為前綴,中間拼接下劃線字符,并以原子類對(duì)象值為后綴。
通過(guò)在信息推送服務(wù)中間件中集成第三方提供的服務(wù),一方面可以避免外部調(diào)用系統(tǒng)受到代碼入侵的影響,另一方面則能夠?qū)崿F(xiàn)對(duì)服務(wù)信息的集中式管理,支持對(duì)服務(wù)信息的快速檢索。短信推送服務(wù)的業(yè)務(wù)流程示意如圖2所示。
在信息推送服務(wù)中間件短信遠(yuǎn)程調(diào)用接口(控制層)被調(diào)用后,控制層會(huì)先行對(duì)傳入?yún)?shù)進(jìn)行檢查,然后控制層會(huì)調(diào)用業(yè)務(wù)邏輯層流水號(hào)(唯一標(biāo)識(shí)號(hào))生成方法進(jìn)行流水號(hào)的生成,再進(jìn)行業(yè)務(wù)邏輯層短信發(fā)送方法調(diào)用,業(yè)務(wù)邏輯層若出現(xiàn)異常則通過(guò)日志服務(wù)把帶有流水號(hào)的異常信息輸出到日志文件,以方便開(kāi)發(fā)和維護(hù)人員進(jìn)行檢索,若服務(wù)正常,則業(yè)務(wù)邏輯層通過(guò)調(diào)用數(shù)據(jù)處理層進(jìn)行對(duì)服務(wù)結(jié)果信息持久化到數(shù)據(jù)庫(kù)中。
圖2 短信推送服務(wù)的業(yè)務(wù)流程
通過(guò)在中間件中集成第三方的消息推送服務(wù),外部系統(tǒng)只需要統(tǒng)一使用Dubbo通訊協(xié)議接入中間件,即可實(shí)現(xiàn)對(duì)異構(gòu)通訊協(xié)議的第三方消息推送服務(wù)的使用,避免了外部系統(tǒng)代碼中耦合大量第三方消息推送服務(wù)的調(diào)用邏輯,且外部系統(tǒng)無(wú)需關(guān)心推送服務(wù)結(jié)果的持久化實(shí)現(xiàn),將第三方消息推送服務(wù)集中于中間件實(shí)現(xiàn),大幅度降低了對(duì)第三方消息推送服務(wù)功能的維護(hù)難度。
該消息推送服務(wù)中間件使用了遠(yuǎn)程調(diào)用功能提供消息推送服務(wù),由于當(dāng)前的遠(yuǎn)程調(diào)用功能僅支持同步回調(diào),因而在整個(gè)信息推送服務(wù)過(guò)程中,調(diào)用第三方短信推送服務(wù)的時(shí)間耗占比會(huì)比較髙,若能實(shí)現(xiàn)遠(yuǎn)程調(diào)用服務(wù)的異步回調(diào),將能大大地縮減信息推送服務(wù)的響應(yīng)時(shí)間,提高服務(wù)響應(yīng)速度,因此,下一步將會(huì)研究遠(yuǎn)程調(diào)用服務(wù)異步回調(diào)的實(shí)現(xiàn),進(jìn)一步提升消息推送服務(wù)中間件的服務(wù)性能。