⏰ Redis延迟队列:让任务"睡个好觉"再执行

25 阅读13分钟

考察点: Sorted Set、ZRANGEBYSCORE、定时轮询、可靠性

🎬 开场:一个关于"闹钟"的故事

想象你是个健忘的人 🧠:

场景1:普通队列(立即执行)

你:今天要买牛奶!
大脑:收到!立即提醒!
你:不是现在,是下午3点!
大脑:不行,我只会立即提醒...😅

场景2:延迟队列(定时执行)

你:今天下午3点提醒我买牛奶
大脑:好的,设置闹钟,3点准时提醒!⏰
(到了3点)
大脑:该买牛奶了!
你:完美!😎

Redis延迟队列就是这样的"智能闹钟"! 📱


第一部分:什么是延迟队列? 🤔

1.1 延迟队列的定义

延迟队列(Delay Queue) = 消息在指定时间之后才能被消费

普通队列:
生产者 → [消息1][消息2][消息3] → 消费者(立即消费)

延迟队列:
生产者 → [消息1(3秒后)][消息2(10秒后)][消息3(60秒后)]
              ↓              ↓              ↓
         等待3秒        等待10秒       等待60秒
              ↓              ↓              ↓
            消费者          消费者         消费者

1.2 延迟队列的应用场景

场景1:订单超时取消 ⏱️

用户下单 → 30分钟未支付 → 自动取消订单

实现:
1. 用户下单时,将订单ID放入延迟队列(延迟30分钟)
2. 30分钟后,消息被取出
3. 检查订单状态,如果未支付,取消订单

场景2:定时发送通知 📧

用户预约体检 → 体检前1天发送提醒短信

实现:
1. 用户预约时,将提醒任务放入延迟队列
2. 延迟时间 = 体检时间 - 1天 - 当前时间
3. 到期后发送短信

场景3:延迟重试 🔄

调用第三方API失败 → 5秒后重试

实现:
1. 调用失败后,将任务放入延迟队列(延迟5秒)
2. 5秒后重新执行
3. 如果还失败,延迟10秒、30秒、60秒...(指数退避)

场景4:定时任务 📅

每天凌晨2点生成报表

实现:
1. 计算距离下次凌晨2点的时间差
2. 将任务放入延迟队列
3. 执行完后,再次添加(下一天凌晨2点)

1.3 延迟队列的要求

必须具备的特性:

  1. 支持延迟时间
  2. 到期后能被消费
  3. 保证消息不丢失
  4. 保证消息不重复消费(尽量)

第二部分:Redis实现延迟队列 🛠️

2.1 核心数据结构:Sorted Set

为什么用Sorted Set?

Sorted Set(有序集合)特点:
1. 成员唯一(不重复)
2. 按分数排序
3. 支持范围查询(ZRANGEBYSCORE)

完美匹配延迟队列需求:
- 成员 = 任务ID/消息内容
- 分数 = 执行时间戳
- 范围查询 = 取出到期的任务

2.2 基础实现(v1.0)

import redis
import time
import json

class DelayQueue:
    def __init__(self, redis_client, queue_name="delay_queue"):
        self.redis = redis_client
        self.queue_name = queue_name
    
    def push(self, message, delay_seconds):
        """
        添加延迟任务
        :param message: 任务内容
        :param delay_seconds: 延迟秒数
        """
        # 计算执行时间
        execute_time = time.time() + delay_seconds
        
        # 将任务添加到Sorted Set
        # score = 执行时间戳
        self.redis.zadd(
            self.queue_name,
            {json.dumps(message): execute_time}
        )
        print(f"✅ 任务已添加,将在 {delay_seconds} 秒后执行")
    
    def pop(self):
        """
        取出到期的任务
        :return: 任务内容 或 None
        """
        # 当前时间戳
        now = time.time()
        
        # 查询 score <= now 的任务(已到期)
        tasks = self.redis.zrangebyscore(
            self.queue_name,
            min=0,
            max=now,
            start=0,
            num=1  # 只取一个
        )
        
        if not tasks:
            return None
        
        task = tasks[0]
        
        # 删除任务(防止重复消费)
        self.redis.zrem(self.queue_name, task)
        
        # 返回任务内容
        return json.loads(task)
    
    def consume(self):
        """
        持续消费任务
        """
        print("🚀 延迟队列启动,等待任务...")
        
        while True:
            # 取出任务
            task = self.pop()
            
            if task:
                print(f"📨 收到任务: {task}")
                # 处理任务
                self.handle_task(task)
            else:
                # 没有任务,休息1秒
                time.sleep(1)
    
    def handle_task(self, task):
        """
        处理任务(业务逻辑)
        """
        print(f"✅ 执行任务: {task}")


# 使用示例
if __name__ == "__main__":
    # 连接Redis
    r = redis.Redis(host='localhost', port=6379, decode_responses=True)
    
    # 创建延迟队列
    queue = DelayQueue(r)
    
    # 添加任务
    queue.push({"orderId": "12345", "action": "cancel"}, delay_seconds=5)
    queue.push({"orderId": "67890", "action": "cancel"}, delay_seconds=10)
    
    # 消费任务
    queue.consume()

运行效果:

✅ 任务已添加,将在 5 秒后执行
✅ 任务已添加,将在 10 秒后执行
🚀 延迟队列启动,等待任务...
(5秒后)
📨 收到任务: {'orderId': '12345', 'action': 'cancel'}
✅ 执行任务: {'orderId': '12345', 'action': 'cancel'}
(10秒后)
📨 收到任务: {'orderId': '67890', 'action': 'cancel'}
✅ 执行任务: {'orderId': '67890', 'action': 'cancel'}

2.3 问题1:并发竞争(多消费者)

问题:

两个消费者同时pop:
消费者1: ZRANGEBYSCORE → 获取task1
消费者2: ZRANGEBYSCORE → 获取task1(重复!)
消费者1: ZREM task1
消费者2: ZREM task1

结果:task1被重复处理!

解决方案:使用Lua脚本保证原子性

class DelayQueue:
    def __init__(self, redis_client, queue_name="delay_queue"):
        self.redis = redis_client
        self.queue_name = queue_name
        
        # Lua脚本:原子性地获取并删除任务
        self.pop_script = """
        local queue_name = KEYS[1]
        local now = ARGV[1]
        
        -- 获取一个到期的任务
        local tasks = redis.call('ZRANGEBYSCORE', queue_name, 0, now, 'LIMIT', 0, 1)
        
        if #tasks == 0 then
            return nil
        end
        
        local task = tasks[1]
        
        -- 删除任务
        redis.call('ZREM', queue_name, task)
        
        return task
        """
    
    def pop(self):
        """
        原子性地取出任务
        """
        now = time.time()
        
        # 执行Lua脚本
        task = self.redis.eval(
            self.pop_script,
            1,  # KEYS数量
            self.queue_name,  # KEYS[1]
            now  # ARGV[1]
        )
        
        if task:
            return json.loads(task)
        return None

2.4 问题2:任务丢失(消费者崩溃)

问题:

消费者取出任务 → 开始处理 → 崩溃(任务丢失!)

解决方案:ACK机制(确认机制)

class ReliableDelayQueue:
    def __init__(self, redis_client, queue_name="delay_queue"):
        self.redis = redis_client
        self.queue_name = queue_name
        self.processing_queue = queue_name + ":processing"
        
        # Lua脚本:取出任务并加入处理队列
        self.pop_script = """
        local queue_name = KEYS[1]
        local processing_queue = KEYS[2]
        local now = ARGV[1]
        local timeout = ARGV[2]
        
        -- 获取任务
        local tasks = redis.call('ZRANGEBYSCORE', queue_name, 0, now, 'LIMIT', 0, 1)
        if #tasks == 0 then
            return nil
        end
        
        local task = tasks[1]
        
        -- 从延迟队列删除
        redis.call('ZREM', queue_name, task)
        
        -- 添加到处理队列(设置超时时间)
        local timeout_time = tonumber(now) + tonumber(timeout)
        redis.call('ZADD', processing_queue, timeout_time, task)
        
        return task
        """
    
    def pop(self, timeout=300):
        """
        取出任务(带超时保护)
        :param timeout: 处理超时时间(秒),默认5分钟
        """
        now = time.time()
        task = self.redis.eval(
            self.pop_script,
            2,
            self.queue_name,
            self.processing_queue,
            now,
            timeout
        )
        
        if task:
            return json.loads(task)
        return None
    
    def ack(self, task):
        """
        确认任务完成
        """
        task_str = json.dumps(task)
        self.redis.zrem(self.processing_queue, task_str)
        print(f"✅ 任务已确认: {task}")
    
    def retry_timeout_tasks(self):
        """
        重试超时的任务(定时任务,每分钟执行一次)
        """
        now = time.time()
        
        # 获取超时的任务
        timeout_tasks = self.redis.zrangebyscore(
            self.processing_queue,
            min=0,
            max=now
        )
        
        if timeout_tasks:
            print(f"⚠️ 发现 {len(timeout_tasks)} 个超时任务,重新加入队列")
            
            for task in timeout_tasks:
                # 从处理队列删除
                self.redis.zrem(self.processing_queue, task)
                
                # 重新加入延迟队列(立即执行)
                self.redis.zadd(self.queue_name, {task: now})
    
    def consume(self):
        """
        消费任务
        """
        print("🚀 可靠延迟队列启动...")
        
        while True:
            try:
                # 取出任务
                task = self.pop()
                
                if task:
                    print(f"📨 收到任务: {task}")
                    
                    try:
                        # 处理任务
                        self.handle_task(task)
                        
                        # 确认任务完成
                        self.ack(task)
                    except Exception as e:
                        print(f"❌ 任务处理失败: {e}")
                        # 不ACK,任务会超时后重试
                else:
                    # 没有任务,检查超时任务
                    self.retry_timeout_tasks()
                    time.sleep(1)
            except Exception as e:
                print(f"❌ 消费出错: {e}")
                time.sleep(1)
    
    def handle_task(self, task):
        """
        处理任务
        """
        # 模拟处理
        time.sleep(2)
        print(f"✅ 任务处理完成: {task}")

2.5 完整示例:订单超时取消

import redis
import time
import json
from datetime import datetime

class OrderCancelQueue:
    """订单超时取消延迟队列"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.queue = ReliableDelayQueue(redis_client, "order:cancel:queue")
    
    def create_order(self, order_id, timeout_minutes=30):
        """
        创建订单
        :param order_id: 订单ID
        :param timeout_minutes: 超时时间(分钟)
        """
        # 订单信息存储(模拟数据库)
        order = {
            "order_id": order_id,
            "status": "unpaid",  # 未支付
            "create_time": time.time()
        }
        self.redis.hset(f"order:{order_id}", mapping=order)
        
        # 加入延迟队列
        task = {
            "order_id": order_id,
            "action": "cancel_if_unpaid"
        }
        self.queue.push(task, delay_seconds=timeout_minutes * 60)
        
        print(f"📝 订单创建: {order_id}, {timeout_minutes}分钟后自动取消(如未支付)")
    
    def pay_order(self, order_id):
        """
        支付订单
        """
        self.redis.hset(f"order:{order_id}", "status", "paid")
        print(f"💰 订单已支付: {order_id}")
    
    def handle_cancel_task(self, task):
        """
        处理取消任务
        """
        order_id = task["order_id"]
        
        # 获取订单状态
        status = self.redis.hget(f"order:{order_id}", "status")
        
        if status == b"unpaid":
            # 未支付,取消订单
            self.redis.hset(f"order:{order_id}", "status", "cancelled")
            print(f"❌ 订单已取消: {order_id} (超时未支付)")
        else:
            # 已支付,不取消
            print(f"✅ 订单已支付: {order_id} (无需取消)")
    
    def start_consumer(self):
        """
        启动消费者
        """
        print("🚀 订单取消队列启动...")
        
        while True:
            task = self.queue.pop()
            
            if task:
                try:
                    self.handle_cancel_task(task)
                    self.queue.ack(task)
                except Exception as e:
                    print(f"❌ 处理失败: {e}")
            else:
                self.queue.retry_timeout_tasks()
                time.sleep(1)


# 使用示例
if __name__ == "__main__":
    r = redis.Redis(host='localhost', port=6379)
    order_queue = OrderCancelQueue(r)
    
    # 创建订单(30秒后超时)
    order_queue.create_order("ORDER001", timeout_minutes=0.5)  # 30秒
    order_queue.create_order("ORDER002", timeout_minutes=1)    # 60秒
    
    # 10秒后支付第一个订单
    time.sleep(10)
    order_queue.pay_order("ORDER001")
    
    # 启动消费者(在另一个进程/线程)
    order_queue.start_consumer()

运行结果:

📝 订单创建: ORDER001, 0.5分钟后自动取消(如未支付)
📝 订单创建: ORDER002, 1分钟后自动取消(如未支付)
(10秒后)
💰 订单已支付: ORDER001
(30秒后)
📨 收到任务: {'order_id': 'ORDER001', 'action': 'cancel_if_unpaid'}
✅ 订单已支付: ORDER001 (无需取消)
(60秒后)
📨 收到任务: {'order_id': 'ORDER002', 'action': 'cancel_if_unpaid'}
❌ 订单已取消: ORDER002 (超时未支付)

第三部分:进阶优化 🚀

3.1 多队列(按优先级)

class PriorityDelayQueue:
    """支持优先级的延迟队列"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.queues = {
            "high": "delay_queue:high",      # 高优先级
            "medium": "delay_queue:medium",  # 中优先级
            "low": "delay_queue:low"         # 低优先级
        }
    
    def push(self, message, delay_seconds, priority="medium"):
        """
        添加任务
        :param priority: high/medium/low
        """
        execute_time = time.time() + delay_seconds
        queue_name = self.queues[priority]
        
        self.redis.zadd(
            queue_name,
            {json.dumps(message): execute_time}
        )
    
    def pop(self):
        """
        按优先级取出任务
        """
        now = time.time()
        
        # 按优先级顺序检查
        for priority in ["high", "medium", "low"]:
            queue_name = self.queues[priority]
            
            tasks = self.redis.zrangebyscore(
                queue_name,
                min=0,
                max=now,
                start=0,
                num=1
            )
            
            if tasks:
                task = tasks[0]
                self.redis.zrem(queue_name, task)
                return json.loads(task), priority
        
        return None, None

3.2 批量消费(提高性能)

def pop_batch(self, batch_size=10):
    """
    批量取出任务
    """
    now = time.time()
    
    # 获取多个任务
    tasks = self.redis.zrangebyscore(
        self.queue_name,
        min=0,
        max=now,
        start=0,
        num=batch_size
    )
    
    if not tasks:
        return []
    
    # 批量删除
    self.redis.zrem(self.queue_name, *tasks)
    
    return [json.loads(task) for task in tasks]

def consume_batch(self):
    """
    批量消费
    """
    while True:
        tasks = self.pop_batch(batch_size=100)
        
        if tasks:
            print(f"📨 收到 {len(tasks)} 个任务")
            
            # 并行处理
            with ThreadPoolExecutor(max_workers=10) as executor:
                executor.map(self.handle_task, tasks)
        else:
            time.sleep(1)

3.3 监控和统计

def get_stats(self):
    """
    获取队列统计信息
    """
    now = time.time()
    
    # 总任务数
    total = self.redis.zcard(self.queue_name)
    
    # 到期任务数
    ready = self.redis.zcount(self.queue_name, 0, now)
    
    # 处理中任务数
    processing = self.redis.zcard(self.processing_queue)
    
    # 最早的任务
    earliest = self.redis.zrange(self.queue_name, 0, 0, withscores=True)
    
    stats = {
        "total": total,
        "ready": ready,
        "processing": processing,
        "waiting": total - ready
    }
    
    if earliest:
        task, score = earliest[0]
        wait_seconds = score - now
        stats["next_task_in"] = max(0, wait_seconds)
    
    return stats

# 使用
print(queue.get_stats())
# 输出:
# {
#     "total": 1000,
#     "ready": 50,
#     "processing": 10,
#     "waiting": 940,
#     "next_task_in": 3.5
# }

第四部分:与专业消息队列对比 🥊

4.1 Redis vs RabbitMQ延迟队列

特性RedisRabbitMQ
实现难度⭐⭐ 简单⭐⭐⭐ 中等
延迟精度秒级(轮询间隔)毫秒级
可靠性需要自己实现ACK内置支持
性能极高(10万+/秒)中等(1万/秒)
持久化支持(RDB/AOF)支持
适用场景中小型应用大型企业应用

4.2 Redis vs RocketMQ延迟消息

特性RedisRocketMQ
延迟级别任意时间固定18级
最大延迟无限制2小时
消息顺序不保证支持
事务Lua脚本分布式事务
适用场景灵活延迟标准延迟

4.3 何时用Redis?

✅ 适合用Redis:
- 延迟时间需要灵活控制
- 数据量不是特别大(百万级以下)
- 已经有Redis,不想引入新组件
- 对性能要求高
- 可以接受秒级精度

❌ 不适合用Redis:
- 需要毫秒级精度
- 消息量特别大(千万级以上)
- 需要复杂的消息路由
- 需要强一致性保证

第五部分:生产环境最佳实践 💼

5.1 完整的生产级实现

import redis
import time
import json
import logging
from concurrent.futures import ThreadPoolExecutor

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ProductionDelayQueue:
    """
    生产级延迟队列
    特性:
    1. ACK机制(防止任务丢失)
    2. 超时重试
    3. 死信队列
    4. 监控统计
    5. 优雅关闭
    """
    
    def __init__(self, redis_client, queue_name="delay_queue"):
        self.redis = redis_client
        self.queue_name = queue_name
        self.processing_queue = queue_name + ":processing"
        self.dead_letter_queue = queue_name + ":dlq"
        self.retry_limit = 3
        self.running = False
        
        # Lua脚本
        self._init_scripts()
    
    def _init_scripts(self):
        """初始化Lua脚本"""
        # 原子性pop脚本
        self.pop_script = self.redis.register_script("""
            local queue = KEYS[1]
            local processing = KEYS[2]
            local now = tonumber(ARGV[1])
            local timeout = tonumber(ARGV[2])
            
            local tasks = redis.call('ZRANGEBYSCORE', queue, 0, now, 'LIMIT', 0, 1)
            if #tasks == 0 then
                return nil
            end
            
            local task = tasks[1]
            redis.call('ZREM', queue, task)
            redis.call('ZADD', processing, now + timeout, task)
            
            return task
        """)
    
    def push(self, message, delay_seconds, retry_count=0):
        """添加任务"""
        execute_time = time.time() + delay_seconds
        
        task_data = {
            "message": message,
            "retry_count": retry_count,
            "create_time": time.time()
        }
        
        self.redis.zadd(
            self.queue_name,
            {json.dumps(task_data): execute_time}
        )
        
        logger.info(f"Task added: {message}, delay: {delay_seconds}s")
    
    def pop(self, timeout=300):
        """取出任务"""
        now = time.time()
        task_str = self.pop_script(
            keys=[self.queue_name, self.processing_queue],
            args=[now, timeout]
        )
        
        if task_str:
            return json.loads(task_str)
        return None
    
    def ack(self, task_data):
        """确认任务完成"""
        task_str = json.dumps(task_data)
        removed = self.redis.zrem(self.processing_queue, task_str)
        
        if removed:
            logger.info(f"Task acknowledged: {task_data['message']}")
        return removed
    
    def nack(self, task_data, delay_seconds=60):
        """
        拒绝任务(重试)
        """
        task_str = json.dumps(task_data)
        self.redis.zrem(self.processing_queue, task_str)
        
        retry_count = task_data.get("retry_count", 0) + 1
        
        if retry_count <= self.retry_limit:
            # 重新加入队列(指数退避)
            delay = delay_seconds * (2 ** (retry_count - 1))
            self.push(
                task_data["message"],
                delay_seconds=delay,
                retry_count=retry_count
            )
            logger.warning(f"Task retrying: {task_data['message']}, retry: {retry_count}/{self.retry_limit}")
        else:
            # 超过重试次数,加入死信队列
            self.redis.lpush(self.dead_letter_queue, task_str)
            logger.error(f"Task moved to DLQ: {task_data['message']}")
    
    def retry_timeout_tasks(self):
        """重试超时任务"""
        now = time.time()
        
        timeout_tasks = self.redis.zrangebyscore(
            self.processing_queue,
            min=0,
            max=now
        )
        
        for task_str in timeout_tasks:
            task_data = json.loads(task_str)
            self.redis.zrem(self.processing_queue, task_str)
            
            logger.warning(f"Task timeout, retrying: {task_data['message']}")
            self.nack(task_data)
    
    def get_stats(self):
        """获取统计信息"""
        return {
            "queue_size": self.redis.zcard(self.queue_name),
            "processing": self.redis.zcard(self.processing_queue),
            "dead_letter": self.redis.llen(self.dead_letter_queue)
        }
    
    def start(self, handler, num_workers=10):
        """
        启动消费者
        :param handler: 任务处理函数
        :param num_workers: 工作线程数
        """
        self.running = True
        logger.info(f"Delay queue started with {num_workers} workers")
        
        with ThreadPoolExecutor(max_workers=num_workers) as executor:
            while self.running:
                try:
                    task_data = self.pop()
                    
                    if task_data:
                        # 提交任务到线程池
                        executor.submit(
                            self._process_task,
                            task_data,
                            handler
                        )
                    else:
                        # 检查超时任务
                        self.retry_timeout_tasks()
                        
                        # 打印统计
                        if int(time.time()) % 60 == 0:
                            logger.info(f"Stats: {self.get_stats()}")
                        
                        time.sleep(1)
                        
                except Exception as e:
                    logger.error(f"Consumer error: {e}")
                    time.sleep(1)
    
    def _process_task(self, task_data, handler):
        """处理任务"""
        try:
            message = task_data["message"]
            logger.info(f"Processing task: {message}")
            
            # 执行业务逻辑
            handler(message)
            
            # 确认任务完成
            self.ack(task_data)
            
        except Exception as e:
            logger.error(f"Task processing failed: {e}")
            # 拒绝任务(重试)
            self.nack(task_data)
    
    def stop(self):
        """优雅关闭"""
        logger.info("Stopping delay queue...")
        self.running = False


# 使用示例
def handle_order_cancel(message):
    """订单取消处理器"""
    order_id = message["order_id"]
    print(f"Cancelling order: {order_id}")
    time.sleep(2)  # 模拟处理
    print(f"Order cancelled: {order_id}")

if __name__ == "__main__":
    r = redis.Redis(host='localhost', port=6379, decode_responses=True)
    queue = ProductionDelayQueue(r, "order:cancel")
    
    # 添加任务
    queue.push({"order_id": "ORDER001"}, delay_seconds=10)
    queue.push({"order_id": "ORDER002"}, delay_seconds=20)
    
    # 启动消费者
    queue.start(handler=handle_order_cancel, num_workers=5)

5.2 监控脚本

import redis
import time

def monitor_delay_queue(redis_client, queue_name, interval=10):
    """监控延迟队列"""
    while True:
        stats = {
            "queue_size": redis_client.zcard(queue_name),
            "processing": redis_client.zcard(queue_name + ":processing"),
            "dlq": redis_client.llen(queue_name + ":dlq")
        }
        
        # 获取即将执行的任务数(未来1分钟)
        now = time.time()
        upcoming = redis_client.zcount(queue_name, now, now + 60)
        
        print(f"""
╔══════════════════════════════════╗
║     Delay Queue Monitor          ║
╠══════════════════════════════════╣
║ Queue Size:      {stats['queue_size']:>6}          ║
║ Processing:      {stats['processing']:>6}          ║
║ Dead Letter:     {stats['dlq']:>6}          ║
║ Upcoming (1min): {upcoming:>6}          ║
╚══════════════════════════════════╝
        """)
        
        time.sleep(interval)

🎓 总结:延迟队列选型

           [需要延迟队列?]
                 |
          ┌──────┴──────┐
          ↓             ↓
    [数据量多大?]   [精度要求?]
         |              |
    < 百万级        秒级可接受
         ↓              ↓
    [Redis延迟队列]    [Redis]
         
    > 千万级        毫秒级
         ↓              ↓
    [RocketMQ]      [RabbitMQ]

记忆口诀 🎵

延迟队列有妙用,
定时任务它能行。
ZSet分数存时间,
到期任务自动触。

原子操作用Lua脚本,
并发竞争不用愁。
ACK机制防丢失,
超时重试更可靠。

死信队列兜底线,
重试次数要限制。
监控统计不能少,
生产环境要完善!

面试要点 ⭐

  1. 实现原理:Sorted Set,score存时间戳,ZRANGEBYSCORE取出
  2. 并发问题:Lua脚本保证原子性
  3. 可靠性:ACK机制、超时重试、死信队列
  4. 性能优化:批量消费、多线程处理
  5. 适用场景:订单超时、定时提醒、延迟重试
  6. 对比其他:vs RabbitMQ、RocketMQ的优劣

最后总结:

Redis延迟队列就像智能闹钟 ⏰:

  • Sorted Set = 闹钟列表(按时间排序)
  • 消费者 = 你(定时检查闹钟)
  • ACK = 关闭闹钟(确认已响)
  • 重试 = 贪睡模式(5分钟后再响)

记住:简单场景用Redis,复杂场景用专业MQ! 🎯

加油,分布式系统架构师!💪