接口冪等性、分佈式鎖

女神Asuna鎮樓!!
前端

 

在分佈式系統中,如何優雅地使用分佈式鎖?mysql

開始咱們的思惟三部曲,what,why,howredis

首先,what,什麼是分佈式鎖?
咱們常說的鎖,通常指的是給資源加鎖,向外界代表資源正在被某個線程佔用,其它企圖得到這個資源的線程檢測到目標資源被鎖住了,就會輪詢等待直到鎖被佔有者釋放,或者等待必定時間後放棄資源去作其它事情。算法

至於分佈式鎖,是特定於分佈式環境的,多臺機器上的線程都企圖得到同一個資源,這時單機環境的鎖機制就再也不適用,必須用一個外部獨立的第三方管理者協調多臺機器上的線程對資源的搶佔訪問。咱們通常選用redis或zookeeper來擔當這個「第三方管理者」。sql

而後,why,爲何要使用分佈式鎖?網絡

 

最後,how,怎麼使用分佈式鎖?負載均衡

 

一個分佈式系統中的某個接口,該如何保證冪等性?分佈式

假如你有個服務提供一些接口供外部調用,這個服務部署在了 5 臺機器上,其中有個接口就是付款接口。而後用戶在前端上操做的時候,不知道胡亂操做了什麼,意外地針對一個訂單發起了兩次支付請求,而後這兩次請求分散在了這個服務部署的不一樣的機器上,結果一個訂單扣款扣了兩次。spa

或者是訂單系統調用支付系統進行支付,意外地由於網絡超時了,訂單系統走了重試機制,致使支付系統收到一個支付請求兩次,並且由於負載均衡算法落在了不一樣的機器上,結果同樣是重複扣款。線程

雖然上面說的都是機率很小的意外事件,可是隻要出現了,就會帶來很壞的負面影響,客戶會憤怒地投訴。

實際上這樣的場景並非技術問題,也沒有通用的方法,咱們應該結合具體的業務來保證冪等性。

所謂冪等性,就是一個接口,屢次發起同一個請求,接口得保證結果是準確的,好比不能多扣款、不能多插入一條數據、不能將統計值多加了 1。換句話說,請求一次和請求一萬次的產生的做用同樣,這就是冪等性。

其實保證冪等性主要是三點:

  • 對於每一個請求必須有一個惟一的標識,舉個栗子:訂單支付請求,確定得包含訂單 id,一個訂單 id 最多支付一次。
  • 每次處理完請求以後,必須有一個記錄標識這個請求處理過了。常見的方案是在 mysql 中用一個字段來記錄狀態,好比支付以前記錄一條這個訂單的支付流水。
  • 每次接收請求須要進行判斷,判斷以前是否處理過。好比說,若是有一個訂單已經支付了,就已經有了一條支付流水,若是重複發送這個請求,則此時先插入支付流水,orderId 已經存在了,惟一鍵約束生效致使報錯失敗,就不會再繼續執行扣款代碼了。

實際運做過程當中,你要結合本身的業務來,好比說利用 redis,用 orderId 做爲惟一鍵。只有成功插入這個支付流水,才能夠執行實際的支付扣款。

具體的實現邏輯:在支付一個訂單以前,先插入一條支付流水,set order_id unpay,在支付完成後,set order_id payed。其中, order_id 是惟一索引 key ,unpay / payed 是對應的 value(標識是否已經支付完成),當下一個重複的請求過來了,先根據key order_id 查詢對應的 value,若是是 payed 就說明已經支付過了,直接返回支付成功的記錄,若是是unpay,正常調用支付接口進行支付。

相關文章
相關標籤/搜索