本系列故事的全部案例和解決方案只是筆者之前在互聯網工做期間的一些事例,僅供你們參考,實際操做應該根據業務和項目狀況設計,歡迎你們留言提出寶貴的意見java
小王和小明分別維護分佈式系統中A、b兩個服務,有一個場景是 A服務會向B服務經過MQ發送事件而且推送用戶信息,而後B服務保存用戶信息。
spring
有一天,小王和小明由於一件事討論得熱火朝天、各執己見,事情由來以下:數據庫
這時候,在一旁掃地的清潔工老梁過來調解,並幫忙排查分析,致使這個問題的主要緣由以下:服務器
僞代碼以下:網絡
@RabbitHandler public void handle(byte[] message) { try { t = parseBody(messageStr); } catch (Exception e) { log.error("消費消息失敗", e.getCause()); } } private void handleMessage(T t) throws MQHandleException { //惟一標識 String key = t.getLockedId(); //獲取鎖 DistributedLock lock = DistributedLockFactory.getLock(key); try { // 解決分佈式服務提交相同資料併發問題 lock.lock(CacheConstants.LOCK_WAIT_TIME, CacheConstants.LOCK_LEASE_TIME, CacheConstants.DEFAULT_CACHE_UNIT); // 處理業務邏輯 handleBusinessLogic(t); } catch (LockException e) { throw new MQHandleException(e); } finally { // 釋放鎖 lock.unLock(); } }
頻繁Redis超時是由於A、B服務共用一個Redis,A服務Key太多把Redis內存資源佔滿了(也可能鏈接佔滿),致使了B服務常常出現鏈接超時(該故障不是本章主要關注目標)
架構
B服務在已經成功接受到消息後,沒有把消息先保存起來,因此也致使了自身並無能力重跑併發
清潔工老梁跟小王和小明進行一番詳談後,瞭解到他們主要需求有兩個:框架
通過上面的分析,老梁的解題思路主要分爲兩個方向:分佈式
通常來講,常見的微服務架構實現最終一致性有三種模式:可靠事件模式、業務補償模式、TCC模式。這裏AB服務是經過業務補償模式實現最終一致性,但這裏又跟咱們通常的分佈式架構的事務問題不一樣,這裏咱們只須要保證B服務能最終把正常消息事件消費成功便可。微服務
實現思路:
針對於B服務,對於收到的MQ信息沒有進行有效的記錄,並且MQ信息處理以後,存在修改錯誤,無法進行對應信息補充修復的功能,增長通用消息處理層,進行消息體的記錄和回溯。 在獲取消息以後進行一次記錄,進行冪等操做和對應的狀態更新, 消息狀態在業務相關操做完成後,標記爲處理完成,認爲對應消息狀態結束。
這裏hash_value是對請求體進行hash計算得出來的一個值,例如:MD五、SHA-2,保證每一個不一樣請求的hash碼不同,相同的請求hash碼相同,能夠用於冪等控制。
表大體操做流程:
異常消息有4個狀態
待處理
處理中
處理完成
異常
,等待後期人工重跑失敗事件隊列在這裏是採用數據庫表代替
由於並不是全部的異常都能重跑就能解決問題,咱們只能針對能夠修復的異常進行重試,這裏把異常分爲兩大類:
最後小明負責的B服務按照老梁的思路,從新調整了代碼,異常處理流程以下: