冪等(idempotent)是乙個數學與計算機學概念,常見於抽象代數中。
在程式設計中,乙個冪等操作的特點是,其任意多次執行所產生的影響均與一次執行的影響相同。冪等函式,或冪等方法,是指可以使用相同引數重複執行,並能獲得相同結果的函式。冪等函式可以改變系統的狀態。例如,settrue()
就是乙個冪等函式,因為無論執行多少次,其結果都是一樣的。
冪等的場景有很多,例如:
冪等並不是併發場景下的特有問題。冪等處理的是多次執行的問題,而併發僅僅是多次執行的一種形式。不管是依次執行,還是併發執行,都需要做好冪等。有些技術人員將解決併發問題的技術手段,例如悲觀鎖、樂觀鎖和分布式鎖,當成冪等的技術手段,這是不對的。
再次強調,冪等的核心是確保唯一性。
在資料庫中建立唯一索引,用作冪等記錄,可以防止插入重複的資料。 在冪等函式中,先執行一次查詢操作,如存在冪等記錄則返回第一次執行的結果,如不存在冪等記錄則繼續執行。在併發場景下,可能存在多個執行緒同時插入冪等記錄,這時候唯一索引可以確保只有乙個執行緒插入成功,其它執行緒丟擲異常。
除了插入冪等記錄,應該還要插入其它的業務資料,這個時候務必使用事務。在實際工作中,冪等記錄與事務經常同時出現,如影相隨。
使用redis、memcache和zookeeper都可以實現唯一資料,這裡僅用redis的setnx舉例。筆者從redis的官方文件摘抄了setnx的用法,如下所示。
setnx key value
將 key 的值設為 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則 setnx 不做任何動作。
setnx 是『set if not exists』(如果不存在,則 set)的簡寫。
可用版本:
>= 1.0.0
時間複雜度:
o(1)
返回值:
設定成功,返回 1 。
設定失敗,返回 0 。
複製**
在冪等函式中,將唯一標識作為key,任取value,呼叫setnx。如果返回1,說明當前是第一次執行,繼續執行冪等函式;如果返回0,取出第一次執行的結果並返回給呼叫方。在併發場景下,可能因尚未完成第一次執行而取不到結果,這時候可以稍作等待。
除了redis、memcache和zookeeper,還有其它手段可以實現唯一資料,讀者可自行探索。只要可以實現唯一資料,就可以用來做冪等。
在單據相關的業務,或者是任務相關的業務,基本會涉及到狀態機。業務單據上面有個狀態,這個狀態根據乙個有限狀態機進行跳轉。如果狀態機已經處於下乙個狀態,這時候是不能往回跳轉到上乙個狀態的。通過狀態機的跳轉約束,可以做到有限狀態機的冪等。
冪等經常與事務同時出現,而事務適合小任務場景、不適合大任務場景,因此筆者將冪等場景分為以下兩類進行介紹。為了方便描述,我們假設bizid可以唯一標識一筆業務。
這個場景的處理方式很簡單,可以追求強一致性。在冪等函式中,先判斷冪等記錄是否存在。如果存在,直接返回;如果不存在,開啟乙個事務。在事務中,採用任務名+bizid作為冪等組合字段,插入冪等記錄和業務資料。它的流程圖如下。
在大任務場景下,需要將大任務拆成多個小任務分別執行。在每個小任務中,都可以有事務。但是,沒有事務保證所有的小任務同時成功。因此,存在部分成功的場景。針對部分成功的場景,可以利用重試機制做到最終一致性。重試機制意味著多次執行,回到了冪等問題。這裡只介紹需要冪等的場景。如果同時存在需要冪等和不需要冪等的場景,**入乙個判斷標。
同步執行小任務的流程圖如下。各小任務依次執行,中間的小任務不返回結果,僅在最後乙個小任務或之後返回結果。
非同步執行小任務的流程圖如下。各小任務單獨執行,互相不感知,也沒有地方返回結果。
不管是同步執行小任務,還是非同步執行小任務,都需要為每個小任務設定乙個冪等字段或冪等組合字段。筆者推薦採用小任務名+bizid
作為冪等組合字段。一方面,bizid可以標識這一批小任務屬於同一筆業務;另一方便,小任務名可以區分不同的小任務。
碼字不易,如有建議請掃碼
深入理解分布式系統中的HTTP冪等性
說起冪等性,可能很多人並不怎麼熟悉,在開發中也沒有去關注它。這是對於乙個初級程式猿來說的,但是,如果作為乙個入行多年的中高階開發,你還不了解冪等性,那麼,你應該感到臉紅 冪等性 idempotence 是http協議涉及到的一種重要性質。冪等性是指一次和多次請求某乙個資源應該具有同樣的 這是其定義,...
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...
mysql 索引深入理解 深入理解MySql的索引
為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...