在做分布式系統整合的時候,當乙個功能涉及到多個平台的時候,通常面對的問題都是如果失敗了怎麼辦?今天就給大家分享乙個新思路-基於事件溯源實現分布式協調
在進行正式開始之前我們需要先介紹下我們的場景是什麼,要解決的問題是什麼。
在應用管理平台建設中需要整合內部的多個平台,比如容器、虛機、監控、發布、cmdb、負載等多個平台,每個平台都只負責某一部分功能,但是比如我們要做乙個虛機擴容、灰度發布等通常就需要操作多個平台;如果是全部都是基於k8s的可能還好一點,但是對於一些公司這種平台建設早於容器平台,這時候就得由應用管理平台來進行協調了
在做一些業務開發時,比如訂單支付通常會為了完成這個功能,多個服務會針對業務進行改造,比如使用tcc、saga等分布式事務模型來進行業務的一致性保障,其核心參考acid的事務模型。而在應用平台建設中,首先對應的業務方不太會配合你進行改造,其次很多業務場景也不可能實現事務。比如你擴容建立了一台虛機,如果後續流程失敗了,你總不能把機器給乾掉吧?
既然不能像業務一樣通過傳統的事務模型進行業務完整性保障,那我們何不換一種思路呢?於是基於穩定性的思考,筆者將設計思路轉換成提高系統的容錯能力,並盡可能的減小**半徑,同時盡可能的提公升系統的可擴充套件性,保障高可用。
提到容錯能力比較典型的場景就是資料處理場景了,這裡先給大家介紹一下在分布式資料場景中是如何進行容錯的。在分布式資料中,通常由source、process、sink三部分組成,而在很多場景中又要實現準確的exactly once,我們看看再flink裡面是如何進行設計的, 這裡先給大家介紹相關概念
checkpoint通常用於儲存某些記錄的位置資訊用於方便系統故障後快速恢復,在flink中也利用了checkpoint機制來實現exactly once語義,其會按照配置週期性的計算狀態生成檢查點快照,然後將checkpoint持久化儲存下來,這樣後續如果崩潰則就可以通過checkpoint來進行恢復
checkpoint只作用於flink內部,那如果要實現從source到sink整個鏈路的exactly once,則就會涉及到多個元件同時做checkpoint的同步, 這時候就要讓多個元件的checkpoint達到一致性, 為了實現這個功能flink裡面引入了barrier用於切分資料流;就類似程式語言中的記憶體屏障,通過barrier讓多個元件同時進行對於checkpoint的持久化。每個barrier都會攜帶乙個checkpoint id,這樣整個資料流的多個元件就會同時進行同乙個checkpoint的持久化了
有了barrier機制之後則就需要乙個觸發和管理元件,利用barrier和checkpoit讓source、process、sink三者同時進行checkpoint儲存,在flink中就引入checkpointcoordinator來協調多個元件, 有了這三個核心的概念,就可以讓在flink中的多個分布式元件中實現checkpoint機制了
前面的設計都是位於flink內部,但是在資料處理中source、sink元件則通常是第三方平台,這個時候如果還要保障exactly once則除了冪等性就需要用到我們這裡說的兩階段提交了;要實現兩階段提交,則就需要對應的平台提供事務機制,在precommit階段做資料的消費和寫入,同時在commit階段實現事務的提交,由於事務未提交則對應的平台讀取不到對應的資料,只有最終都提交成功後,才可以讀取到寫入的資料
通過上面的我們了解了如何基於利用兩階段提交、checkpoint、barrier結合事務機制實現分布式環境中的exactly once實現機制,後續在資料處理的場景中,我們就可以利用這套機制結合實際業務場景進行落地了
在下一節我們將開始介紹分布式任務編排中的另外一種實現機制,用於實現分布式系統的容錯解決上述場景中遇到的問題
事件溯源保證應用狀態的所有改變都儲存在事件流中. 這樣我們不僅能查詢這些事件,我們也可以通過這個事件的日誌來重新構建以前的狀態, 以些為基礎實現自動改變狀態來應對追溯過的變化.
任務編排的核心是通過編排對應的任務序列實現某個業務功能,在分布式環境中,通常會涉及到workflow任務的編排、task任務分配、執行時資料的儲存等。在大多數的任務編排框架中,關注點都是任務排程。而我們今天接下來要介紹的temporal其關鍵點則是容錯,即當對應的workflow、task如果執行失敗,系統該如何進行恢復。也是事件溯源利用的主要場景。
在前面的介紹exactly once場景中我們介紹過兩階段對事物機制的依賴,同理在任務編排中的狀態,我們這裡容錯機制實現的語義是at-lease-once,即任務至少被執行一次,並盡可能保障業務不會重複被執行
前面提到通過事件序列來進行事件回放可以得到當前狀態,其實在任務編排場景中還有第二個序列-執行序列,即我們要執行的任務列表一定要是順序的。只有這樣才能順著正確的道路繼續恢復。
例如在go裡面對slice的for range遍歷是固定的,這裡包含兩部分:恢復slice和遍歷slice, 即我再不同的機器上通過歷史資料我可以構建出slice, 然後遍歷這個slice這兩個操作的結果都是一樣的。
但是對map則不一定,我們並不能保證在不同機器上恢復和遍歷這兩個操作的結果都是一樣的。所以workflow裡面的邏輯和狀態資料一定要是不變的
不過想想基於temporal可以快速實現乙個分布式、可擴充套件、高容錯、無狀態的任務編排系統,其他都是小事情哈哈。後面有時間在給大家從原始碼上梳理下temporal的是如何實現上述功能的。包括任務分片、ringpop、訊號、狀態儲存等
什麼是事件溯源:
使用事件和訊息佇列實現分布式事務
原文 不同於單一架構應用 monolith 分布式環境下,進行事務操作將變得困難,因為分布式環境通常會有多個資料來源,只用本地資料庫事務難以保證多個資料來源資料的一致性.這種情況下,可以使用兩階段或者三階段提交協議來完成分布式事務.但是使用這種方式一般來說效能較差,因為事務管理器需要在多個資料來源之...
利用redis實現分布式鎖
一.對於分布式的應用,一定程度上會增加處理的速度。但是也會帶來一些分布式上的麻煩,比如有個需求 後台程式部署在多台伺服器上,client向該後台程式傳送引數為 使用者賬號和 賬號型別 的rpc請求,後台程式需要返回該賬號對應的身份資訊 邏輯很簡單,先判斷庫中有沒有該賬號資訊,有就返回,沒有就新生成乙...
利用redis實現分布式鎖
因為redis是單執行緒程式,可以天然的保證執行緒安全,只要我們的命令是單條命令,就可以保證操作的安全性,而redis中給我們提供了setnx key value命令,setnx命令的作用就是當我們的redis中沒有這個key的鍵值隊時,就會建立這個鍵值隊的值,如果已經有了這個key就不作操作 所以...