在 Microservices Patterns (可參考 https://microservices.io) 這本書中提到微服務間的通信可以簡單分為兩類:
- 同步通信
- 非同步通信
同步其實就是我們熟知的打 API,如 Restful 或 gRPC。使用起來簡單直覺,只要以前有設計過 api 的人都可以簡單上手。但主要缺點如下:
- 可用性低
假想現在對外有一隻 API,打他時後端程式碼必須同時也對 A 和 B service 打 API 下指令。架設 A 可用性 97%,B可用性 95%,整體其實只有 97% x 95% = 92%。只要其中一個服務壞掉,整個 API 就爆了 - 需要給定 API 的 url 位置
如果是使用 kubernetes 等自動管理架構,他會幫你處理掉服務發現的問題,這個缺點就會消失。如果沒有使用它而是自己管理的話,只要移動 container 到不同的機器,ip 就會改變。所有打這個微服務的程式碼都需要做修改。(假如你有使用參數外置的手法,如使用 AWS SSM,那可能只需要去 SSM console 修改一次即可。但還是有人為疏失忘記的可能。)
其它缺點可以直接參考書中內容,這邊就不再贅述。
非同步通信,通常會透過一層消息代理來做中介,負責接收生產者發佈的消息,並派發到訂閱的消費者手中。如 Kafka 或 RabbitMQ 都是常見的消息代理。用這種方式處理訊息傳送有以下好處:
- 松耦合
因為是透過第三方,也就是消息代理,幫你把訊息散播出去,生產者不需要知道要發給誰,也不用擔心消費者突然當掉會影響到自己的可用性,耦合度低,可用性也能提高。
- 消息緩存
訊息發布後會暫存在代理身上。假設剛好發佈的當下消費者死掉,只要他再度復活,代理就會把他沒收到的訊息再次發送給胎他。如此訊息不漏接,可以降低出問題後的所需的復原時間。
其他好處可以參考書本。但同時也會有幾個壞處:
- 消息代理的可用性必須很高
因為所有的訊息都必須透過他來傳送,如果他掛了,想當然爾大家也只能一起葬送。所以通常會起集群,提高可用性。
- 開發上較複雜
使用代理的手法,和以往開發 API 的方式不一樣,非同步處理比較不好思考,需要一些時間去練習增加經驗
不過壞處 1 我覺得好解決,如果是 AWS 可以使用 MSK 服務,把 kafka 託管給他們,解決掉複雜的架設以及集群的維運管理。一切只需要透過 web console 就可以簡單監控操作。架設跨 availability zone 的集群也很簡單,不用再手動一一輸入每個 kakfa 機器的位置,實在太方便!
書中也提到,通常內部通訊會伴隨著資料改變。比如說今天使用者下一筆訂單,所以訂單服務要做兩件事:
- 對資料庫寫入一筆新訂單資料
- 同時發布新訂單的訊息到 kafka
假如寫入資料庫到發布訊息是透過程式碼來控制的兩個動作,就很有可能在中間發生 exeption,導致資料庫寫入新訂單,但是訊息沒發出來!解法是透過關聯式資料庫的原子性來處理。此時資料庫中需要多建立一張表,比如說 outbox,裡面存放要發到 kafka 的訊息資料。把剛剛的兩件事改成
- 對資料庫寫入一筆新訂單資料
- 對資料庫寫入發布新訂單的訊息
並且把這兩步包成同一個 transaction,這樣就能透過原子性,只要成功建立新訂單,就能保證有寫入新訂單訊息。
但問題來了,那要怎麼把訊息發布到 kafka?
書中提到比較好的方式是 tailing database transaction log,透過另一套服務監控資料庫日誌,只要發現有資料異動,就將資料發布到 kafka。書中有提到很多服務,這邊我們選用 Debezium。
Debezium 使用的方式是 CDC (Change Data Capture),透過這個技術來監控給定的資料表,一但有所變動,就將變動透過 Kafka Connect 發布至 Kafka,消費者註冊這些 topic,就可以收到最新變動的資料。
可能有人會疑問,那如果 Debezium 掛掉怎麼辦?這不用擔心,資料庫端和 Debezium 都會記錄最後同步到哪一筆資料,只要將 Debezium 重啟,他就能接續串流資料出來!不必人為重新設定。
所以整合來說是這樣的流程:
- 使用者下訂單
- 訂單服務將訂單資料,和新訂單訊息包成一個 transaction 存到資料庫
- Debezium 透過 CDC 監控訊息表,得知有一個新訂單訊息被寫入,於是把他的資料發布到 Kafka 的特定 topic
- 其他微服務,如出貨服務,已經事先訂閱此 topic,就會收到此事件,他就可以去做應有的邏輯
基本架構與原理大致是這樣,下一篇 Kafka + Debezium 串流 DB – 實戰步驟 就會分享我架設的經驗,希望能為大家減少試錯的時間!
延伸閱讀:Kafka + Debezium 串流 DB – 實戰步驟