搭個微服務(二)與錯共舞

2021-08-21 10:43:40 字數 2082 閱讀 2112

如果你是學院派,玩微服務必須dubbo,zookeeper不離手,業務保證100%可用,那本文就不是為你寫的啦。

網路間發生抖動

某個服務發生異常,導致依賴它的服務異常

某個服務正在重啟

上文說到,所有的微服務都必須保證:內部一致,外部冪等。這是重試失敗請求的保證。

在實踐中遇到網路錯誤,如果是get請求就可以毫不猶豫的重試,前提是:get方法不能對持久資料有任何影響。

for i in range(5):

# 重試5次,看你能不能成功

try:

ret = await fetch_json(url)

...except:

await sleep(1)

continue

像這樣醜陋的**,甚至可以直接寫到fetch_json這樣的底層工具上。大膽放心的用吧。

如果是post的請求失敗,那情況就會複雜很多。此時,需要在服務設計之時就保證內部一致性和冪等性,也就是:

如果b服務接收到a服務的請求,那b服務就一定能執行完畢。

在乙個session中,無論a呼叫多少次b服務的介面,b服務都只響應一次

保證一致性需要從業務具體分析,但保證冪等非常簡單。引入flow_no流水號即可。

a服務呼叫b服務,生成唯一流水號並傳給b, flow_no=123

b服務得到響應,將123設定為finished

a服務網路錯誤,重試,使用相同的流水號 , flow_no=123

b 響應前先查詢流水號,發現123已被使用,返回「已完成」錯誤碼(看需求,也可以返回之前計算結果)。

當服務a重啟的時候,假如a還有任務尚未完成,那sigterm訊號可能會直接打斷這次任務。這會造成難以挽回的資料不一致。

大部分網路框架都提供了graceful killer的功能,讓程序安全的退出。但必須警惕自己實現的「生產」「消費」模式。確保每個程序都能優雅的退出。類似這篇文章《python:優雅的退出程式或重啟服務》

使用rabbitmq或redis等高速持久化佇列,而不是將任務資訊儲存在記憶體佇列中是乙個比較好的做法。

微服務資料一致性的問題,總的來說是乙個可信發布的問題。當上面簡單的策略都無法完成業務的需求,那就只能啟動容錯。

比如完成操作a實質上需要進行b,c,d三個操作:

-> b

a -> c

-> d

此時需要有一種機制,當b,c,d中任何乙個操作沒有完成,則將a操作標記為失敗。同時啟動容錯機制

比如以下提現業務:

使用者賬號 coin 扣除 500金幣

呼叫第三方介面,給該使用者打錢0.5元

插入一條提現日誌到withdrawlog

此業務需要呼叫3個服務:coin,wetchat,withdraw。更何況支付服務是第三方的,根本無法控制。

所以,在進入提現流程前,需要對這個任務進行跟蹤,並記錄中間狀態。具體上:

進入提現 建立 monitor_log , status = withdraw_pre_doing

鎖定該使用者的金幣,此時使用者不能再進行金幣相關操作,確保第三方賬戶裡有足夠的錢。

使用者賬號 coin 扣除 500金幣 成功: status = withdraw_already_pay_coin

呼叫第三方介面,給該使用者打錢0.5元 成功: status = withdraw_already_pay_wx

插入一條提現日誌到withdrawlog 成功: status = withdraw_done

這種設計,實質上是基於訊息的分布式事務,它可以保證最終一致性。實作中會每隔一段時間啟動monitor的回滾,選取所有中間狀態不為done的monitor。然後呼叫各服務對應的容錯操作,在容錯操作中,會讀取monitor記錄的資訊,使用合適的方式使資料一致。並且,所有被標記為資料損壞的使用者,在資料一致前都不能有進一步的操作。艱苦的過程就要來臨。

注:要實現monitor,redis的天然原子操作和高效能絕對是不二之選。

注:由於保證服務內部的acid,並且鎖定了資源(coin和第三方賬戶)。容錯操作很可能只是給失敗的服務重新傳送了一次請求。

微服務與微服務架構

微服務 微服務強調的是服務的大小,它關注的是某乙個點,是具體解決某乙個問題 提供落地對應服務的乙個服務應用,狹意的看,可以看作eclipse裡面的乙個個微服務工程 或者module。例如 訂單服務 支付服務 微服務架構 馬丁.福勒 martin fowler 微服務架構介紹 微服務架構是 種架構模式...

SpringCloud 微服務與微服務對接心德

對方已經提供好乙個api文件,然後傳一堆傳輸,返回給我一些資訊。如下 我這邊建立實體類,返回值這些東西,如下 介面如下 feignclient還有以下標籤 name 指定feignclient的名稱,如果專案使用了ribbon,name屬性會作為微服務的名稱,用於服務發現 url url一般用於除錯...

微服務二 RPC

什麼是rpc?rpc指遠端過程呼叫,簡單的理解就是像呼叫本地方法一樣,呼叫其他伺服器中提供的方法。rpc的呼叫過程 1.客戶端client發起服務呼叫請求 2.client stub可以理解成乙個 將呼叫的方法 引數按照一定格式進行封裝,並且通過服務提供的位址,發起網路請求 3.訊息通過網路傳輸到服...