楊成榮 劉峻松 孫新杰 吳超
摘要:隨著微服務架構的興起,越來越多的應用由單體式向微服務架構轉移,由于微服務其分布式的特性,以及微服務架構自身強調數據的獨立,整體的數據一致性問題被放大。該文主要針對在微服務通訊過程中引入分布式消息隊列進行研究。首先,解決消息和指令的冪等性,保證重復消息的單次執行。其次,在分布式消息隊列中對消息數據進行落盤保存通過偏移量的操作實現單方重新上線后的自我補償,保證消息的投遞。最后,人為模擬業務流程和可能出現的問題進行試驗,由該機制進行自動處理,實現數據的最終一致性。通過分析實驗結果,該機制可以在低時效性業務系統中自動解決由于服務或數據庫離線造成的數據不一致,實現微服務整體的數據的最終一致性。
關鍵詞:微服務;分布式;數據一致性
中圖分類號:TP311 文獻標識碼:A
文章編號:1009-3044(2020)08-0266-03
隨著互聯網業務的復雜性和其用戶量的不斷增加,單體式應用的弊端已經逐步顯現,微服務架構應運而生。微服務架構將巨大臃腫的單體式應用根據業務和功能的需求分解為無數小的且通過不同互聯技術相互連通的微服務[1],其優勢主要在于方便部署,擴展性高,開發周期和成本大大降低等[2]。但是,微服務架構自身的分布式特性也存在一定的弊端。在實際生產環境中,越來越多的行業領域都開始使用軟件自動化來代替人工,相應的,計算機軟件的穩定性、健壯性的影響也越來越大,計算機軟件出現的錯誤所付出的代價也越來越大,目前微服務架構的興起,也要面臨其所帶來的風險,數據一致性[3]的保證問題就是其中之一。
目前針對微服務架構在分布式系統方面數據不一致情況有了一些研究和解決方案。文獻[4]使用對關鍵業務進行整合的方法,將某些關聯性極強的服務整合成一個服務,整合后自身使用事務管理來保證數據一致性。文獻[5]采用了一種危機應對的機制,當任何一處發生異常時,觸發一套針對異常的回滾事件,借此來使得整個系統來恢復到執行前的狀態。文獻[6]針對網絡連接異常的問題進行了討論和研究,設計了一個鏈路的檢測機制來做到預先發現網絡問題并進行處理,但是對于已經發生的數據不一致情況沒有給出解決方案。
1 業務流程概述
本文針對微服務架構中存在的問題[7],重新設計了業務流程:業務從發送端的消息列表產生,也從發送端的消息列表結束,一個新的指令被創建的時刻將在消息列表進行記錄和登記,接下來開始對該指令進行執行過程,每個關鍵點的執行都要對該列表內該事務狀態進行更新,然后向指定位置發送消息,消息的接收者從指定話題中消費消息,將消息首先記錄在本地消息列表中,然后再開始后續的執行過程,每個關鍵點的完成都要對列表內狀態進行更新。
2 關鍵模塊概述
針對以上業務流程分別設計五個關鍵模塊,分別為業務發起模塊、任務管理模塊、消息發送模板、消息接收模塊以及遠程分布式消息隊列模塊。
2.1 業務發起模塊
業務發起模塊用于對一個新的業務進行發起。主要包括兩方面功能,一方面是當該模塊處于一個主動發起業務的服務中時,由服務在應用內部向該模塊發送業務相關內容,該模塊直接對該業務賦予一個唯一標記的Key值,生成相關任務條目信息將信息傳送給任務管理模塊,則為成功發起一項新的業務;另一方面當該模塊處于一個被動接受指令的服務時,該模塊從消息接收模塊處接收任務指令,首先向任務管理模塊發送請求對接收到的指令Key值進行核對,若該任務已經存在且尚未完成,則直接忽略處理,由任務管理模塊自行處理,若該任務以完成,則由任務管理模塊重新核對完成信息,由消息發送模塊直接發送該任務完成的信息;若該任務不存在,則同新發起業務流程,生成必要信息遞交任務管理模塊。
2.2 任務管理模塊
任務管理模塊用于對所有已登記記錄的任務進行管理。主要包括以下功能:1)對業務發起模塊發出的查詢請求進行回應,包括對Key值進行查重,向其返回查詢狀態和該任務狀態。2)對業務發起模塊所發起的業務進行登記,記錄在任務列表當中,當該模塊所在服務對該條任務的業務流程完成后,更新任務列表中的任務完成狀態為已完成狀態,對由于服務自身原因無法完成的任務標記為異常狀態。3)定時掃描所有處于尚未完成狀態的任務條目,向消息的發送模塊遞交發送任務結果請求;對于處于尚未完成狀態但是最后發送時間較當前系統時間差值超過設定超時時間時,視該任務為超時,則直接向發送模塊遞交重發請求;對超時的任務但是發送次數已經超過預設閾值的條目進行標記失敗,記錄該條任務的全部信息,根據業務需求通知人工干預處理;對所有處于尚異常狀態的任務遞交消息發送模塊進行轉發處理。4)當該模塊處于一個任務的發起服務時,將接收從消息接收模塊遞交的完成申請對該條任務的完成狀態進行更新。
2.3 消息發送模塊
消息發送模塊用于根據其他模塊遞交的發送申請根據類型分類并整理為指定消息格式然后進行消息的發送和廣播。該模塊可以通過預設或者運行過程中動態改變發送Topic值來改變發送的目標;同時該模塊下設一個后備列表,當該模塊所在的服務由于種種原因不能完成該項業務,則想該后備列表查詢與該服務功能相同的后備服務,然后將該異常任務直接遞交給后備服務執行。
2.4 消息接收模塊
消息接收模塊包括被動消息監聽守護模塊和主動消息接收模塊兩個子模塊。被動消息監聽守護模塊隨服務啟動監聽固定的Topic,將獲取的消息解讀并根據分類遞交給業務發起模塊或者任務管理模塊。主動消息獲取模塊可以在每次服務啟動時或者是在預設閾值時間內沒有接收到任何指令的情況下,或者在任務管理模塊的指令下,使用底層API對遠程分布式消息對列中當前終端的偏移量和本地記錄的最近一次偏移量進行比較,若不相同則判定為有消息丟失,則根據實際情況重復消費指定偏移量的消息進行解讀和遞交。
2.5 遠程分布式消息隊列模塊
遠程分布式消息隊列模塊處于發送與接收之間的中間件。本文使用Apache Kafka分布式隊列[8]作為中間件,在本文所設計的整體機制中為所有的消息傳遞進行記錄和落盤處理,由于其自身的特性,使用文件與偏移量的形式來實現消息隊列,而且保證了每個用戶分組只能有且只有一個用戶消費到同一條消息,被消費過的消息不可重復消費,但是在本文設計的機制中由于需要對部分異常情況進行消息的補償操作,所以使用該平臺提供的低層API進行偏移量的操作[9];另外該分布式平臺的落盤處理根據其節點的數量均有不同數量的備份,可以確保在部分節點宕機崩潰離線的情況下整個消息平臺依舊可用且消息不丟失。最紅該平臺可以通過參數的設置來根據實際生產環境來設定定時對落盤的過久消息進行處理和清理,保證整個系統的資源占用。
3 數據一致性保障機制
根據上述描述,每個業務服務都可簡單地理解為一個發送方和一個接收方的數據交互的組合,因此根據這一模型,可能會出現數據不一致的情況可能有如下幾種:
1)發送方成功發送業務請求,接收方成功接收,但此時發送方服務離線,在發送方重啟后,可能會再次發送業務請求造成接收端重復執行相同指令。
2)發送方成功發送業務請求,此時接收方離線,造成該消息丟失,進而該業務停滯無法繼續進行。
3)發送方成功發送業務請求,接收方成功接收該請求,兩方自身業務成功執行,接收方發送指令回執,此時發送方離線,該消息丟失,在成該業務數據不一致。
4)發送方成功發送業務請求,接收方剛剛接收該請求,接收方離線,造成該消息丟失。
除此之外還有很多不可預料問題造成消息的丟失和消息的重復接收,進而造成數據不一致的發生。
針對以上所可能發生的問題,根據微服務模塊之間多種傳輸模式[10],采取如下一系列策略來保證數據的一致性:通過實現消息的冪等性來解決一切重復消費的問題,具體的實現方法體現在為每一條業務流程分配唯一的Key值,在接收到指令后首先對Key值進行核對如果出現重復則忽略該消息。通過引入一個外部的分布式消息隊列來解決一切消息或者信息丟失的問題,具體實現方法體現在所有消息的傳輸均經過該消息隊列,該消息隊列對所有的消息進行羅盤存儲,然后接收者通過消息隊列進行消息的消費,通過一系列設置保證消息的百分百投遞。通過對每一項業務進行記錄,保證了所有自身環境的數據不一致的發生。通過對遠程消息隊列的偏移量的高級操作來實現在特定情況下對消息進行重復消費來保證數據一致性。
4 模擬實驗結果分析
基于上述機制,本文使用Java線程模擬微服務場景,各個模擬微服務之間通過外部Kafka消息隊列平臺進行消息傳輸,然后通過手動阻塞的方式對微服務交互的每個階段可能出現的離線情況進行模擬,用來檢測該機制的處理情況。
首先模擬正常通訊過程,服務A發起一個新的任務向服務B發送任務請求,同時執行自身業務邏輯,服務B接收到任務后執行自身業務邏輯,完成后向服務A發送完成回執,整個業務流程結束。
第一次模擬服務A在發送指令之后崩潰離線,重啟后重新執行該指令,造成對服務B的同一條指令的兩次重復傳遞,服務B根據本條業務的Key值確定為重復指令,重復向服務A發送任務回執,保證了消息的冪等性。
第二次模擬服務A發起業務并向服務B發送任務請求,服務B成功接收請求并執行自身業務邏輯,完成后向服務A發送任務完成回執,服務A成功接收回執,但是在對自身任務列表狀態更改之前,服務A異常崩潰離線,重啟后,根據啟動機制,首先向遠端消息列表查詢當前偏移量和本地最后一次執行的偏移量做對比,發現出現誤差,則前移偏移量重復消費上次的內容,獲得服務B發送的消息回執,則此次業務流程完成。
第三次模擬服務A發起業務并向服務B發送任務請求,服務B成功接收請求,但是在將請求記錄在自身任務列表之前服務B異常崩潰,重啟后,根據服務B自身啟動機制,核對遠端當前偏移量與自身本地偏移量,發現異常并重復消費,獲取服務A發送的任務請求,正常執行業務流程。
第四次模擬服務B接收到服務A的服務指令,但是在執行自身業務邏輯時由于自身問題無法完成該業務,則發送求助,此時服務C和服務D同處于該求助列表中,有且只有一個服務消費到了這條求助并執行B的任務,向A發送回執,保證該次業務流程完成。
第五次模擬服務A發起一次業務流程,向服務B發送任務請求,但是由于一部分原因,服務B自身無法接收到該指令,因此,服務A在超時后再次向服務B發送同一條指令,發送超過規定次數后,服務A認為服務B已經離線,并且無法完成任務,于是向后備列表發送求助,此時服務C和服務D同時接收到求助,有且只有一個服務消費此求助,然后完成任務向服務A發送回執。
本文設計并實現了在微服務架構中針對服務間數據交互中可能出現的各種導致數據不一致的問題的解決方案,該機制通過保證消息的冪等性,消息的落盤和每個服務對于偏移量的操作基本實現在較低的時延內在低時效性的業務模型中保證數據的最終一致性,通過人為模擬業務各個步驟當中可能出現的各類角色的離線情況驗證該機制可以預防一定的數據不一致并且在數據不一致發生時能夠觸發一定的事件來對整個業務邏輯進行補償,而且能夠盡可能的單方自行解決,避免了在耗時較高的業務中重發等待時間過長導致的業務時延成倍增加問題,并且將該機制設計為服務模塊可以隨服務啟動又可以獨立于業務邏輯之外來保證該機制的運行。
參考文獻:
[1] Dragoni N.Giallorenzo S.Lafuente A L et al-Microservices:yesterday, today, and tomorrow[Ml//Present and Ulterior Soft-ware Engineering. Cham: Springer Intemational Publishing,2017: 195-216.
[2] Pahl C,Jamshidi P.Microservices:a systematic mapping study[C]//Proceedings of the 6th International Conference on Cloud Computing and Services Science, April 23-25, 2016. Rome,It一aly. SCITEPRESS - Science and and Technology Publications, 2016: 137-146.
[3]周婧,王意潔,阮煒,等.面向海量數據的數據一致性研究[Jl-計算機科學,2006,33(4):137-140,161.
[4]徐進,黃勃,馮炯.基于消息通信的分布式系統最終一致性平臺[J].計算機應用,2017,37(4):1157-1163.
[5]孫赫勇.基于企業服務總線消息補償方法的設計[J].微型機與應用,2013,32(10):90-91.
[6]姜夢蘭.基于消息中間件服務可靠性保障方案的研究與實現[D].成都:電子科技大學,2010.
[7]李貞吳.微服務架構的發展與影響分析[Jl.信息系統工程, 2017(1):154-155.
[8] Garg N.Apache Kafka[M]. 2013.
[9]杜岳峰,申德榮,聶鐵錚,等.基于關聯數據的一致性和時效性清洗方法[J].計算機學報,2017,40(1):92-106.
[10] Thones J.Microservices[J]. IEEE Software, 2015, 32(1):116.
【通聯編輯:謝媛媛】
收稿日期:2020-01-25
基金項目:教育大數據視域下學習干預模型構建與研究(項目編號:LPSSY201908)
作者簡介:楊成榮(1993-),男,河北衡水人,助教,碩士,研究方向為機器學習、數據處理;劉峻松(1995一),男,山東青島人,碩士,研究方向為數據處理;孫新杰(1987-),男,河南駐馬店人,副教授,碩士,研究方向為數據挖掘;吳超(1993-),男,江西鷹潭人,講師,碩士,研究方向為數據處理。