使用消息中間件完成用戶註冊

        作者:birkhoff001

       我們從一個簡單的實例入手. 基本所有互聯網應用都會有用戶註冊的功能. 在這個例子中, 我們對於用戶註冊有兩步操作:
1. 註冊成功, 保存用戶信息.
2. 需要給用戶發放一張代金券, 目的是鼓勵用戶進行消費.
如果是一個單一架構應用, 實現這個功能非常簡單: 在一個本地事務裏, 往用戶表插一條記錄, 並且在代金券表裏插一條記錄, 提交事務就完成了. 但是如果我們的應用是用微服務實現的, 可能用戶和代金券是兩個獨立的服務, 他們有各自的應用和數據庫, 那麼就沒有辦法簡單的使用本地事務來保證操作的原子性了. 現在來看看如何使用事件機制和消息隊列來實現這個需求.(我在這裏使用的消息隊列是kafka, 原理同樣適用於ActiveMQ/RabbitMQ等其他隊列)

我們會爲用戶註冊這個操作創建一個事件, 該事件就叫做用戶創建事件(USER_CREATED). 用戶服務成功保存用戶記錄後, 會發送用戶創建事件到消息隊列, 代金券服務會監聽用戶創建事件, 一旦接收到該事件, 代金券服務就會在自己的數據庫中爲該用戶創建一張代金券. 好了, 這些步驟看起來都相當的簡單直觀, 但是怎麼保證事務的原子性呢? 考慮下面這兩個場景:
1. 用戶服務在保存用戶記錄, 還沒來得及向消息隊列發送消息之前就宕機了. 怎麼保證用戶創建事件一定發送到消息隊列了?
2. 代金券服務接收到用戶創建事件, 還沒來得及處理事件就宕機了. 重新啓動之後如何消費之前的用戶創建事件?

wKioL1lwJjPShJh6AACWtoZPD68135.png


EventPublish是記錄待發布事件的表. 其中:
id: 每個事件在創建的時候都會生成一個全局唯一ID, 例如UUID.
status: 事件狀態, 枚舉類型. 現在只有兩個狀態: 待發布(NEW), 已發佈(PUBLISHED).
payload: 事件內容. 這裏我們會將事件內容轉成json存到這個字段裏.
eventType: 事件類型, 枚舉類型. 每個事件都會有一個類型, 比如我們之前提到的創建用戶USER_CREATED就是一個事件類型.
EventProcess是用來記錄待處理的事件. 字段與EventPublish基本相同.


1. 用戶服務在接收到用戶請求後開啓事務, 在用戶表創建一條用戶記錄, 並且在EventPublish表創建一條status爲NEW的記錄, payload記錄的是事件內容, 提交事務.
2. 用戶服務中的定時器首先開啓事務, 然後查詢EventPublish是否有status爲NEW的記錄, 查詢到記錄之後, 拿到payload信息, 將消息發佈到kafka中對應的topic.
發送成功之後, 修改數據庫中EventPublish的status爲PUBLISHED, 提交事務.


1. 代金券服務接收到kafka傳來的用戶創建事件(實際上是代金券服務主動拉取的消息, 先忽略消息隊列的實現), 在EventProcess表創建一條status爲NEW的記錄, payload記錄的是事件內容, 如果保存成功, 向kafka返回接收成功的消息.
2. 代金券服務中的定時器首先開啓事務, 然後查詢EventProcess是否有status爲NEW的記錄, 查詢到記錄之後, 拿到payload信息, 交給事件回調處理器處理, 這裏是直接創建代金券記錄. 處理成功之後修改數據庫中EventProcess的status爲PROCESSED, 最後提交事務.

回過頭來看我們之前提出的兩個問題:
1. 用戶服務在保存用戶記錄, 還沒來得及向消息隊列發送消息之前就宕機了. 怎麼保證用戶創建事件一定發送到消息隊列了?
根據事件發佈的順序圖, 我們把創建事件和發佈事件分成了兩步操作. 如果事件創建成功, 但是在發佈的時候宕機了. 啓動之後定時器會重新對之前沒有發佈成功的事件進行發佈. 如果事件在創建的時候就宕機了, 因爲事件創建和業務操作在一個數據庫事務裏, 所以對應的業務操作也失敗了, 數據庫狀態的一致性得到了保證.
2. 代金券服務接收到用戶創建事件, 還沒來得及處理事件就宕機了. 重新啓動之後如何消費之前的用戶創建事件?
根據事件處理的順序圖, 我們把接收事件和處理事件分成了兩步操作. 如果事件接收成功, 但是在處理的時候宕機了. 啓動之後定時器會重新對之前沒有處理成功的事件進行處理. 如果事件在接收的時候就宕機了, kafka會重新將事件發送給對應服務.


歡迎訪問肖海鵬老師的課程中心:http://edu.51cto.com/lecturer/user_id-10053053.html

歡迎加入肖海鵬老師技術交流羣:2641394058(QQ)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章