冪等性設計藝術:在分布式重試風暴中構筑堅不可摧的防線

冪等性設計藝術:在分布式重試風暴中構筑堅不可摧的防線

??2023年某支付平臺凌晨故障??:

由于網絡抖動導致支付指令重復發送,系統在2分鐘內處理了??17萬筆重復交易??,引發??4.2億資金風險??。

事故根本原因:??缺少冪等防護??的支付接口在重試機制下成為"資金黑洞"。

一、冪等性:分布式系統的生命線

1.1 什么是冪等性?

??數學定義??:

對于操作f,若滿足 f(f(x)) = f(x),則稱f具有冪等性

??分布式系統定義??:

一個操作無論被執行一次還是多次,對系統狀態的影響都是相同的

1.2 為什么需要冪等性?

??分布式環境四大不確定性??:

  1. 網絡超時重試

  2. 消息隊列重復投遞

  3. 客戶端重復提交

  4. 故障恢復后補償

二、冪等性實現模式全景圖

2.1 唯一請求ID模式(全局ID方案)

實現原理:

Java實現:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;public class IdempotentService {// 使用分布式緩存如Redis生產環境private final ConcurrentMap<String, Object> requestCache = new ConcurrentHashMap<>();public Response processRequest(Request request) {String requestId = request.getRequestId();// 檢查是否已處理Object cachedResult = requestCache.get(requestId);if (cachedResult != null) {return (Response) cachedResult;}// 獲取分布式鎖(防并發重復)Lock lock = distributeLock.lock(requestId);try {// 雙重檢查cachedResult = requestCache.get(requestId);if (cachedResult != null) {return (Response) cachedResult;}// 執行業務邏輯Response response = executeBusiness(request);// 記錄結果(設置合理過期時間)requestCache.put(requestId, response, 24, TimeUnit.HOURS);return response;} finally {lock.unlock();}}// 業務執行示例private Response executeBusiness(Request request) {// 核心業務邏輯Payment payment = paymentService.create(request);return new Response(200, "支付成功", payment);}
}

??適用場景??:

  • 支付交易

  • 訂單創建

  • 重要業務操作

2.2 狀態機模式(業務狀態約束)

狀態流轉圖:

Java實現(樂觀鎖方案):
public class OrderService {@Transactionalpublic void payOrder(String orderId, BigDecimal amount) {Order order = orderDao.findById(orderId);// 狀態檢查if (order.getStatus() != OrderStatus.PENDING) {throw new IllegalStateException("訂單狀態異常");}// 樂觀鎖更新int rows = orderDao.updateStatus(orderId, OrderStatus.PENDING, // 舊狀態OrderStatus.PAID     // 新狀態);if (rows == 0) {// 更新失敗,可能已被其他請求處理throw new ConcurrentUpdateException();}// 扣減庫存等后續操作inventoryService.reduce(order.getProductId(), order.getQuantity());}
}

??適用場景??:

  • 訂單狀態變更

  • 工作流引擎

  • 庫存管理

2.3 令牌桶模式(預取號機制)

工作流程:

Java實現:
public class TokenService {// 使用Redis存儲令牌狀態private final RedisTemplate<String, Boolean> redisTemplate;// 生成令牌public String generateToken(String businessType) {String token = UUID.randomUUID().toString();String key = "token:" + businessType + ":" + token;// 設置過期時間30分鐘redisTemplate.opsForValue().set(key, false, 30, TimeUnit.MINUTES);return token;}// 驗證并消耗令牌public boolean consumeToken(String businessType, String token) {String key = "token:" + businessType + ":" + token;// 使用Lua腳本保證原子性String script = "if redis.call('get', KEYS[1]) == false then " +"   redis.call('set', KEYS[1], true) " +"   return true " +"else " +"   return false " +"end";return redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),Collections.singletonList(key));}
}// 客戶端使用
public class PaymentController {@PostMapping("/pay")public Response pay(@RequestBody PaymentRequest request) {// 驗證令牌if (!tokenService.consumeToken("payment", request.getToken())) {return new Response(400, "重復請求");}// 處理支付return paymentService.process(request);}
}

??適用場景??:

  • 防止表單重復提交

  • 短信驗證碼校驗

  • 敏感操作確認

三、HTTP冪等性深度解析

3.1 HTTP方法冪等性矩陣

方法

是否冪等

原因說明

GET

只讀操作,不影響資源狀態

HEAD

同GET,不返回響應體

PUT

全量替換資源

DELETE

刪除資源,多次刪除結果相同

POST

??否??

每次創建新資源

PATCH

通常否

部分更新可能產生不同結果

OPTIONS

獲取服務器支持的方法

3.2 POST方法實現冪等的三種方案

四、行業級應用實踐

4.1 消息隊列冪等消費(Kafka實現)

public class KafkaConsumerService {private final Map<TopicPartition, Set<Long>> processedOffsets = new ConcurrentHashMap<>();@KafkaListener(topics = "payment")public void handlePayment(ConsumerRecord<String, PaymentMessage> record) {TopicPartition tp = new TopicPartition(record.topic(), record.partition());long offset = record.offset();// 檢查是否已處理if (processedOffsets.computeIfAbsent(tp, k -> ConcurrentHashMap.newKeySet()).contains(offset)) {return; // 已處理,跳過}try {paymentService.process(record.value());// 記錄已處理offsetprocessedOffsets.get(tp).add(offset);} catch (Exception e) {// 處理失敗,不記錄offsetthrow e;}}// 定期清理舊offset@Scheduled(fixedRate = 60000)public void cleanProcessedOffsets() {long now = System.currentTimeMillis();processedOffsets.forEach((tp, offsets) -> {offsets.removeIf(offset -> offset < getOldestUnprocessedOffset(tp));});}
}

4.2 分布式庫存扣減(Redis+Lua)

-- KEYS[1]: 庫存key
-- ARGV[1]: 扣減數量
-- ARGV[2]: 請求IDlocal key = KEYS[1]
local quantity = tonumber(ARGV[1])
local requestId = ARGV[2]-- 檢查請求是否已處理
if redis.call('sismember', key..':processed', requestId) == 1 thenreturn 0 -- 已處理
end-- 檢查庫存
local stock = tonumber(redis.call('get', key))
if stock < quantity thenreturn -1 -- 庫存不足
end-- 扣減庫存
redis.call('decrby', key, quantity)
redis.call('sadd', key..':processed', requestId)return 1 -- 成功

4.3 支付系統冪等設計

五、避坑指南:冪等設計的致命陷阱

5.1 經典反模式案例

??案例1:訂單重復創建??

// 錯誤實現:缺少冪等檢查
public Order createOrder(OrderRequest request) {// 直接創建訂單Order order = new Order(request);return orderRepository.save(order);
}

??案例2:數據庫冪等失效??

/* 危險操作:非冪等更新 */
UPDATE account SET balance = balance - 100 WHERE user_id = 123;
-- 重試時重復扣款

5.2 冪等設計十大黃金法則

  1. ? ??前置檢查??:在執行業務前進行冪等驗證

  2. ? ??狀態約束??:利用業務狀態機防止重復流轉

  3. ? ??請求標識??:全局唯一ID貫穿整個請求鏈路

  4. ? ??原子操作??:使用數據庫事務或Lua腳本保證原子性

  5. ? ??過期機制??:為冪等記錄設置合理過期時間

  6. ? ??錯誤隔離??:區分冪等錯誤和業務錯誤

  7. ? ??版本控制??:業務變更時考慮冪等兼容性

  8. ? ??壓力測試??:在高并發下驗證冪等設計

  9. ? ??監控告警??:對重復請求進行監控

  10. ? ??文檔規范??:明確接口冪等特性

六、進階:分布式環境下的挑戰與解決方案

6.1 分庫分表下的冪等挑戰

??解決方案??:

6.2 跨系統冪等傳遞

??Saga事務中的冪等設計??:

public class OrderSaga {@SagaSteppublic void reserveInventory(Order order) {// 冪等鍵:訂單ID+步驟名String idempotentKey = order.getId() + ":reserveInventory";if (idempotencyService.isProcessed(idempotentKey)) {return;}inventoryService.reserve(order.getItems());idempotencyService.markProcessed(idempotentKey);}@Compensatepublic void compensateReserve(Order order) {// 補償操作同樣需要冪等String idempotentKey = order.getId() + ":compensateReserve";if (idempotencyService.isProcessed(idempotentKey)) {return;}inventoryService.cancelReservation(order.getItems());idempotencyService.markProcessed(idempotentKey);}
}

七、思考題

  1. ??設計題??:

    如何設計一個支持百億級請求的去重系統?要求:

    • 99.99%的精確去重

    • 存儲成本低于1TB

    • 毫秒級響應時間

      請描述架構和核心算法選擇

  2. ??故障分析??:

    某系統雖然實現了冪等設計,但在數據庫主從切換后出現重復處理,可能的原因是什么?如何解決?

  3. ??性能優化??:

    在高并發場景下(10萬QPS),冪等檢查成為性能瓶頸,有哪些優化方案?


??分布式系統設計箴言??:

"在分布式世界中,任何可能出錯的事情終將出錯。

冪等性不是可選項,而是系統穩定性的最后一道防線。"

—— 分布式系統設計原則

????性能對比??:

方案

吞吐量(QPS)

存儲開銷

適用場景

數據庫唯一索引

2,500

低頻關鍵業務

Redis去重

45,000

高頻業務

布隆過濾器

120,000+

可容忍誤判場景

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

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

相關文章

從零開始理解NDT算法的原理及應用

1. 概述 NDT&#xff0c;全稱 Normal Distributions Transform&#xff08;正態分布變換&#xff09;&#xff0c;是一種廣泛使用的點云配準算法&#xff0c;它的核心思想與ICP截然不同&#xff1a;NDT不直接計算點與點之間的對應關系&#xff0c;而是通過概率模型來描述和匹配…

艾體寶案例 | 數據驅動破局:DOMO 如何重塑寵物零售門店的生存法則

某連鎖寵物店店長緊盯著電腦屏幕上的Excel表格&#xff0c;手指機械地在鍵盤上敲擊出“CtrlC/V”的組合鍵——這是她第17次嘗試將三個不同系統的數據拼湊到一起。門店POS機導出的銷售記錄、會員系統的消費偏好、庫存管理的臨期預警&#xff0c;這些本應串聯起門店運營全貌的關鍵…

極飛科技AI智慧農業實踐:3000畝棉田2人管理+產量提15%,精準灌溉與老農操作門檻引討論

在新疆尉犁縣的棉田里&#xff0c;兩架農業無人機正沿著設定航線低空飛行&#xff0c;它們掠過之處&#xff0c;傳感器實時傳回土壤濕度和作物長勢數據——這片3000畝的棉田&#xff0c;如今只需要兩名90后新農人通過手機管理&#xff0c;產量卻比傳統種植模式提高了15%。這不是…

企業級-搭建CICD(持續集成持續交付)實驗手冊

搭建CI/CD(持續集成/持續交付)企業示例 為了讓容器構建鏡像并可以持續集成&#xff0c;可以自動上傳到Harbor倉庫&#xff1b;并且業務主機可以通過CD自動從倉庫中下載鏡像latest版本并實現業務更新。1.環境部署 1.1 環境搭建業務IP域名GitLab172.25.254.50gitlab.dhj.orgJenki…

吃透《數據結構》C 語言版:線性表的類型定義詳解

作為數據結構的入門章節&#xff0c;線性表就像 “地基” 一樣重要&#xff0c;而第二章 2.3 節的 “線性表的類型定義”&#xff0c;更是理解后續操作&#xff08;插入、刪除、查找等&#xff09;的核心前提。今天就結合自己的學習筆記&#xff0c;用通俗的語言拆解這個知識點…

文件系統中的核心數據結構

宏觀上文件系統在kernel的形態文件系統運作流程按照:vfs->磁盤緩存->實際磁盤文件系統->通用塊設備層->io調度層->塊設備驅動層->磁盤。具體流程的詳細展現如下如如何理解文件系統中的數據結構&#xff1f;linux中文件系統還有幾種核心數據結構分別是super_b…

TDengine與StarRocks在技術架構和適用場景上有哪些主要區別?

TDengine 與 StarRocks 作為國產數據庫領域的代表性產品&#xff0c;分別專注于時序數據處理和高性能分析場景&#xff0c;在技術架構和適用場景上存在顯著差異。以下從核心架構、數據模型、性能特點及典型應用場景等方面進行對比分析&#xff1a;&#x1f3d7;? ??一、技術…

Qt事件_xiaozuo

Qt事件Qt 的事件機制是其實現用戶交互和系統響應的核心框架&#xff0c;基于事件驅動模型構建。以下從五個關鍵方面詳細解釋其工作原理和用法&#xff1a;1. 事件&#xff08;QEvent&#xff09;的定義與分類事件本質&#xff1a;事件是 QEvent 類或其子類的實例&#xff0c;用…

運動控制技術:自動化與智能驅動的核心

一、運動控制概述運動控制技術是自動化技術和電氣拖動技術的融合&#xff0c;以工控機、PLC、DSP等為控制器的運動控制技術融合了微電子技術、計算機技術、檢測技術、自動化技術以及伺服控制技術等學科的新成果&#xff0c;在工業生產中起著極為重要的作用。早期的運動控制技術…

鏈表實戰指南:手動實現單鏈表與雙鏈表的接口及OJ挑戰(含完整源碼)

文章目錄一、鏈表的概念二、鏈表的分類三、手動實現單鏈表1.鏈表的初始化2.鏈表的打印3.申請新的節點大小空間4.鏈表的尾插5.鏈表的頭插6.鏈表的尾刪7.鏈表的頭刪8.鏈表的查找9.在指定位置之前插入數據10.在指定位置之后插入數據11.刪除指定節點12.刪除指定節點之后的數據13.銷…

Spring 事件驅動編程初探:用 @EventListener 輕松處理業務通知

一、核心概念與模型Spring 的事件機制是觀察者模式&#xff08;也叫發布-訂閱模型&#xff09;的一種典型實現。它主要由三個核心部分組成&#xff1a;事件 (Event)&#xff1a; 承載信息的對象&#xff0c;通常是某種狀態變化的通知。可以是繼承 ApplicationEvent 的類&#x…

無人機也能稱重?電力巡檢稱重傳感器安裝與使用指南

在無人機電力巡檢中&#xff0c;工程師們常常面臨一個棘手難題&#xff1a;如何精確知道新架設或老舊纜線的實際負重&#xff1f; 傳統依靠老師傅“肉眼估算”的方法不僅風險極高&#xff0c;而且數據極不準確&#xff0c;給電網安全埋下巨大隱患。難道沒有更科學的方法嗎&…

第二階段WinForm-8:特性和反射,加密和解密,單例模式

1_預處理指令 &#xff08;1&#xff09;源代碼指定了程序的定義&#xff0c;預處理指令&#xff08;preprocessor directive&#xff09;指示編譯器如何處理源代碼。例如&#xff0c;在某些情況下&#xff0c;我們希望編譯器能夠忽略一部分代碼&#xff0c;而在其他情況下&am…

基于mac的智能語音處理與應用開發-環境部署

上一次寫文章還是上一次&#xff0c;時隔一年再次開啟學習之路。新機mac沒有開發環境&#xff0c;在gpt老師的指導下開始學習之路。 mac開發環境的部署參考了b站程序員云謙和Clover-You的視頻教程&#xff0c;然后結合自身及gpt老師的幫助現在開始部署。 g老師的&#x1f34e…

Java中使用正則表達式的正確打開方式

正則表達式基礎語法Java正則表達式基于java.util.regex包&#xff0c;核心類是Pattern和Matcher。基本語法遵循標準正則規范&#xff1a;. 匹配任意單個字符&#xff08;除換行符&#xff09;\d 匹配數字&#xff0c;等價于 [0-9]\w 匹配單詞字符&#xff0c;等價于 [a-zA-Z0-9…

Docker中Mysql容器忽略大小寫

場景說明 在數據遷移場景中&#xff0c;從一個數據庫中將數據遷移到另一個數據&#xff0c;經常會遇到&#xff0c;兩個不同數據庫之間&#xff0c;一個默認忽略大小寫&#xff0c;一個默認不忽略大小寫&#xff0c;導致實際業務層服務進行數據庫訪問時&#xff0c;切換數據庫之…

神經網絡激活函數:從ReLU到前沿SwiGLU

摘要 本文全面介紹了神經網絡中常用的激活函數,包括Sigmoid、Tanh、ReLU等傳統函數,以及2017年后出現的Swish、Mish、SwiGLU等新興函數。每個函數均提供數學定義、優缺點分析、Python實現代碼和可視化圖像,并附有實際應用建議和性能對比數據,幫助讀者根據具體任務選擇合適…

線程池常見面試問答

好嘞 &#x1f44d;&#xff0c;我幫你把這些 線程池 并發編程八股文 整理成 問答對照表&#xff08;Q & A&#xff09;&#xff0c;你面試時可以直接用。&#x1f9fe; 線程池常見面試問答一、基礎語法 & STLQ1&#xff1a;std::function<void()> 和函數指針的…

Flutter 開發技巧 AI 快速構建 json_annotation model 的提示詞

將下面這段復制到AI GPT、DeepSeek 、文心快碼 試過效果都可以&#xff0c;不用做任何更改。將 json 數據丟給 AI 就行了 我會提供一段 JSON 數據&#xff0c;請幫我生成 Dart 模型&#xff0c;要求嚴格如下&#xff1a;1. 使用 json_annotation 包&#xff0c;包含&#xff1a…

【秋招筆試】2025.08.30科大訊飛秋招筆試題

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍在線刷題 bishipass.com 科大訊飛 題目一:物品種類統計 1??:使用集合或哈希表統計不同物品編號的數量 2??:利用數學公式 n - 不同種類數 計算最終答案 難度:簡單 這道題目的關…