最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis Stream秒殺系統(tǒng)實現(xiàn)

 更新時間:2025年11月28日 09:56:59   作者:⑩-  
文章瀏覽閱讀345次,點贊7次,收藏3次。高性能: Lua腳本原子操作,毫秒級響應高并發(fā): 異步處理,支持10萬+ QPS數(shù)據(jù)一致性: 庫存不會超賣可靠性: 消息隊列確保訂單不丟失用戶體驗: 立即返回結果,無需等待。

?? 案例背景

雙11秒殺活動:某電商平臺推出1000臺特價iPhone,10萬用戶同時搶購。

??? 系統(tǒng)架構圖

用戶請求 → Lua腳本校驗 → Redis Stream隊列 → 異步處理 → 數(shù)據(jù)庫

?? 詳細步驟說明

步驟1:用戶點擊秒殺按鈕

// 前端調(diào)用
public Result seckillVoucher(Long voucherId) {
    // 生成唯一訂單ID: 2024110500012345
    long orderId = redisIdWorker.nextId("order");
    // 執(zhí)行Lua腳本進行原子操作
    Long result = stringRedisTemplate.execute(
            SECKILL_SCRIPT,
            Collections.emptyList(),
            "1001",  // 優(yōu)惠券ID (iPhone特價券)
            "12345", // 用戶ID
            "2024110500012345" // 訂單ID
    );
    // 立即返回結果給用戶
    if(result != 0){
        return Result.fail(result==1 ? "庫存不足":"不能重復下單");
    }
    return Result.ok(2024110500012345L);
}

?? Lua腳本詳解 (SECKILL_SCRIPT)

-- 參數(shù):優(yōu)惠券ID、用戶ID、訂單ID
local voucherId = ARGV[1]
local userId = ARGV[2]  
local orderId = ARGV[3]
-- 構建Redis Key
local stockKey = 'seckill:stock:' .. voucherId
local orderKey = 'seckill:order:' .. voucherId
-- 1. 判斷庫存是否充足
local stock = redis.call('get', stockKey)
if tonumber(stock) <= 0 then
    return 1  -- 庫存不足
end
-- 2. 判斷用戶是否已經(jīng)下單 (set集合)
if redis.call('sismember', orderKey, userId) == 1 then
    return 2  -- 不能重復下單
end
-- 3. 扣減庫存
redis.call('decr', stockKey)
-- 4. 記錄用戶購買記錄
redis.call('sadd', orderKey, userId)
-- 5. 發(fā)送消息到Stream隊列
redis.call('xadd', 'stream.order', '*',
    'voucherId', voucherId,
    'userId', userId, 
    'orderId', orderId
)
return 0  -- 成功

?? 實際場景演示

場景1:用戶A成功秒殺

時間線:
10:00:00.000 - 用戶A點擊秒殺按鈕
10:00:00.050 - Lua腳本執(zhí)行:
                ? 庫存檢查: 庫存1000 > 0
                ? 重復檢查: 用戶A未購買
                ? 庫存-1 → 999
                ? 記錄用戶A到已購集合
                ? 發(fā)送消息到stream.order
10:00:00.100 - 返回訂單ID: 2024110500012345
10:00:00.150 - 異步線程處理訂單入庫
10:00:01.000 - 訂單創(chuàng)建完成

場景2:用戶B重復秒殺

時間線:
10:00:00.200 - 用戶B點擊秒殺按鈕  
10:00:00.250 - Lua腳本執(zhí)行:
                ? 庫存檢查: 庫存999 > 0
                ? 重復檢查: 用戶B已在已購集合中
                → 返回2 (不能重復下單)
10:00:00.300 - 前端顯示:"不能重復下單"

場景3:第1001個用戶秒殺

時間線:
10:00:05.000 - 用戶Z點擊秒殺按鈕
10:00:05.050 - Lua腳本執(zhí)行:
                ? 庫存檢查: 庫存0 <= 0
                → 返回1 (庫存不足)
10:00:05.100 - 前端顯示:"庫存不足"

?? 異步訂單處理流程

正常處理流程

// VoucherOrderHandler - 訂單處理線程
while(true){
    // 從消息隊列讀取訂單
    List<MapRecord<String, Object, Object>> list = stringRedisTemplate
        .opsForStream()
        .read(
            Consumer.from("g1", "c1"),  // 消費者組g1,消費者c1
            StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),
            StreamOffset.create("stream.order", ReadOffset.lastConsumed()) // 讀取新消息
        );
    if(!list.isEmpty()){
        MapRecord<String, Object, Object> record = list.get(0);
        Map<Object, Object> values = record.getValue();
        // 構建訂單對象
        VoucherOrder order = new VoucherOrder();
        order.setId(Long.parseLong((String)values.get("orderId")));
        order.setUserId(Long.parseLong((String)values.get("userId")));
        order.setVoucherId(Long.parseLong((String)values.get("voucherId")));
        // 保存到數(shù)據(jù)庫
        voucherOrderService.save(order);
        // 確認消息已處理
        stringRedisTemplate.opsForStream()
            .acknowledge("stream.order", "g1", record.getId());
        log.info("訂單處理成功: {}", order.getId());
    }
}

異常處理流程

private void handlePendingList() {
    while(true){
        try {
            // 讀取未確認的消息 (處理異常情況)
            List<MapRecord<String, Object, Object>> list = stringRedisTemplate
                .opsForStream()
                .read(
                    Consumer.from("g1", "c1"),
                    StreamReadOptions.empty().count(1),
                    StreamOffset.create("stream.order", ReadOffset.from("0")) // 從pending-list讀取
                );
            if(list.isEmpty()) break; // 沒有異常消息
            MapRecord<String, Object, Object> record = list.get(0);
            // 重新處理訂單...
            createVoucherOrder(voucherOrder);
            // 確認消息
            stringRedisTemplate.opsForStream()
                .acknowledge("stream.order", "g1", record.getId());
        } catch (Exception e) {
            // 處理失敗,等待后重試
            Thread.sleep(20);
        }
    }
}

?? 實戰(zhàn)場景模擬

模擬10萬并發(fā)秒殺

// 模擬10萬用戶同時秒殺
for(int i = 1; i <= 100000; i++){
    new Thread(() -> {
        Result result = seckillVoucher(1001L); // iPhone秒殺
        if(result.getCode() == 200){
            System.out.println("用戶" + Thread.currentThread().getId() + "秒殺成功");
        } else {
            System.out.println("用戶" + Thread.currentThread().getId() + "秒殺失敗");
        }
    }).start();
}

執(zhí)行結果:

用戶12345: 秒殺成功
用戶12346: 秒殺成功
...
用戶11344: 秒殺成功  
用戶11345: 庫存不足
用戶11346: 庫存不足
...
用戶100000: 庫存不足

?? Redis數(shù)據(jù)狀態(tài)變化

秒殺開始前

seckill:stock:1001: "1000"     # 庫存1000
seckill:order:1001: []         # 空集合
stream.order: []               # 空消息隊列

秒殺過程中

seckill:stock:1001: "500"      # 庫存剩余500
seckill:order:1001: ["12345", "12346", ...]  # 500個用戶ID
stream.order: [消息1, 消息2, ...]            # 500條待處理消息

秒殺結束后

seckill:stock:1001: "0"        # 庫存為0
seckill:order:1001: [1000個用戶ID]          # 1000個購買用戶
stream.order: []               # 消息全部處理完成

?? 核心優(yōu)勢總結

  • 高性能: Lua腳本原子操作,毫秒級響應
  • 高并發(fā): 異步處理,支持10萬+ QPS
  • 數(shù)據(jù)一致性: 庫存不會超賣
  • 可靠性: 消息隊列確保訂單不丟失
  • 用戶體驗: 立即返回結果,無需等待

?? 擴展思考

問題: 如果異步處理訂單時數(shù)據(jù)庫掛了怎么辦?
答案: 消息會留在pending-list中,等數(shù)據(jù)庫恢復后自動重試。

問題: 如何防止惡意用戶刷 單?
答案: 在Lua腳本中加入頻率限制,如:redis.call('incr', 'user:limit:'..userId)

到此這篇關于Redis Stream秒殺系統(tǒng)實現(xiàn)的文章就介紹到這了,更多相關Redis Stream秒殺內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Redis緩存實例超詳細講解

    Redis緩存實例超詳細講解

    實際開發(fā)中緩存處理是必須的,不可能我們每次客戶端去請求一次服務器,服務器每次都要去數(shù)據(jù)庫中進行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運行速度
    2022-12-12
  • redis底層數(shù)據(jù)結構之ziplist實現(xiàn)詳解

    redis底層數(shù)據(jù)結構之ziplist實現(xiàn)詳解

    這篇文章主要為大家介紹了redis底層數(shù)據(jù)結構之ziplist實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Redis超詳細講解高可用主從復制基礎與哨兵模式方案

    Redis超詳細講解高可用主從復制基礎與哨兵模式方案

    Redis因為其高性能和易用性在我們后端的服務中發(fā)揮了巨大的作用,并且很多重要功能的實現(xiàn)都會依賴redis,本篇我們來了解Redis高可用主從復制與哨兵模式
    2022-04-04
  • Redis?布隆過濾器命令的使用詳解

    Redis?布隆過濾器命令的使用詳解

    這篇文章主要介紹了Redis?布隆過濾器的相關命令的使用,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • 一篇文章帶你徹底搞懂Redis?事務

    一篇文章帶你徹底搞懂Redis?事務

    這篇文章主要介紹了一篇文章帶你徹底搞懂Redis?事務的相關資料,需要的朋友可以參考下
    2022-10-10
  • Window server中安裝Redis的超詳細教程

    Window server中安裝Redis的超詳細教程

    這篇文章主要介紹了Window server中安裝Redis的教程,本文通過圖文實例代碼相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • Redis如何使用HyperLogLog的實現(xiàn)

    Redis如何使用HyperLogLog的實現(xiàn)

    本文主要介紹了Redis如何使用HyperLogLog的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • Redis基于Session實現(xiàn)分布式登錄的示例代碼

    Redis基于Session實現(xiàn)分布式登錄的示例代碼

    本文主要介紹了Redis基于Session實現(xiàn)分布式登錄的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-08-08
  • Redis 在真實世界的 5 個用法

    Redis 在真實世界的 5 個用法

    Redis是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API這篇文章主要介紹了Redis 在真實世界的 5 個用法,需要的朋友可以參考下
    2018-03-03
  • 淺談我是如何用redis做實時訂閱推送的

    淺談我是如何用redis做實時訂閱推送的

    這篇文章主要介紹了淺談我是如何用redis做實時訂閱推送的,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03

最新評論

腾冲县| 缙云县| 吉木乃县| 金坛市| 灵山县| 定西市| 泰顺县| 时尚| 兴海县| 綦江县| 敦化市| 通海县| 迁西县| 民县| 绥江县| 云龙县| 兴和县| 太仆寺旗| 威信县| 河间市| 嘉兴市| 安康市| 晋城| 清流县| 双鸭山市| 赫章县| 靖边县| 大邑县| 巫溪县| 辉县市| 汶川县| 自治县| 万宁市| 闵行区| 积石山| 晋宁县| 新田县| 开江县| 龙岩市| 德令哈市| 久治县|