冪等性設計

目錄

前言

冪等性設計

冪等性設計處理流程

HTTP 冪等性

消息隊列冪等性 基于kafka?


前言

冪等性設計,就是說,一次和多次請求某一個資源應該具有同樣的副作用。為什么我們要有冪等性操作?說白了,就兩點:1、網絡的不穩定性 2、服務狀態不確定性,服務狀態不僅有成功,失敗,還有超時。超時又有多種原因引起的,有可能是網絡抖動,也有可能是負載引起的。對于這種情況,需要做重試,重試的后果是服務被調用了多次,數據不對,業務當然出問題了。打個比方吧,我們網上購物,去支付時,網絡原因超時,我們做重試,在我們發起重試后,網絡好了,是不是有可能執行了兩次,扣了兩次錢。這樣的情況其實有很多很多,還比如,訂單服務重試,創建了兩個同樣的訂單,等等。

系統超時,而調用方重試一下,給我們的系統帶來不一致的副作用。遇到這樣的情況,有幾種情況處理

  1. 需要下游系統提供相應的查詢接口。上游系統在 timeout 后去查詢一下。如果查到了,就表明已經做了,成功了就不用做了,失敗了就走失敗流程

  2. 通過冪等性的方式。也就是說,把這個查詢操作交給下游系統,我上游系統只管重試,下游系統保證一次和多次的請求結果是一樣的

  3. 可以在一些特殊字段比如訂單號設置成唯一索引,讓數據表自己去判斷

在這幾種處理情況中,第一點主要是需要系統提供查詢接口,第三點是根據數據庫的特性設計。第二點比較比較特殊,我會詳細講解。

以上說的是業務的冪等性,還有HTTP 的冪等性,消息隊列的冪等性主要談論kafka 冪等性的設計。

冪等性設計

冪等性設計,需要有一個唯一的標識,來標志是同一個請求發起的。這個唯一的標識一般會用全局ID,才能做到全局唯一性。那么這個全局ID,怎么分配的。

  1. 可以有一個中心的發號系統分配,每個請求就先請求發好系統,簡單的業務可以用redis incr 。但是這樣會有很多問題,中心的發號系統會成為系統的瓶頸,每次請求都要去請求發號系統。若設計成集群,那么全局ID 可能會重復,這個方案比較適合流量小,設計成單體系統。

  2. 為了解決集群ID 沖突問題,們需要使用一個不會沖突的算法,比如使用 UUID 這樣沖突非常小的算法。UUID 占用字符串空間大,索引效率低,生成的ID 太過于隨機,索引為了保證數據的順序性,可能會頁的分裂。

  3. 在全局唯一 ID 的算法中,這里介紹一個 Twitter 的開源項目 Snowflake。它是一個分布式 ID 的生成算法。它的核心思想是,產生一個 long 型的 ID,

    1)41bits 作為毫秒數。大概可以用 69.7 年。

    2)10bits 作為機器編號(5bits 是數據中心,5bits 的機器 ID),支持 1024 個實例。

    3)12bits 作為毫秒內的序列號。一毫秒可以生成 4096 個序號。

它主要是有幾部分組成:41bits 為毫秒級時間+5bits data center id+5 bits worked id+12 bits 毫秒內的技術

冪等性設計處理流程

方案一:我們可以先通過記錄全局id查詢。每次請求的時候,先去查,沒有的話,就記錄下來,有的話,就不處理請求,這樣每次都必須先查詢。

對于方案一是幾個步驟:1、先查詢全局id 2、插入數據。感覺這個設計保證數據的一致性是很難的。

1、我們把全局ID放在redis中流程圖是這樣的

這個妥妥的是有問題的,并發請求,查詢Redis,沒有,都會同時插入數據,舍棄

2、如果直接在數據表,先查詢呢,可能有多個請求同時查詢,沒有,同時插入,也是有問題的。

這種方案需要加入分布式鎖,客戶端與客戶端之間互斥只有一個客戶端能夠操作,加入了分布式鎖無疑增加了系統的復雜度,而且效率也會低的。

方案二、其實我們可以直接用sql 語句操作。對于insert insert into … values … on DUPLICATE KEY UPDATE …

方案三 對于更新來說,如果只是狀態更新,多次操作不會有副作用,是冪等的,比如 update table set status = “paid” where id = xxx and status = “unpaid”; 當然還有mvcc 樂觀鎖去處理,都是可以的,還是建議大家用全局id

HTTP 冪等性

http 有幾個方法:GET、HEAD、OPTIONS、DELETE、POST、PUT ,http 冪等性與這幾個方法有關:

GET 方法用于獲取資源,沒有副作用,是冪等的。比如 url ,不會改變資源的狀態,調用n次返回的都不會改變資源,沒有副作用。因此是冪等的

HTTP HEAD 和 GET 本質是一樣的,區別在于 HEAD 不含有呈現數據,而僅僅是 HTTP 頭信息,不應有副作用,也是冪等的。有的人可能覺得這個方法沒什么用,其實不是這樣的。想象一個業務情景:欲判斷某個資源是否存在,我們通常使用 GET,但這里用 HEAD 則意義更加明確。也就是說,HEAD 方法可以用來做探活使用。

HTTP OPTIONS 主要用于獲取當前 URL 所支持的方法,所以也是冪等的。若請求成功,則它會在 HTTP 頭中包含一個名為“Allow”的頭,值是所支持的方法,如“GET, POST”。

HTTP DELETE 方法用于刪除資源,有副作用,但它應該滿足冪等性。比如:DELETE url,調用一次和 N 次對系統產生的副作用是相同的,即刪掉 ID 為 4231 的帖子。因此,調用者可以多次調用或刷新頁面而不必擔心引起錯誤。

HTTP POST 方法用于創建資源,所對應的 URI 并非創建的資源本身,而是去執行創建動作的操作者,有副作用,不滿足冪等性。比如:POST url?的語義是在 url 下創建一篇帖子,HTTP 響應中應包含帖子的創建狀態以及帖子的 URI。兩次相同的 POST 請求會在服務器端創建兩份資源,它們具有不同的 URI;所以,POST 方法不具備冪等性。

HTTP PUT 方法用于創建或更新操作,所對應的 URI 是要創建或更新的資源本身,有副作用,它應該滿足冪等性。比如:PUT url 的語義是創建或更新 ID 為 4231 的帖子。對同一 URI 進行多次 PUT 的副作用和一次 PUT 是相同的;因此,PUT 方法具有冪等性。

所以,對于 POST 的方式,很可能會出現多次提交的問題,就好比,我們在論壇中發帖時,有時候因為網絡有問題,可能會對同一篇貼子出現多次提交的情況。對此,一般的冪等性的設計如下。

  1. 首先,在表單中需要隱藏一個 token,這個 token 可以是前端生成的一個唯一的 ID。用于防止用戶多次點擊了表單提交按鈕,而導致后端收到了多次請求,卻不能分辨是否是重復的提交。這個 token 是表單的唯一標識。(這種情況其實是通過前端生成 ID 把 POST 變成了 PUT。)

  2. 然后,當用戶點擊提交后,后端會把用戶提交的數據和這個 token 保存在數據庫中。如果有重復提交,那么數據庫中的 token 會做排它限制,從而做到冪等性。

  3. 當然,更為穩妥的做法是,后端成功后向前端返回 302 跳轉,把用戶的前端頁跳轉到 GET 請求,把剛剛 POST 的數據給展示出來。如果是 Web 上的最好還把之前的表單設置成過期,這樣用戶不能通過瀏覽器后退按鈕來重新提交。這個模式又叫做 PRG 模式(Post/Redirect/Get)。

消息隊列冪等性 基于kafka?

生產端:從kafka 0.11.0 版本開始 每個生產端生成一個唯一的ID,在每條消息中生成一個sequence num 進行消息去重,只對在一個生產端內生產的消息有效。也可以在消息內容加個全局id 業務判斷,和上面一樣的。

后續補充

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/719717.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/719717.shtml
英文地址,請注明出處:http://en.pswp.cn/news/719717.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LeetCode第125場雙周賽個人題解

目錄 100231. 超過閾值的最少操作數 I 原題鏈接 思路分析 AC代碼 100232. 超過閾值的最少操作數 II 原題鏈接 思路分析 AC代碼 100226. 在帶權樹網絡中統計可連接服務器對數目 原題鏈接 思路分析 AC代碼 100210. 最大節點價值之和 原題鏈接 思路分析 AC代碼 10023…

大話C++之:對象內存模型

一般繼承(無虛函數覆蓋) 只有一個虛指針,指向一個虛表,虛函數按順序從祖先節點開始插入到虛表上。字段按順序從祖先節點開始插入到對象內存上 一般繼承(有虛函數覆蓋) 只有一個虛指針,指向一個虛表,虛函數按順序從祖先節點開始&a…

桂院校園導航 靜態項目 二次開發教程 2.0

Gitee代碼倉庫:桂院校園導航小程序 GitHub代碼倉庫:GLU-Campus-Guide 靜態項目 2.0版本 升級日志 序號 板塊 詳情 1 首頁 重做了首頁,界面更加高效和美觀 2 校園頁 新增了 “校園指南” 功能,可以搜索和瀏覽校園生活指南…

【金三銀四】每日一點面試題(Java--JVM篇)

1、說一下 JVM 的主要組成部分及其作用? JVM(Java虛擬機)是Java程序運行的核心組件,它負責將Java字節碼翻譯成底層操作系統能夠執行的指令。JVM由以下幾個主要組成部分構成: 類加載器(Class Loader&#…

Modbus協議詳細解析與案例分享

目錄 Modbus協議詳細解析與案例分享1. Modbus協議簡介2. Modbus RTU和Modbus TCP的區別3. Modbus幀結構4. Modbus協議示例5. Modbus應用場景結語 Modbus協議詳細解析與案例分享 1. Modbus協議簡介 Modbus是一種串行通信協議,用于實現工業自動化設備之間的通信。它…

消息中間件|初識消息隊列

文章目錄 消息隊列是什么?消息隊列關鍵概念消息隊列優點消息隊列的應用場景異步處理應用解耦流量削峰消息通訊 常用消息隊列中間件的對比 消息隊列是什么? 消息隊列(Message Queue)是一種用于在軟件系統之間傳遞消息的通信機制。…

spring boot概述

SpringBoot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。 該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 通過這種方式,SpringBoot致力于在蓬勃發展的快速應用開發…

實時抓取SKU商品屬性詳細信息API數據接口(淘寶,某音)

item_sku-獲取sku詳細信息 taobao.item_sku詳細信息 API公共參數 請求地址: https://api-gw.onebound.cn/taobao/item_sku 名稱類型必須描述keyString是調用key(演示示例)secretString是調用密鑰api_nameString是API接口名稱(包括在請求地…

設計模式學習筆記 - 設計原則 - 3.里氏替換原則,它和多態的區別是什么?

前言 今天來學習 SOLID 中的 L:里氏替換原則。它的英文翻譯是 Liskov Substitution Principle,縮寫為 LSP。 英文原話是: Functions that use points of references of base classes must be able to use objects of derived classes withou…

python-分享篇-生成仿微信公眾號推廣的個性二維碼(支持動態)

代碼 生成仿微信公眾號推廣的個性二維碼(支持動態)from MyQR import myqr # 要生成動態二維碼,只需要將piture參數和save_name參數設置gif動圖即可 myqr.run(wordshttps://blog.csdn.net/stqer/article/details/135553200, # 指定二維碼包含…

JVM(內存區域劃分)

JVM JVM - Java虛擬機 我們編寫的 Java 程序, 是不能夠被 OS 直接識別的 JVM 充當翻譯官的角色, 負責把我們寫的的 Java 程序 ,翻譯給 OS “聽”, 讓 OS 能夠識別我們所寫的 Java 代碼 JVM 內存區域劃分 JVM 是一個應用程序, 在啟動的時候, 會從 操作系統 申請到一整塊很大的內…

AI-RAN聯盟在MWC24上正式啟動

AI-RAN聯盟在MWC24上正式啟動。它的logo是這個樣的: 2月26日,AI-RAN聯盟(AI-RAN Alliance)在2024年世界移動通信大會(MWC 2024)上成立。創始成員包括亞馬遜云科技、Arm、DeepSig、愛立信、微軟、諾基亞、美…

【dc-dc】AP510X單路低壓差線性恒流芯片

說明 AP510X 是一系列外圍電路簡潔的單路線性 LED 恒 流芯片,適用于 3-60V 電壓范圍的 LED 恒流調光 領域。 AP510X 采用我司專利算法,可以實現高精度的恒 流效果,輸出電流恒流精度≤ 3 %,電源供電工作 范…

【LeetCode】升級打怪之路 Day 11:棧的應用、單調棧

今日題目: Problem 1: 棧的應用 155. 最小棧 | LeetCode20. 有效的括號 | LeetCode150. 逆波蘭表達式求值 | LeetCode Problem 2: 單調棧 496. 下一個更大元素 I739. 每日溫度503. 下一個更大元素 II 目錄 Problem 1:棧 - “先進后出”的應用LC 155. 最…

【Java設計模式】五、建造者模式

文章目錄 1、建造者模式2、案例:共享單車的創建3、其他用途 1、建造者模式 某個對象的構建復雜將復雜的對象的創建 和 屬性賦值所分離,使得同樣的構建過程可以創建不同的表示建造的過程和細節調用者不需要知道,只需要通過構建者去進行操作 …

力扣刷題記錄--463. 島嶼的周長

題目鏈接&#xff1a;463. 島嶼的周長 - 力扣&#xff08;LeetCode&#xff09; 題目描述 我的代碼實現 class Solution {public int islandPerimeter(int[][] grid) { int result0; int rowgrid.length; int colgrid[0].length; for(int i0;i<row;i){for(int j0;j<col…

【EI會議征稿通知】2024年圖像處理與人工智能國際學術會議(ICIPAI2024)

2024年圖像處理與人工智能國際學術會議&#xff08;ICIPAI2024&#xff09; 2024 International Conference on Image Processing and Artificial Intelligence&#xff08;ICIPAI2024&#xff09; 2024年圖像處理與人工智能國際學術會議&#xff08;ICIPAI2024&#xff09;將…

返回靜態數據

在Java項目中&#xff0c;往往不會一直返回某某數據&#xff0c;而是會返回一個靜態頁面&#xff0c;那么&#xff0c;如何正確返回一個靜態頁面呢&#xff1f;&#xff1f; 要想成功的返回一個靜態頁面前提是必須要有一個靜態頁面&#xff1a; <!DOCTYPE html> <ht…

如何讓 JOIN 跑得更快?

JOIN 一直是數據庫性能優化的老大難問題&#xff0c;本來挺快的查詢&#xff0c;一旦涉及了幾個 JOIN&#xff0c;性能就會陡降。而且&#xff0c;參與 JOIN 的表越大越多&#xff0c;性能就越難提上來。 其實&#xff0c;讓 JOIN 跑得快的關鍵是要對 JOIN 分類&#xff0c;分…

Effective Programming 學習筆記

1 基本語句 1.1 斷言 在南溪看來&#xff0c;斷言可以用來有效地確定編程中當前代碼運行的前置條件&#xff0c;尤其是以下情況&#xff1a; 第三方工具庫對輸入數據的依賴&#xff0c;例如&#xff1a;minitouch庫對Android版本的要求