張聰聰 孫二鑫
(中汽數據有限公司,天津 300384)
隨著物聯網技術的飛速發展,車聯網技術作為物聯網在道路交通方面的具體體現也隨之發展壯大。目前我國車聯網產業鏈已初步形成,車聯網作為汽車產業轉型升級的創新驅動力,具有極強的賦能效應[1]。而共享出行市場從2015年發展至今,經歷爆發式擴張、又迅速收縮、質疑、重整后,也在回歸理性和成熟,尤其在車聯網技術的共同發展下,更是加速了行業發展[2-3]。傳統的共享汽車模式一般是查看當前可用車輛,然后進行鎖定預約。這種模式不能有效提高車輛的使用率。本系統針對本企業的共享汽車需求及對系統穩定性的要求,采用RabbitMQ消息隊列管理服務,對預約審批流程進行分布式高并發優化,充分利用RabbitMQ自由路由、多協議、高可靠性等特點對不同時間點的不同流程任務進行有效處理,對不同的消息特點進行實時推送,完美的實現了動態推送時間的消息推送方法,大幅提高了車輛的使用率,并有效的保障了系統的穩定性。
消息隊列(Message Queue),是分布式系統中重要的組件,當不需要立即獲得結果,但是并發量又需要進行控制的時候,就是需要使用消息隊列的時候。比如活動秒殺、多應用并發、消息隊列主要解決了應用耦合、異步處理、流量削鋒等問題。當前使用較多的消息隊列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分數據庫如Redis、Mysql以及phxsql也可實現消息隊列的功能[4-6]。
RabbitMQ在是一個在AMQP(高級消息隊列協議,Advanced Message Queuing Protocol)基礎上完成的、開源的、可復用的消息隊列服務系統,是當前最主流的消息中間件之一。RabbitMQ有幾點特點:(1)高可靠性,RabbitMQ提供了很多技術供開發者在性能和可靠性之間進行權衡;(2)靈活的路由,消息在到達隊列前是通過交換機進行路由的。RabbitMQ為典型的路由邏輯提供了多種內置交換機類型,同時開發者也可自由定制組合路由;(3)支持多種消息隊列協議;(4)管理界面,RabbitMQ有一個易用的豐富的用戶界面,使得用戶可以監控和管理消息。本平臺綜合考慮采用RabbitMQ來實現共享汽車的預約審批業務消息推送。
本企業的共享汽車預約審批流程如圖1所示。用戶登錄手機端共享汽車APP,選擇取車網點和還車網點、預計取車時間和還車時間等信息進行預約,服務端將生成“已預約待審核”的訂單,審批員登錄WEB端后臺管理系統進行審批,如果審批通過,訂單狀態為“已預約已審核”。在已預約待審批中狀態時,用戶可隨時取消訂單。服務端自動修改訂單狀態變為“用戶主動取消”。如果到了取車時間點預約單還未審批,系統將自動取消訂單,同時將訂單狀態修改為“預約超時自動取消”。已經審批通過的訂單,在預計取車時間點前30分鐘即可用車,服務端將自動判斷用戶是否可以取車,如果可以取車,則修改訂單狀態為“待取車”。在待取車狀態時,用戶可開始用車。如果訂單達到“待取車”狀態,但到預計取車時間點還未取車,則服務端自動修改訂單狀態為“取車超時異常”。如果已預約已審批的訂單,到還車時間還未取車的,則服務端會自動取消該訂單,同時修改訂單狀態為“系統自動取消”。
從業務流程上看,共享汽車預約審批消息推送服務主要分為主動式和觸發式兩種。主動式服務通過WE B端或AP P端人員主動發起請求,將消息推送給服務端或AP P端;觸發式服務則為根據所設定的條件,系統自動判斷是否滿足要求,自動觸發服務,將消息發送給服務端或APP端。
(1)主動式服務:1)審批員對訂單進行審批后,將審批結果主動推送給用戶。2)當訂單狀態變化時,推送訂單變化后的數據信息給用戶。3)用戶主動取消訂單,服務端應將訂單取消,同時將車輛狀態改變,自動判斷下一訂單是否滿足用車要求,進入延時隊列。(2)觸發式服務:1)用戶預約下單,到了取車時間點預約單還未審批,系統將自動取消訂單。2)審批員審批通過,在預計取車時間點前30分鐘時,服務端自動修改訂單狀態為“待取車”。3)訂單達到“待取車”狀態,但到預計取車時間點還未取車,則服務端自動修改訂單狀態為“取車超時異常”。4)已預約已審批的訂單,到還車時間還未取車的,則服務端會自動取消該訂單,同時修改訂單狀態為“系統自動取消”。
各訂單發起時間不同,預約時間也不盡相同,預計取車時間和還車時間也不一定都相同,但傳統的消息推送方法一般是同一隊列Queue中的消息將按照先進先出方式進入Consumer,無法滿足共享汽車消息平臺要求,因此平臺需要建立可動態處理推送時間的消息推送機制。消息推送流程如圖2所示。

圖2 消息推送流程
當用戶在WEB端或APP端進行操作或在特定情況被觸發服務時,一方面將執行相關業務邏輯并將數據狀態持久化到數據庫中,另一方面將消息存入RabbitMQ隊列中,在特定條件下被Consumer消費掉,在Consumer中再執行對應的業務邏輯并將數據持久化到數據庫中,一些業務還會生成新的消息存入RabbitMQ中,比如向APP端推送消息等。需要說明的是,本平臺中消息一旦被消費之后,即從隊列Queue中清除,不必二次消費,因此此動態推動時間的消息推送方法是點對點模式的。
平臺基于Spring開發,因此使用Spring提供的相關功能組件進行以上功能模塊開發:
(1)創建延時消息DTO。延時消息DTO包含消息id和消息到期時間targetDelayDate,targetDelayDate一般為觸發式服務中的時間節點。比如用戶預約下單,消息的到期時間targetDelayDate為取車時間。(2)發送消息和消費消息。平臺通過RabbitTemplate類的convertAndSend()方法將消息發送到指定的隊列和路由上,同時設置MessagePost Processor中的Expiration屬性值等于延時消息DTO的消息到期時間與當前時間的時間差,避免消息一直存在隊列中。平臺設置有2種隊列,延時隊列DelayQueue和死信隊列DLXQueue(DLX:Dead Letter Exchange)。延時隊列DelayQueue屬于正常隊列,Consumer消費者通過配置@RabbitListener注解從指定隊列中獲取到消息,同時通過@RabbitHandler的方法處理相關業務邏輯,例如圖示實線路徑。延時隊列DelayQueue2與DelayQueue1不同的是,添加參數配置隊列TTL(Time To Live),即通過來設定消息存活時間。當隊列TTL時間過期時,隊列中的所有消息就會變成死信被重新publish到DLXQueue死信隊列中,在DLXQueue死信隊列的消費者處理方法中判斷當前時間是否到達消息到期時間targetDelayDate,如果到達則正常執行業務邏輯,如果沒有到達則將消息重新convert AndSend到對應的隊列和路由中,例如圖示虛線路徑。這種循環將保證在一個T T L 時間段內,所有消息都將被Consumer消費一次,這樣可以有效保證后進入的消息需要先執行的情況被及時消費,同時可根據消息的到期時間targetDelayDate來判斷消息是否需要真正的被Consumer消費。(3)向APP端推送消息。平臺在一些特定情況下需要給APP端推送實時消息,比如審核消息等,平臺采用極光推送(JPush)服務進行向APP端推送消息。極光推送,是一個面向普通開發者開放的,免費的第三方消息推送服務。相較于websocket,作為平臺端和APP端間的實時通信,JPush更加便捷,開發簡單,時效性強。在平臺中,可簡單的按照消息產生順序進行推送消息,因此采用圖示實線路徑實現平臺到APP端的實時消息推送。
本文的主要測試點是發送消息、消費消息、向APP端推送消息三大部分。發送消息部分主要采用Junit進行單元測試,主要測試用戶觸發的消息是否與RabbitMQ中消息數是否保持一致。消費消息部分主要通過查看數據庫中相關業務邏輯狀態是否在預定時間改變。向APP端推送消息部分主要通過檢查JPush服務中的消息數是否與原邏輯一致。經過測試統計,消息推送成功率在100%,達到預期效果。
本文基于共享汽車預約審核需求,利用靈活路由的RabbitMQ消息隊列服務提出了一種基于動態推送時間的預約審核系統,實現了任意時間下準時推送消息的機制,為企業的共享汽車預約平臺提供高可靠性的保障,同時也為共享汽車的使用率提升提供了一種方向。