系統冪等設計

前言

冪等簡單的定義:redis

系統中的屢次操做,無論多少次,都應該產生同樣的效果,或返回同樣的效果。數據庫

好比實際的業務請求爲建立一個活動,理論上須要根據業務形態開發冪等建立活動的接口,這樣在相同參數調用接口屢次建立活動時,只能夠建立成功一次。安全

因爲查詢天生的是冪等請求,因此針對於查詢場景能夠不作業務角度的冪等約束,查詢冪等的約束可能是針對於資源控制,安全防刷,流控來作的。分佈式

一個場景

試想有這樣一個場景:
A系統傳遞userId和活動Id調用B系統發券,若是B系統發券成功,須要返回A系統本次發券userId和發券code。
因爲B系統須要對本身發出去的券進行限制防止超發,因此會根據userId和code創建冪等攔截。
可是A系統的調用次數是不受信的,B系統會對屢次重複的請求作攔截,這樣形成一部分A的請求爲無效請求,被直接打回。
可是A系統接受B系統的返回值中是須要code的,若是沒有收到code,A系統會認爲調用B系統失敗,進行重試,結果就形成了A系統不停被重試,B系統攔截無效請求,返回默認值,A再重試的死循環。優化

解決這個場景問題有兩種方法:設計

  • 在B系統識別到A重複請求時,須要查詢流水錶,返回已經發送的code,組裝參數返回A系統,A系統識別到code,作本地記錄,再也不調用B系統發送。
  • A系統調用B系統發券這個邏輯拆分紅兩個接口,發券接口調用和查詢發券記錄。

第一種方案明顯的缺點在於,針對於重複發送的請求都會轉化成一次查詢操做,這樣無形中加大了對於B系統資源的浪費,同時因爲發券接口邏輯中引入了查詢邏輯,形成此接口違反了「單一職能原則」,在將來圍繞這個接口的新業務邏輯形成的代碼修改時,好比容許對同一個用戶發送多張券,可能出現潛在的bug問題。code

第二種方案則是我選擇的更好的方案,也是更支持的方案,一個接口最好只作一件事,這樣一個接口只作發券,同時對於屢次重複發券作請求攔截,沒有必要放無效請求到系統核心邏輯中,更沒有必要所以引入查詢邏輯消耗系統資源。
在調用B系統發券接口由於攔截重複請求,返回重複請求狀態碼後,系統A調用B系統的查詢接口,進行已發送code的查詢,這樣在使用角度和後期業務迭代角度及系統資源使用和將來優化角度來講,都存在必定的空間,而不會形成代碼複雜度提高引入隱患bug。索引

總結

針對於冪等操做還有以下幾種方案:token

  • 刪除/修改操做,必定要帶入版本號和原始修改參數,萬不可直接在下游邏輯中直接i++,i--
  • 爲進一步攔截真實數據羅庫,須要在數據庫表中建立惟一約束,防止由於分佈式系統鎖問題或數據不一致問題致使攔截不到,這樣在DB層創建最後一次兜底策略
  • token機制,能夠作相似於頁面重複提交的功能,token能夠放到redis中,並自帶實效
  • 悲觀鎖/樂觀鎖,通常分爲分佈式鎖,單機鎖,update where
  • 有限狀態機,訂單系統通常都會設計一個訂單狀態流轉的狀態機,表述在不一樣狀態下的狀態變動,只有在上一個狀態知足時,纔會進行接下來的狀態變動,這樣保證了狀態變動的冪等性
  • 接口調用最好引入來源source,序列號seq等信息,能夠用source+seq作惟一索引,也能夠將這兩個值上報作好監控
  • 監控和開關,爲能夠更直觀的觀察系統冪等狀況,能夠創建對應的監控大盤,及告警配置,這樣能夠更直觀的發現問題,同時配置相應的開關,在發現問題時好比被刷時,經過調控開關及時止損。

相關文章
相關標籤/搜索