通過Dapr實現一個簡單的基於.net的微服務電商系統(四)——一步一步教你如何擼Dapr之訂閱釋出

a1010發表於2021-04-16

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

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

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

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

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

附錄:(如果你覺得對你有用,請給個star)
一、電商Demo地址

二、通訊框架地址

  慣例我們還是再老生常談一下什麼是訂閱釋出,訂閱釋出是根據設計模式之觀察者模式發展出來的一種軟體系統設計思想,它的核心是指“多個物件間存在一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新”。假設一個系統有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<T>的方式接收,否則反序列化器可能會收不到請求。最後ack必須以DefaultEventHandlerResponse.Default的方式返回,否則事件匯流排會認為本次訂閱器消費失敗,會重複推送。

   需要在我們的hostbuilder裡註冊這個物件到ioc容器:

  接著我們在RPC介面專案建立事件Data HelloEventData,其中之包含一個演示用的words欄位(圖略)。

  接下來我們在上一章的HelloServiceImpl中注入一個事件匯流排,併傳送事件:

 

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

 

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

  

相關文章