什么是冪等(idempotency)?簡單一點說宋下,一個操作如果具有任意多次執(zhí)行所產(chǎn)生的影響與一次執(zhí)行產(chǎn)生的影響相同,就是冪等辑莫。
這樣來說学歧,似乎也很容易理解。但是要知道摆昧,這樣的定義撩满,其實是一個語義范疇內(nèi)對行為結(jié)果的定義。如果用語法和規(guī)則去確保行為能達(dá)到這個結(jié)果,往往需要很謹(jǐn)慎的設(shè)計與實現(xiàn)伺帘。在系統(tǒng)中昭躺,冪等是一個很重要的概念。無論是在大型的互聯(lián)網(wǎng)系統(tǒng)還是企業(yè)級應(yīng)用伪嫁,REST API都被廣泛使用领炫。而正確的使用冪等,是API技術(shù)中極其重要的一個技術(shù)點张咳。
為什么說非常重要帝洪?日常生活中,支付是最常見的交易場景脚猾。比如我們在給支付寶發(fā)送一筆付款請求時葱峡,正常情況下,用戶扣款成功龙助,支付寶返回支付成功的信息砰奕。但是如果發(fā)生異常怎么辦?比如客戶端發(fā)出請求后提鸟,請求超時军援,你沒有收到下游系統(tǒng)的處理結(jié)果,那到底是成功還是失敗称勋,或者其它情況胸哥。
請求超時的情況也分很多種:
1、這個請求到達(dá)支付寶前端之前就發(fā)生了超時赡鲜,也就是支付寶根本就不知道有這筆訂單的存在空厌,也就是通常說的漏單。
2蝗蛙、支付寶已經(jīng)收到了這個請求蝇庭,但是支付失敗,這時發(fā)生超時異常捡硅,支付寶處理失敗哮内。
3、支付寶收到了這個請求壮韭,并且支付也成功北发,但這時候還是發(fā)生了超時,支付寶處理成功喷屋,但時沒有回執(zhí)琳拨。
4、支付寶收到了這個請求屯曹,支付也成功狱庇,并且發(fā)送了回執(zhí)惊畏,但因為網(wǎng)絡(luò)但原因客戶端沒有收到,客戶端超時密任,所以并不知道處理結(jié)果颜启。
遇到這種情況怎么辦?常見但做法是重試機(jī)制浪讳,重試機(jī)制有幾種方案缰盏,這里不展開。但是有一個存在的問題淹遵,請求超時是上面的那一種口猜,會不會造成重復(fù)交易的問題?這就涉及到冪等性問題透揣。
那么冪等又該如何實現(xiàn)呢济炎?多次執(zhí)行所產(chǎn)生的影響和一次執(zhí)行產(chǎn)生的影響相同。簡而言之淌实,我們需要一個去重的機(jī)制冻辩,這往往有很多實現(xiàn)方法,但有兩個很關(guān)鍵的因素:
1拆祈、冪等令牌。也就是說客戶端和服務(wù)端通過什么來識別是同一個請求倘感,或者是一個請求嘗試多次放坏。這一般需要客戶端和服務(wù)端協(xié)議,通常由客戶端來產(chǎn)生令牌老玛。
2淤年、確保唯一性。服務(wù)端通過什么來確認(rèn)是同一個請求蜡豹,也就是說怎么確認(rèn)請求的唯一性麸粮,這通常使用數(shù)據(jù)庫來實現(xiàn)。把冪等令牌作為數(shù)據(jù)庫列的唯一索引镜廉。但當(dāng)有兩個同樣的冪等令牌到達(dá)時弄诲,必然有一個會失敗。注意一點娇唯,簡單的讀檢查并不一定行齐遵,因為讀與讀之間存在競爭條件,因此有可能出錯塔插。
如果一個系統(tǒng)能正確的處理上面兩個要素梗摇,那基本上就能達(dá)到冪等等要求。那么現(xiàn)實系統(tǒng)中想许,常見等問題都出現(xiàn)在哪里呢伶授?
1断序、冪等令牌什么時候產(chǎn)生,怎么產(chǎn)生糜烹?這一點很重要逢倍。還是拿上面等例子來說,支付寶能確定對每一筆支付請求只執(zhí)行一次景图,那它必然有一個唯一標(biāo)識來區(qū)分较雕。假如客戶端對同一筆對多次請求,每次請求的冪等令牌都不一樣挚币,那支付寶也確認(rèn)不了這是同一筆交易亮蒋。
2、令牌有沒有可能被誤刪的可能妆毕。這是上面的一種特殊情況慎玖。冪等令牌是由客戶端生成的,那么如果客戶端在使用完令牌后笛粘,不小心因為DB rollback等原因被刪除啦趁怔。這時客戶端就不知道之前已經(jīng)發(fā)送過一次交易。這時候就有可能產(chǎn)生一筆新的交易薪前,并產(chǎn)生一筆新的訂單润努,服務(wù)端對此時毫無感知。所以這個必須客戶端來保證示括。
3铺浇、各種競爭條件。上面說的用DB讀來確保唯一性經(jīng)常因為競爭不工作垛膝。其實一個實現(xiàn)冪等等系統(tǒng)中鳍侣,各個環(huán)節(jié)都需要配合實現(xiàn),都需要考慮競爭條件吼拥。
4倚聚、對服務(wù)對重試處理,一般都是服務(wù)端實現(xiàn)的凿可。一個常見的做法是要區(qū)分正在處理中惑折,處理成功,處理失敗矿酵。這樣當(dāng)客戶端重新請求時唬复,根據(jù)具體情況是直接返回還是再次處理。
5全肮、一個系統(tǒng)中有多個冪等敞咧。一個是說服務(wù)端不是由一個系統(tǒng)實現(xiàn)的,A系統(tǒng)發(fā)給B系統(tǒng)辜腺,B系統(tǒng)再發(fā)給C系統(tǒng)休建,C處理完了可能還需要發(fā)給D系統(tǒng)乍恐,之后再D返回C,C返回B测砂,B再返回A等等各種情況茵烈。那么在整個鏈路中,如果A砌些、B呜投、C、D中有一個系統(tǒng)沒有正確的實現(xiàn)冪等存璃,也還是會出現(xiàn)冪等漏洞仑荐。