冪等性和實現方法 – tommwq.tech/blog
如果乙個操作重複執行多次,其效果(不考慮操作時間)和只執行一次是一樣的,那麼這個操作就叫做是冪等(idempotent)的。乍看起來,冪等操作似乎沒什麼用處,畢竟只有第一次執行有效。但如果在系統設計中考慮到「失敗」場景的話,冪等操作是非常重要的。因為失敗發生和感知失敗發生是兩件不同的事情。想象兩個伺服器進行通過網路進行通訊。伺服器a傳送請求到伺服器b,伺服器b執行並將結果傳送給a。在理想的情況下,一切執行順利。我們從伺服器a的角度來看看發生了什麼。首先伺服器a發出乙個請求,等待了一會後,服務a收到乙個應答,並且應答裡的訊息表明操作成功。現在我們引入失敗的情況。可能的失敗有這麼幾種:
伺服器a傳送請求失敗。
伺服器b接收請求失敗。
伺服器b處理請求失敗。
伺服器b傳送應答失敗。
伺服器a接收應答失敗。
從伺服器a的角度來看,除了第1種錯誤可以立刻感知外,其他的錯誤都可能無法被伺服器a感知到。在乙個更加實際的場景中,伺服器a傳送了請求,等待了一會,沒有收到應答。這時伺服器a無法判斷伺服器b的操作是成功了,還是失敗了。它應該繼續等待呢?還是應該重新傳送一次請求呢?如果繼續等待,一旦伺服器b發生故障,伺服器a將陷入永久停滯。如果重新傳送請求,一旦伺服器b已經成功執行了操作(失敗情形4、5),再次請求就會讓伺服器b重複執行2次相同的操作。如果請求的操作是「扣除100元」,重複2次操作的效果將是「扣除200元」,這將違背伺服器a的意圖。但如果這是乙個冪等操作,無論重複幾次,效果都和只執行一次相同,那麼伺服器a就可以放心的重發請求了。這就是冪等操作的好處。冪等操作可以大大簡化客戶端**的故障處理邏輯,提高系統整體的穩定性。
將非冪等操作封裝成冪等操作,需要將操作分成兩部分:為操作執行例項分配編號;通過編號提交操作。伺服器b在收到操作提交請求時,首先檢查操作是否已經執行。如果操作已經執行,將結果傳送給伺服器a。如果操作尚未執行,執行操作,並傳送結果。
// 非冪等操作
operationresult result = operation.execute();
// 冪等操作
class operation
operation operation = getoperation(id);
operation.execute();
state.setexecuted();
}}operation.register(operation);
string id = operation.getlastregisteredid();
operation.commit(id);
operationresult result = operation.getoperationresult(id);
我們來看拆分出來的兩個步驟:
為操作執行例項分配編號。
通過編號提交操作,當且僅當操作尚未執行時,執行該操作。
第一步為操作分配了乙個編號,但沒有執行操作,沒有修改業務狀態。因此從業務狀態的變化來看,可以認為是冪等的。第二步顯然是冪等的,因為只要操作成功執行,後續的請求不會再次執行操作。
對於單體單執行緒服務,上面的**已經夠用了。對於多執行緒或分布式服務,還有一些細節需要考慮。首先是全域性唯一id生成,這已經有成熟的方案了。其次,在判斷操作是否已經執行時,需要通過全域性鎖保護,以保證多執行緒或分布式程式中的個節點的觀察順序。或者在提交操作結果之前,再次檢查操作狀態。如果發現其他執行緒/節點已經完成操作,丟棄本地操作結果。
方法冪等性控制
方法冪等性控制 冪等http 1.1中對冪等性的定義是 一次和多次請求某乙個資源對於資源本身應該具有同樣的結果 網路超時等問題除外 也就是說,其任意多次執行對資源本身所產生的影響均與一次執行的影響相同。冪等不僅僅只是一次 或多次 請求對資源沒有 比如查詢資料庫操作,沒有增刪改,因此沒有對資料庫有任何...
冪等性的實現
1.生成key的方式 記得保證redis生成的key和刪除的key是成功的 看返回值 1 允許表單跳轉 這種情況比較容易,比如在列表中新增一條記錄,可以在列表頁面生成乙個key,放到redis中,同時在新增頁面時帶著這個key。等到提交時,把key也提交,後台根據key與redis中進行比較,有的話...
冪等性的實現
1.生成key的方式 記得保證redis生成的key和刪除的key是成功的 看返回值 1 允許表單跳轉 這種情況比較容易,比如在列表中新增一條記錄,可以在列表頁面生成乙個key,放到redis中,同時在新增頁面時帶著這個key。等到提交時,把key也提交,後台根據key與redis中進行比較,有的話...