冪等性概念認知
釋義
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single. 《rfc2616 - 9.1.2 Idempotent Methods》
以上是摘自HTTP1.1標準中有關冪等性的介紹,大致內容為,除開網路錯誤以及請求超時的問題,請求同一個介面多次和單次,對資源所造成的影響是一致的。
這裡需要注意的是,冪等性關注的是對資源造成的影響,而非請求返回的結果。
例如我們設計了一個GET
介面api/getSystemTime
,用於返回伺服器的實時時間,雖然每次返回的結果都是不一樣的,但是對伺服器來說並沒有發生資源變動,所以也是冪等的。
一般來說,GET
、OPTIONS
、HEAD
、DELETE
這些請求方法都是冪等的,因為對伺服器資源都是沒有影響的,或是產生的影響是一致的。像POST
、PUT
、PATCH
這些請求方法一般都是非冪等的。
當然,有一些業務場景下,我們需要用到POST
介面,同時也要保證冪等性,我們也可以自己實現介面的冪等性。
場景
一般我們定義冪等性介面的使用場景是防止出現請求多次而導致的服務結果不一致的情況。例如付款介面,使用者在前端可能因為點選多次,發起了多次請求,如果這個時候介面不做好冪等性的話,可能會出現多次付款的情況。
思路
Token方式
實現冪等性可以從控制資源訪問的次數下手。
即使有多個請求過來需要請求支付,我們只需要允許其中一次請求進行完整的支付流程,其他請求均放棄即可。
這樣我們可以延伸出token
的概念。
假設我們的系統由訂單系統和支付系統兩部分組成,當我們提交訂單後,由訂單系統向支付系統申請一個token,支付系統在生成後返回這個token,同時將token存至Redis快取中。這樣當我們向支付系統發起支付請求時,帶上這個token,支付系統需要先判斷一下在快取中是否存在這個token,如果存在則刪除這個token,同時繼續執行支付邏輯;如果快取中不存在這個token,則返回業務錯誤。
這裡的token類似於一個信物,只有持有這個信物的人才允許被放行,放行後,這個信物也不被信任,下次即使有攜帶相同信物來的人,也不給放行。
題外話
寫到最後,突然想起來為啥要研究這個冪等性
來著。
當時是在一個客戶現場出現的生產問題,我們的應用程式,通過nginx
往演演算法服務傳送一個POST請求後,在經過大概10分鐘,演演算法突然又被呼叫了一次,且收到的引數和第一次一摸一樣。一開始以為是應用程式的問題,在公司的測試環境模擬了一遍,沒有復現,後來懷疑可能是nginx
做的鬼,問了現場,才知道現場使用的nginx
版本是1.8.1
(吐槽一下版本有點老)。然後在網上查閱資料,得知1.9.13以前版本的nginx預設會將POST等非冪等請求做超時重試處理。雖然我們的應用程式在往演演算法發起請求後,就不會再做什麼後續處理,但坑的是演演算法會保持這個請求也不返回資料,導致nginx
認為請求超時了,又發起了一波請求,血與淚哦。
由於不能讓現場升級nginx,所以我們只能讓現場在nginx
中加大了那個演演算法介面的超時時間。
下面摘自nginx
官方檔案。
normally,requests with a non-idempotent method (
POST
,LOCK
,PATCH
) are not passed to the next server if a request has been sent to an upstream server (1.9.13); enabling this option explicitly allows retrying such requests;