通過 Dapr 實現一個簡單的基於 dotnet 的微服務電商系統——一步一步教你如何擼 Dapr 之訂閱發佈

 之前的章節我們介紹瞭如何通過 dapr 發起一個服務調用,相信看過前幾章的小夥伴已經對 dapr 有一個基本的瞭解了,今天我們來聊一聊 dapr 的另外一個功能——訂閱發佈

目錄:
一、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統

二、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (二)——通訊框架講解

三、通過 Dapr 實現一個簡單的基於. net 的微服務電商系統 (三)——一步一步教你如何擼 Dapr

附錄:(如果你覺得對你有用,請給個 star)
一、電商 Demo 地址:https://github.com/sd797994/Oxygen-Dapr.EshopSample

二、通訊框架地址:https://github.com/sd797994/Oxygen-Dapr

  慣例我們還是再老生常談一下什麼是訂閱發佈,訂閱發佈是根據設計模式之觀察者模式發展出來的一種軟件系統設計思想,它的核心是指 “多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新”。假設一個系統有 ABC 三個模塊其中 BC 依賴於 A,當 A 進行改變後需要 A 主動調用 BC 進行相應改變,而觀察者模式則將 A 的控制權剝離,A 改變之後只是發送一個事件給消息總線 “我改變了”,BC 通過預先訂閱該主題而獲取到 A 的狀態變化,再進行自身的狀態變更。

強耦合調用模式

通過消息中間件訂閱發佈模式

  聰明的同學應該發現了,通過訂閱發佈其實我們是將以往強耦合的 ABC 通過巧妙的控制權轉移的方式進行了解耦,由之前的 BC 依賴於 A 改爲了 BC 依賴於消息組件,通過消息組件接受到 A 的消息後進行分發,這樣設計系統的目的當然有好有壞,好處是這會大大提高 A 的吞吐量,假設以往操作 ABC 總耗時 300ms 平均單個操作耗時 100ms,通過解耦後 A 耗時 100ms 後就可以馬上返回線程。那壞處是什麼呢,由於對 BC 進行了解耦往往狀態的一致性就得不到保障了。當 ABC 處於同一個粗粒度的原子操作裏(比如數據庫事務操作、比如 lock 鎖),我們很容易控制 ABC 的強一致性,ABC 有一個操作失敗可以很輕鬆的進行回滾而不用影響我們持久化設備的數據一致。另外由於需要依賴第三方中間件,整個系統的健壯性是會有一定影響的。另外還需要考慮訂閱方消費失敗、異常後如何處理。關於這部分內容這裏我們就不展開了,如果大家確實感興趣,推薦大家看看國內開源作者 @楊曉東寫的. netcore 分佈式一致性解決方案 CAP,地址:https://github.com/dotnetcore/cap

  OK,老生常談的部分嘮完,咱今天就來嘮嘮在 Dapr 中如何實現訂閱發佈的。通過上面的部分大家應該知道如果要實現一個進程間的訂閱發佈系統,我們需要準備很多東西,其中一個是事件總線,事件總線的作用是讓事件發佈者可以通過該模塊進行事件發佈。第二個需要選型一個消息組件,第三需要訂閱器對訂閱特定類型組件的技術支持。由於每一種組件其協議和接口實現方式都不同,在傳統的訂閱發佈設計中我們往往需要對某種特定類型的消息組件在基礎設施層進行相應的 SDK 集成,通過爲業務層提供事件總線接口和訂閱接口來進行技術解耦。就算做到了業務系統中不耦合技術實現,往往我們也很難替換消息組件。而 Dapr 在這方面爲開發者集成了相當一部分的主流訂閱發佈組件 (通過該支持列表可預覽支持)。同時在業務層面是完全基於 http + 謂詞的形式來實現訂閱發佈的。這就大大降低了引入 SDK 產生的成本。

  訂閱發佈的 API 如下:

POST http://localhost:<daprPort>/v1.0/publish/<pubsubname>/<topic>[?<metadata>]
GET http://localhost:<appPort>/dapr/subscribe

  稍微說一下這兩個接口的含義,第一個接口告訴 sidecar,我們將會調用某個已申明的類型爲 pubsub 的 component 發送我們的事件到特定的 topic

  第二個接口是告訴 sidecar 我們當前這個服務會訂閱哪些 topic,我們提供的訂閱器入口地址是什麼,我們只接受哪一個 component 發佈的數據

  也就是說和服務調用一樣,我們只需要一個 weapi+httpclient 就可以實現一個訂閱發佈模式而,其他的一切都交給 dapr 好了。

  現在我們來看看如何實現它,首先我們還是需要選一個特定的訂閱發佈組件,這裏我就選擇 redis,通過 redis5.0 新增的 stream 來做訂閱發佈。搭建 redis 這裏不贅述,搭建好之後,我們需要創建一個 dapr 的特定 CRD Component 來申明引用該組件,其申明 yaml 文件如下

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis.infrastructure.svc.cluster.local:6379

  其中的 type 是由 Dapr 預定義的, 可以參考這裏,不要隨意改變。metadata 是對組件的一組描述包括其地址、賬號密碼等等,由於是演示這裏我就直接使用 k8s 創建了一個無密碼的 redis pod 並暴露其 6379 端口到 svc。當我們創建好並通過 kubectl apply -f x.yaml 後,可以在 dashboard 的 Componsents 頁面觀察是否已經創建成功

  基礎設施準備完畢,接下來就是打開我們的項目看看如何實現訂閱發佈了。首先我們還是要把上一章的解決方案打開,上一章不是通過 client 發起一個對 service 的調用嗎,今天我們反着來演示,我們在 client 創建一個訂閱器,當 clientsample 調用 servicesample 時讓 servicesample 發佈一個事件,由該訂閱器訂閱並打印出文本到控制檯。

  首先我們在 clientsample 創建一個訂閱器,訂閱器類必須繼承 ieventhandle 接口,其訂閱方法體必須添加 EventHandlerFunc 註解並申明需要訂閱的主題 (topic),訂閱器接收參數必須以 EventHandleRequest 的方式接收,否則反序列化器可能會收不到請求。最後 ack 必須以 DefaultEventHandlerResponse.Default 的方式返回,否則事件總線會認爲本次訂閱器消費失敗,會重複推送。

   需要在我們的 hostbuilder 裏註冊這個對象到 ioc 容器:

  接着我們在 RPC 接口項目創建事件 Data HelloEventData, 其中之包含一個演示用的 words 字段 (圖略)。

  接下來我們在上一章的 HelloServiceImpl 中注入一個事件總線,併發送事件:

   一切就緒,我們重新按照上一章的內容打包並部署,然後開啓 postman 和控制檯日誌觀看結果,可以看到我們的 clientsample 發起一個服務調用後,我們的 serversample 回調併發送了事件,而 clientsample 成功訂閱到了該事件並消費掉了。

   今天的分享到此爲止,demo 只是對 dapr 訂閱發佈最基礎功能的演示,真正到生產環境還需要客服諸多問題來提高系統健壯,系統建設是一個長期持續的過程。歡迎大家評論區留言討論~ 下期我們將講一下 dapr 裏如何做狀態管理以及 actor 模型

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/AH7V_MI-oqJNnu1ljlI_TA