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

Redis 延時隊列詳解

 更新時間:2026年06月30日 08:24:44   作者:用戶307459698207  
本文主要介紹了Redis 延時隊列詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、什么是延時隊列

普通隊列: 消息一到就消費
延時隊列: 消息到了先放著,到指定時間再消費

普通隊列:  [消息] → 立即消費
延時隊列:  [消息] → 等 30 分鐘 → 到期 → 消費

場景舉例:

  • 下單 30 分鐘未支付,自動取消
  • 紅包 24 小時未領取,自動退回
  • 會議開始前 5 分鐘,發(fā)送提醒
  • 7 天后自動確認收貨

二、為什么用 ZSet 實現(xiàn)

數(shù)據(jù)類型結構能做延時隊列嗎
List按插入排序? 不支持按時間排序
Set無序? 沒法指定執(zhí)行時間
ZSet按 score 排序? score 存到期時間戳
# ZSet 天然適合:
ZADD delay_queue 1718000000 "task_001"   # score=到期時間戳
ZADD delay_queue 1718000300 "task_002"   # 自動按時間排序

三、核心流程

生產(chǎn)者                     Redis ZSet                      消費者(定時任務)
──────                    ──────────                      ──────────────
XADD delay_q              score  = 到期時間戳
score=到期時間            member = 任務數(shù)據(jù)
                          ┌─────────────────┐
                          │ 1718000000 task1 │  ← 最早到期
                          │ 1718000300 task2 │
                          │ 1718000600 task3 │
                          └─────────────────┘
                                  ↓
                          ZRANGEBYSCORE 0 當前時間
                          取到 task1(已到期)
                                  ↓
                          執(zhí)行 task1 → ZREM 刪除

四、基礎實現(xiàn)(有并發(fā)問題)

// 生產(chǎn)者:投遞延時任務
$redis->zAdd('delay:orders', time() + 1800, json_encode([
    'order_id' => 12345,
    'action'   => 'auto_cancel',
]));
// 消費者:每秒輪詢到期任務(有 BUG 的版本)
$now = time();
$tasks = $redis->zRangeByScore('delay:orders', 0, $now, ['limit' => [0, 1]]);
if ($tasks) {
    $task = $tasks[0];
    // ?? 這里有 BUG!如果同時多個消費者拿到同一條
    $redis->zRem('delay:orders', $task);
    processTask($task);
}

問題在哪? ZRANGEBYSCOREZREM 是分開的,多個消費者可能同時拿到同一條任務!

五、Lua 腳本原子化(解決并發(fā))

-- 原子操作:查出到期任務 + 立刻刪除 + 返回
local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1], 'LIMIT', 0, 1)
if #tasks == 0 then
    return nil
end
local task = tasks[1]
local removed = redis.call('ZREM', KEYS[1], task)
if removed == 1 then
    return task       -- 刪除成功,返回任務
else
    return nil        -- 被別的消費者搶了
end

PHP 端調(diào)用:

$lua = <<<'LUA'
local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1], 'LIMIT', 0, 1)
if #tasks == 0 then return nil end
local task = tasks[1]
if redis.call('ZREM', KEYS[1], task) == 1 then
    return task
else
    return nil
end
LUA;
// 定時任務循環(huán)執(zhí)行
while (true) {
    $task = $redis->eval($lua, ['delay:orders', time()], 1);
    //                                      ↑ KEYS 部分       ↑ key數(shù)量
    if ($task) {
        $data = json_decode($task, true);
        echo "處理任務: {$data['order_id']}\n";
        processTask($data);
    } else {
        sleep(1);  // 沒任務就等一下
    }
}

六、完整實戰(zhàn):30 分鐘未支付自動取消

<?php
// ====== 生產(chǎn)者(下單時) ======
function createOrder($orderId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6380);
    // 1. 創(chuàng)建訂單...
    // 2. 投遞延時任務:30分鐘后自動取消
    $delayAt = time() + 1800;  // 30分鐘
    $task = json_encode([
        'order_id' => $orderId,
        'action'   => 'auto_cancel',
        'create_at'=> date('Y-m-d H:i:s'),
    ]);
    $redis->zAdd('delay:orders', $delayAt, $task);
    echo "訂單 {$orderId} 已創(chuàng)建,30分鐘后未支付將自動取消\n";
}
// ====== 消費者(定時腳本) ======
$lua = <<<'LUA'
local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1], 'LIMIT', 0, 1)
if #tasks == 0 then return nil end
if redis.call('ZREM', KEYS[1], tasks[1]) == 1 then
    return tasks[1]
end
return nil
LUA;
while (true) {
    $task = $redis->eval($lua, ['delay:orders', time()], 1);
    if ($task) {
        $data = json_decode($task, true);
        // 檢查訂單是否已支付
        $order = getOrder($data['order_id']);
        if ($order['status'] === 'unpaid') {
            cancelOrder($data['order_id']);
            echo "? 訂單 {$data['order_id']} 超時未支付,已自動取消\n";
        } else {
            echo "? 訂單 {$data['order_id']} 已支付,跳過\n";
        }
    } else {
        sleep(1);
    }
}

七、ZSet 延時隊列 vs 其他方案

方案原理優(yōu)點缺點
ZSetscore=時間戳,輪詢?nèi)?/td>簡單,Redis 自帶需要輪詢,精度秒級
Redis 過期回調(diào)key 過期觸發(fā)通知不用輪詢通知不可靠,可能丟失
RabbitMQ 延時插件消息自帶 TTL + 死信隊列專業(yè)可靠需要額外裝插件
數(shù)據(jù)庫輪詢定時掃表實現(xiàn)簡單大量數(shù)據(jù)時很慢

八、ZSet 的 score 誰來賦值的

ZADD key score member
          ↑
     你自己指定的

ZADD delay_queue 1718000000 "task_001"
#                 ↑    時間戳就是 score,你自己算的
#                 score 決定了 ZSet 里的排序

排序規(guī)則: score 越小越靠前,所以過期時間越早的排最前面。

九、Set vs ZSet 能不能做延時隊列

SetZSet
有序嗎? 無序? 按 score 排序
能查到期的嗎?? ZRANGEBYSCORE 0 now
能做延時隊列嗎不行可以

延時隊列的核心需求是"按時間排序、查到期任務",只有 ZSet 能做到。

十、面試常問

Q: 延時隊列為什么不用 List?

List 只能頭進頭出,無法按時間排序,不知道哪些消息到期了。

Q: 輪詢會不會性能差?

單次 ZRANGEBYSCORE + ZREM 是 O(log N),每秒輪詢對 Redis 壓力很小。10萬條延時任務也沒問題。

Q: 很大量級的延時任務怎么辦?

  1. 用多個 ZSet key 分桶(按分鐘/小時)
  2. 每個桶一個消費者線程
  3. 配合 Redis Cluster 分片

Q: 消息丟了怎么辦?

Redis 純內(nèi)存的話宕機會丟。重要業(yè)務建議:

  • AOF 持久化
  • 訂單狀態(tài)雙寫(Redis + DB),定時任務掃表兜底

Q: score 存毫秒級時間戳可以嗎?

可以,ZSet 的 score 是 double 浮點數(shù),毫秒時間戳完全放得下。

核心記?。篫Set 的 score 排序 + Lua 原子搶任務 = 可靠的延時隊列

到此這篇關于Redis 延時隊列詳解的文章就介紹到這了,更多相關Redis 延時隊列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Redis都做了哪些加快速度的設計

    Redis都做了哪些加快速度的設計

    這篇文章主要介紹了Redis都做了哪些加快速度的設計的相關資料,需要的朋友可以參考下
    2021-02-02
  • redis配置認證密碼的方法

    redis配置認證密碼的方法

    這篇文章主要介紹了redis配置認證密碼的方法,需要的朋友可以參考下
    2016-08-08
  • redis發(fā)布訂閱模式的實現(xiàn)

    redis發(fā)布訂閱模式的實現(xiàn)

    本文主要介紹了redis發(fā)布訂閱模式,Redis?的?SUBSCRIBE?命令可以讓客戶端訂閱任意數(shù)量的頻道,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-04-04
  • redis+lua實現(xiàn)限流的項目實踐

    redis+lua實現(xiàn)限流的項目實踐

    redis有很多限流的算法(比如:令牌桶,計數(shù)器,時間窗口)等,在分布式里面進行限流的話,我們則可以使用redis+lua腳本進行限流,下面就來介紹一下redis+lua實現(xiàn)限流
    2023-10-10
  • redis內(nèi)存空間效率問題的深入探究

    redis內(nèi)存空間效率問題的深入探究

    redis緩存固然高效,可是它會占用我們系統(tǒng)中寶貴的內(nèi)存資源,那該如何解決呢?這篇文章主要給大家介紹了關于redis內(nèi)存空間效率問題的相關資料,需要的朋友可以參考下
    2021-05-05
  • Redis數(shù)據(jù)庫的鍵管理示例詳解

    Redis數(shù)據(jù)庫的鍵管理示例詳解

    這篇文章主要為大家介紹了Redis數(shù)據(jù)庫的鍵管理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Redis?延時任務實現(xiàn)及與定時任務區(qū)別詳解

    Redis?延時任務實現(xiàn)及與定時任務區(qū)別詳解

    這篇文章主要為大家介紹了Redis?延時任務實現(xiàn)及與定時任務區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Redis?Hash序列化存儲的問題及解決方案

    Redis?Hash序列化存儲的問題及解決方案

    這篇文章主要介紹了Redis?Hash序列化存儲的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Redis 5.05 單獨模式安裝及配置方法

    Redis 5.05 單獨模式安裝及配置方法

    這篇文章主要介紹了Redis 5.05 單獨模式安裝,文中通過代碼給大家介紹了Redis 5.0.5 單節(jié)點 安裝配置方法,需要的朋友可以參考下
    2019-10-10
  • Redis集群利用Redisson實現(xiàn)分布式鎖方式

    Redis集群利用Redisson實現(xiàn)分布式鎖方式

    這篇文章主要介紹了Redis集群利用Redisson實現(xiàn)分布式鎖方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論

怀集县| 太保市| 柳江县| 沙河市| 多伦县| 文成县| 隆德县| 渑池县| 定西市| 大新县| 松江区| 盐池县| 祁门县| 新宾| 应城市| 辽阳市| 荣成市| 洛南县| 措勤县| 巫山县| 乌鲁木齐市| 新干县| 曲松县| 友谊县| 平和县| 新郑市| 锦屏县| 固原市| 县级市| 信丰县| 漯河市| 北海市| 郓城县| 永康市| 渝中区| 新兴县| 句容市| 凭祥市| 上虞市| 都安| 渑池县|