日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[译] 基于事件流构建的服务

發布時間:2025/3/18 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [译] 基于事件流构建的服务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[譯] 基于事件流構建的服務

摘要:本文屬于原創,歡迎轉載,轉載請保留出處:https://github.com/jasonGeng88/blog

原文:https://www.confluent.io/blog/build-services-backbone-events/

對許多人來說,微服務是建立在請求和響應協議之上的,如 REST 等等。這種方法很自然。 我們編寫程序是一回事,我們調用其他代碼模塊,等待響應并繼續。它也與我們每天看到的大量使用情況緊密相連:前面的用戶點擊按鈕的網站,并期待事情發生。

但是當我們進入許多獨立服務的世界時,事情就會開始變化。隨著服務的數量隨著時間的推移逐漸增長,同步交互的網絡也隨之增長。以前良性的可用性問題開始引發更廣泛的中斷。

在分布式系統中,排查問題對于我們不幸的運維工程師來說,將是艱巨的任務。瘋狂的從一個服務到另一個服務,拼湊各個服務的信息片段。

這是一個眾所周知的問題,并且有一些解決方案。一個是確保您的個人服務具有比您的系統更高的 SLAs。Google 提供了這樣做的協議。另一種方法是簡單地分解將服務綁定在一起的同步關系。

我們可以使用異步作為這樣做的機制。如果你在在線零售工作,你會發現同步接口,如 getImage() 或 processOrder() 感覺自然,期望調用得到立即響應。但是當用戶點擊“購買”時,它會觸發一個復雜而異步的過程。一個采購的過程,并將其線下交付到用戶門口,這種方式已經超出原本按鈕的上下文。因此,將軟件分解成異步流可以使我們能夠區分我們需要解決的不同問題,并允許我們擁抱一個本身就是異步的世界。

在實踐中,我們發現會有輪詢數據庫表來進行更改,或者通過一些定時任務來進行更新。這些是打破同步關系的簡單方式,但這些方式給人不透明的感覺,像有黑客篡改了你的數據一樣。可能他們有一個很好的理由。

所以我們可以將所有這些問題集中到一個觀察中。我們命令服務去做我們要求的事情,這樣的命令式編程模式不適合獨立運行的服務。

在這篇文章中,我們將看看架構硬幣的另一面:不是通過命令鏈,而是通過事件流的方式來組合服務。這是一個有效的方法。它也為我們將在本系列后面討論的更先進的模式形成基準,我們將事件驅動處理的想法與流式平臺中的觀點相結合。

命令(Commands)、事件(Events)和查詢(Queries)

在我們深入研究一個例子之前,我們需要解決三個簡單的概念。服務可以通過三種方式相互交互:命令、事件和查詢。 如果你以前沒有考慮過這三者之間的區別,那么這很值得。

事件的優點是事實和觸發。外部數據可以被系統中的任何服務來重用。但從服務的角度來看,事件造成的耦合又要比命令和查詢來得低。這個事實很重要。

服務間交互的三種方式:

  • 命令:是一個動作,在另一個服務中執行某些操作的請求。有些會改變系統狀態。命令會期待一個響應結果。

  • 事件:既是事實也是觸發器。對已經發生事情的一種通知。

  • 查詢:是查找某物的一個請求。重要的是,查詢是無副作用的,不會造成系統狀態的改變。

一個簡單的事件驅動流程

我們從一個簡單的例子開始:客戶訂購小部件,這個行為會觸發接下來的兩個事情:

  • 處理相關的付款。

  • 系統檢查以查看是否需要更多小部件。

  • 在請求驅動的方法中,這可以表示為一連串的命令。目前沒有查詢。互動將如下所示:

    要注意的第一個事情是通過調用訂單服務初始化“購買更多的庫存”的業務流程。這混合了兩個服務的責任,理想情況,我們應該更好的分離關注點。

    現在,如果我們可以使用一個事件驅動方法來代表相同的流程,那么事情會變得更好。

  • UI 服務觸發一個“訂單請求”事件,并在返回給用戶之前等待一個“訂單確定”(或拒絕)的事件。

  • 訂單服務與庫存服務都通過觸發的事情來進行響應。

  • 仔細看,UI 服務與訂單服務的交互沒有任何改變,除了他們是通過事件來交流的,而不是直接調用對方。

    庫存服務很有趣。訂單服務不再告訴它要做什么,也不再控制是否參與互動。這是這種類型的架構非常重要的屬性,稱為 “Receiver Driven Flow Control”。邏輯被推送到事件的接收者,而不是發送者。責任的重任進行了翻轉!

    將控制轉移到接收者可減少服務之間的耦合,從而為架構提供了重要的可插拔性。組件可以輕松地換入換出。

    隨著架構變得越來越復雜,可插拔性的這一要素變得越來越重要。說我們要添加一個實時管理定價的服務,根據供需調整產品的價格。在一個命令驅動的世界里,我們需要引入一個可以由庫存服務和訂單服務調用的 maybeUpdatePrice() 方法。但在事件驅動的世界重新定價只是一種訂閱共享流的一個服務,當滿足相關標準時發送價格更新。

    混合事件與查詢

    上面的例子只考慮了命令/事件。 沒有查詢操作(請記住我們將所有交互定義為命令、事件和查詢的其中一種)。查詢是除了最簡單的架構之外的所有架構的必需品。所以我們來擴展這個例子,讓訂單服務檢查在處理付款之前有足夠的庫存。

    對此的請求驅動方法將涉及向庫存服務發送查詢以檢索當前庫存數量。這導致混合模型,其中事件流純粹用于通知,允許任何服務進入流程,但查詢直接轉到源。

    對于服務需要獨立發展的更大的生態系統,遠程查詢增加了很多耦合,在運行時將服務捆綁在一起。 我們可以通過內部化來避免這種跨上下文的查詢。事件流用于緩存每個服務中的數據集,使其可以在本地進行查詢。

    所以要添加這個庫存檢查,訂單服務將訂閱庫存事件流,將它們進行本地存儲。然后直接查詢本地緩存來驗證是否有足夠的庫存。


    純事件驅動系統沒有遠程查詢的概念 - 事件將狀態傳播到在本地進行查詢的服務

    這種“按事件傳播查詢”方法有三個優點:

    • 更好的解耦:查詢是本地的。它們不涉及跨上下文調用。這種服務的耦合性遠遠低于他們請求驅動時的耦合性。

    • 更好的自治:訂單服務具有庫存數據集的私有副本,因此它可以隨意使用它,而不僅限于庫存服務提供的查詢功能。

    • 高效連接:如果我們在每個訂單上“查詢庫存”,我們將有效地通過兩個服務之間的網絡進行連接。隨著負載的增加,或者更多的資源被使用時,這可能會變得非常糟糕。按事件傳播查詢通過將查詢(和連接)本地化來解決此問題。

    這種做法不是沒有缺點。服務內部變成有狀態的。他們需要跟蹤和處理一段時間內傳播的數據集。狀態的重復也可能使一些問題更難理解(我們如何原子地減少庫存數量?),我們也應該注意數據是最終一致性的問題。但是,所有這些問題都有可行的解決方案,他們只需要考慮一下。

    單獨寫原則

    適用于這種風格的系統的有用原則是將特定類型的傳播事件的責任分配給單個服務:單獨寫原則。因此,庫存服務部門將擁有“庫存清單”如何隨時間推進,訂單服務部門將擁有訂單等。

    這有助于通過單個代碼路徑(盡管不一定是單個進程)來保證一致性,驗證和其他“寫入路徑”問題。所以,在下面的示例中,請注意,訂單服務控制對訂單進行的每個狀態更改,但整個事件流量跨越訂單、付款和發貨,每個由其各自的服務管理。

    分配事件傳播的責任很重要,因為這些不僅僅是短暫的事件,也不是短暫的聊天。他們代表共同的事實,數據在外面。因此,隨著時間的推移,服務需要負責策劃這些共享數據集:修復錯誤,處理模式變化等情況。

    這里每個顏色代表 Kafka 在訂單、發貨和付款中的一個主題(topic)。當用戶點擊“購買”時,會觸發“訂單請求”,等待“訂單確認”事件,然后再回復給用戶。另外三個服務處理與其工作流程部分相關的狀態轉換。例如,付款處理完成后,訂單服務將訂單從驗證推送到已確認。

    混合模式和集群服務

    對于上面描述的一些模式看起來像企業消息(Enterprise Messaging),但還是有些許的不同。企業消息在實踐中側重于狀態的轉移,通過網絡有效地將數據庫捆綁在一起。

    事件協作是關于服務通過一系列事件來處理一些業務目標,這些事件將觸發服務的行動。所以這是業務處理的一種模式,而不是簡單的移動狀態的機制。

    但是,我們通常希望在我們構建的系統中利用這種模式的“faces”。事實上,這種模式的美妙之處在于它可以處理微觀和宏觀,或者在有意義的情況下被混合。

    組合模式也很常見。 我們可能想要遠程查詢的靈活性,而不是本地維護數據集的開銷,特別是在數據集增長時。這使部署簡單的功能變得容易(如果我們要組合輕量級、無服務器架構和事件流,這一點就很重要),或者因為我們處于無狀態的容器或瀏覽器。

    訣竅是限制這些查詢接口的范圍,理想情況下是在界限上下文中。通常情況下,具有多個特定目標視圖的架構會比單一的共享數據存儲的架構要好。(界限上下文,這里是一組共享相同的部署周期或領域模型的服務。)

    為了限制遠程查詢的范圍,我們可以使用集群上下文模式。這里事件流是上下文之間的唯一溝通模式。但是,上下文中的服務會利用他們所需的事件驅動處理和請求驅動視圖。

    在下面的例子中,我們有三個部分,只通過事件相互溝通。 在每一個內部,我們使用更細粒度的事件驅動流。 其中一些包括視圖層(查詢層)。這平衡了耦合的便利性,允許我們將細粒度的服務與較大的實體相結合; 傳統的應用程序或現成的產品中都存在許多真實的服務場景。


    集群上下文模式

    事件驅動服務的五大優勢:

    • 解耦:如果基于事件,服務可以更容易地插入到現有的事件流中,或者重做工作流的一些子集。

    • 離線/異步流:服務卸下了保證交付給消息協商器(broker)的責任。這使得以事件驅動的方式輕松管理離線任務。

    • 狀態轉移:事件流提供了一種分發數據集的有效機制,因此可以在界限上下文中重構和查詢。

    • 連接:從不同的服務組合/加入/擴充數據集更容易。連接是快速和本地化的。

    • 可追溯性:當有一個中心的、不可變的,保持敘事性的,每次互動隨著時間的推移而日常化的記錄時,調試分布式將變得更加容易。

    總結

    所以在事件驅動的方法我們使用事件代替命令,事件觸發處理。它們也變成我們可以在本地查詢的視圖。我們在必要時回到遠程同步查詢,特別是在較小的生態系統中,但是在較大的系統中我們限制了它的范圍(理想情況下,僅限于單個界限上下文)。

    但所有這些方法只是模式。一起構建系統的指導原則。對于它們,我們不應該太教條化。例如,如果它是很少改變的東西(比如單點登錄服務),一個全局查詢服務仍然是一個好主意。

    訣竅是從事件的基準開始。事件提供了更少的服務機會來將自己相互聯系起來,并且將流程控制轉移到接收者使得更好的分離關注和更好的可插拔性。

    關于事件驅動方法的另一個有趣的事情是,它們對于大型、復雜的架構,和對于小型、高度協作的架構同樣起到很好的作用。事件的支柱為服務提供自由發展所需的自治權。去除了復雜的命令和查詢關系。對于運維工程師來說,系統排查仍然是痛苦的,但是希望不是那么頻繁,至少現在這個故事還有一個腳本!

    但是,隨著所有這些事件的討論,我們談到了很少的分布式日志或流處理。當我們將這種模式與 Kafka 應用時,系統的規則就會改變。協商器的保留特性成為我們可以設計的工具,允許我們接觸外部的數據。某些服務可以參考。

    流式平臺非常自然地與這種模型的處理事件和構建視圖相配。直接嵌入到服務中的視圖,遠程服務查詢的視圖,或視圖實現作為一個持續的流。

    這導致了一系列優化:利用事件流和事件存儲之間的對偶性,混合流式處理工具,篩選敘述,加入來自許多服務的流和實現我們可以查詢的視圖。這些模式正在賦予權力。它們允許我們使用專門用于處理事件流的工具集來重新構想業務處理。但是,所有這些優化都是基于這里討論的概念,僅僅應用于更現代的工具集。

    在下一篇文章中,我們將通過考慮將日志的保留屬性作為我們的服務生態系統的組成部分來使數據更具確定性。我們將數據保存在外部作為可以依賴的中央共享敘事的地方。

    總結

    以上是生活随笔為你收集整理的[译] 基于事件流构建的服务的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。