導語: 微服務架構目前是各網際網路系統架構的首選,在使用微服務的過程中,除錯一個分散式系統是一項具有挑戰的任務, 事件溯源是一種非常好的方式來解決微服務可見性的一種手段。且看大名鼎鼎的couchbase如何使用事件溯源解決微服務的可見性問題。
正如我在之前的文章中提到那樣,微服務是怎樣失敗的,除錯一個分散式系統是一項具有挑戰的任務。 許多東西可能是錯的並且是不可控的, 例如網路的不穩定性,臨時不可用或者是一些外部的BUG。
用一些工具監控網路能被快速解決(像Service Mesh ),你也可以使用一些額外的工具像OpenTracing 來做分散式的日記記錄. 但是當我們談到理解我們的物體狀態時,並沒有快速的即插即用的框架。
你的資料可能比你程式碼存活的時間還要長, 然而我們卻忽略了我們的資料隨著時間推移而產生的變化。 在大多數系統中,即使是簡單的問題, 例如“該物體如何達到這種狀態?” 或 “一個月前我的狀態是怎樣的?” 都無法回答,因為沒有儲存任何變更的歷史記錄。 持續追蹤這些變更狀態對一個系統的健康是極其重要的, 不僅是為了安全或者是除錯目的, 而是出於巨大的商業價值(你的產品負責人會很高興)
讓我們來深入理解它是怎麼工作的。 假設我們正在為一個電商網站構建一個訂單服務(Order Service) , 讓我們看一下我們的應用狀態和事件看起來是怎樣的:
許多作者對於事件的溯源和記錄都定義了三個主要的規則:
-
事件總是不可變的;
-
事件總是那些過去已經發生過的事。 一些開發者錯誤指令(例如: PlaceOrder) 事件(ex: OrderPlaced)
-
理論上, 在任意時間點,你可以刪除你當前的狀態並且透過重新處理所接收到全部訊息來重新構建你的整個系統。
事件溯源| 事件記錄流
-
訊息接器: 負責將傳入的請求轉換為事件並且校驗他們;
-
事件儲存: 負責有序儲存這些事件並且通知監聽器;
-
事件監聽器:正如你可能猜到的, 它負責根據每一個事件型別來執行對應的業務邏輯
這種樣式有很多種實現方式, 在Couchbase5.5中使用的“事件服務”就是這種樣式的實現之一。 總而言之, 它允許你編寫函式, 在一個檔案被插入/更新/刪除時來觸發這些函式。 這個事件機制也能讓你生成curl 請求,因此無論何時將給定的檔案儲存在資料庫中,都可以在應用程式中觸發一個endpoint來處理它。 讓我們看一下它是如何使用事件的:
如果你想瞭解更多關於它(Event Service) 資料, 閱讀 couchbase eventing 官方檔案。
Couchbase Eventing 是非同步的, 所以上述套件實現僅適用於你的應用只接收非同步呼叫的情況。 它也可以用來充當額外的安全層以觸發通知, 例如,如果有人試圖手動更新一個事件。
在某些系統中, 事件的欄位和結構可能有很大的不同, 將這些事件儲存在一個固定結構的RDBM 中是很難建模的, 出於這個原因, 開發人員通常將它他們用一個varchar型別的欄位將這些事件儲存為一個json字串。這種辦法存在一個主要的問題: 它使得事件查詢變得困難,使你的大部分查詢變慢, 變複雜並且充拆著大量的類似’likes’操作。 其中一種可有的解決方案是使用檔案資料庫, 因為它們大多數將檔案儲存為json並且具有用於查詢它的類似SQL的語言, 如N1QL[1]。
快照-對你的狀態進行版本控制
事件溯源世界中新增版本控制/歷史記錄被稱為快照。 當你想要想要知道N天以前的狀態是什麼樣的, 可以避免你重新處理所有的事件。 當你需要快速識別在某時間點時應用的狀態與處理一個事件之後的所預期的狀態之間的差異。
快照具功能十分好用,成本低,易實現並且非常適合實時的上報。 如果你決定實現一個Event Sourcing, 可以在實現快照中多投入一點努力。
修複不一致的問題
這部份是你的所有的努力得到回報的地方。 一旦你在這個地方有了事件溯源/記錄並且具有快照功能, 你就可以使用Retroactive Event 樣式的來修複不一致的情況。
我總結一下, 如果你修複了一個BUG並且現在需要調整被影響物體的狀態, 而不是手動更新他, 你可以將你的物體的狀態設定為BUG之前的狀態,並且從那個時刻重放所以與之關聯的事件。 無須手動就會自動修改你的狀態。
-
-
-
重新構建事件: 從標的之後重建所有事件。
但是,如果事件中有錯誤資料或者從來沒有被觸發過,該怎麼辦?我們可以更新或刪除事件並重新處理整個事件嗎?
如果你還記得,事件溯源的第一條規則是“事件永遠是不變的”,這是一個很好的理由;你需要相信你所看到的日誌。但它不能回答我們的問題;只需略微修改一下:我們如何在不更改事件的情況下更改事件日誌?
那麼,解決這個問題的一個簡單方法就是將事件標記為可忽略的,以便在重建過程中我們可以忽略它們:
如果事件是由錯誤資料或錯誤順序觸發的呢?使用這種方法,我們不得不做的就是將所有事件標記為可忽略的,並新增一個具有正確值或位置正確的新事件,如下所示:
當然,上面的方法有一些瑕疵, 但是它是一種簡單的實現,易查詢並且能大多數場上執行的很好。 如果你需構建一個更健壯結構,考慮在一個連結串列結構中儲存你的事件:
關於外部系統|其他微服務?
微服務不是孤島,重放事件的副作用之一是你的服務向外部傳送訊息是合理的。這些訊息可能會在其他系統中引發不一致或傳播錯誤,這可能會使情況比以前更糟糕。
不幸的事,由於可能的情況多種多樣, 這裡沒有銀彈來解決這個問題, 並且每一個案例不得不單獨處理。 下麵給出一些普遍的解決方案:
-
臨時修改配置禁止傳送任務外部訊息或者新增一個攔截器允許你配置哪些訊息需要傳送;
-
重新路由指定的請求到一個假的服務(如果你正在使用的服務網路樣式就是一個典型的場景)
-
使其他服務能夠識別出一個給定的操作已經在過去以相同的引數執行了,而不是丟擲一個錯誤,服務需要像以前一樣傳回相同的成功訊息。
當然,有相當多的情況下,您無法自動修複外部不一致情況,在這種情況下,預計其他系統會輸出人為可讀的錯誤和/或觸發人工幹預的通知。
事件溯源的優點
儘管它是一個簡單的樣式,但使用它有很多優點:
-
事件日誌具有很高的商業價值;
-
它在DDD和事件驅動架構下執行得非常好。
-
除錯用應用程式狀態中所有變更的來源;
-
它允許您重放失敗的事件;
-
易於除錯,您可以將標的物體的所有事件複製到您的機器並除錯每個事件,以瞭解應用程式如何達到特定狀態(忽略從生產環境複製資料的安全隱患);
-
允許您使用追溯事件樣式重建/修複您的狀態。
許多作者還將優先順序作為時間查詢的能力,但我認為查詢多個後續事件不是一項簡單的任務。因此,我通常認為時間查詢是快照樣式的一個優點。
事件溯源的缺點
結論
參考連結
[1] https://query-tutorial.couchbase.com/tutorial/#1
相關閱讀:
微博開源的Motan RPC最新進展:新增跨語言及服務治理支援
模組化還是微服務 – 為什麼說大部分團隊微服務化都走入了陷阱
本文作者Denis Rosa,由王賀翻譯。轉載譯文請註明出處,技術原創及架構實踐文章,歡迎透過公眾號選單「聯絡我們」進行投稿。
活動預告:
6 月 1 ~ 2 日,GIAC 全球網際網路架構大會將於深圳舉行。GIAC 是高可用架構技術社群推出的面向架構師、技術負責人及高階技術從業人員的技術架構大會。今年的 GIAC 已經有騰訊、阿裡巴巴、百度、今日頭條、科大訊飛、新浪微博、小米、美圖、Oracle、鏈家、唯品會、京東、餓了麼、美圖點評、羅輯思維、ofo、迅雷、曠視、LinkedIn、Pivotal 等公司專家出席。
本期 GIAC 大會上,微服務部分精彩的議題如下:
參加 GIAC,盤點2018最新技術。點選“閱讀原文”瞭解大會更多詳情。