RedissonRelayedQueue

RedissonRelayedQueue 是 Redisson 提供的一个分布式队列实现,它基于 Redis 的发布/订阅机制(Pub/Sub)和队列结构来实现高效的分布式消息传递。RedissonRelayedQueue 是一种特殊的队列,它结合了 RQueueRTopic 的特性,适用于需要在多个节点之间进行消息广播或任务分发的场景。

主要特点

  1. Relay(中继)机制

    • 当一个生产者向 RedissonRelayedQueue 添加元素时,该元素不仅会被放入队列中,还会被发布到一个相关的主题(topic)上。
    • 所有订阅该主题的消费者都会收到这个消息的副本(即“中继”),从而实现消息的广播功能。
  2. 队列 + 广播

    • 它结合了传统队列(FIFO)和发布/订阅(Pub/Sub)的特性。
    • 每个消费者都可以从队列中获取元素(像普通队列一样),同时也能通过订阅主题即时收到新元素(像 Pub/Sub 一样)。
  3. 分布式支持

    • 支持多节点部署,适用于分布式系统中任务的分发和广播。
  4. 异步处理

    • 支持异步操作,适合高并发场景。

使用场景

  • 任务广播:当你希望将一个任务广播给多个消费者节点处理。
  • 事件通知:用于在分布式系统中通知多个节点某个事件发生。
  • 缓存一致性:当某个数据发生变化时,通知所有节点更新本地缓存。
  • 日志聚合:将日志消息广播到多个日志处理服务。

示例代码

以下是一个简单的使用示例:

import org.redisson.Redisson;
import org.redisson.api.RQueue;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonRelayedQueueExample {

    public static void main(String[] args) {
        // 配置 Redisson 客户端
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");

        RedissonClient redisson = Redisson.create(config);

        // 创建或获取一个 relayed queue
        RQueue<String> queue = redisson.getQueue("myRelayedQueue");

        // 创建一个生产者线程
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                String message = "Message " + i;
                queue.add(message);
                System.out.println("Produced: " + message);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // 创建多个消费者线程
        for (int i = 0; i < 3; i++) {
            int consumerId = i;
            new Thread(() -> {
                while (true) {
                    try {
                        String message = queue.poll();
                        if (message != null) {
                            System.out.println("Consumer " + consumerId + " received: " + message);
                        } else {
                            Thread.sleep(500); // 没有消息时等待
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

        // 可以通过 topic 订阅消息
        RTopic<String> topic = redisson.getTopic("myRelayedQueue");
        topic.addListener((channel, msg) -> {
            System.out.println("Received via topic: " + msg);
        });
    }
}

注意事项

  • 队列与主题名称一致RedissonRelayedQueue 内部会自动创建一个同名的 RTopic,用于消息的广播。
  • 消息持久化:如果需要消息持久化,请确保 Redis 配置了持久化策略(如 RDB 或 AOF)。
  • 性能与资源:由于每个消息都会广播到所有订阅者,可能会增加网络流量和内存使用,需根据实际情况评估。

RQueueRTopic 的区别

特性 RQueue RTopic RedissonRelayedQueue
消息存储
消息广播
消费方式 拉取(poll) 推送(监听) 拉取 + 推送
适用场景 点对点任务分发 事件广播 分布式广播 + 队列

RedissonRelayedQueue.offer() 是 Redisson 提供的分布式队列方法之一,用于向队列中添加一个元素,并返回是否成功true 表示成功,false 表示失败),与 Java 的 Queue.offer() 接口一致。

RedissonRelayedQueue 中,offer() 方法不仅会将元素放入队列中,还会通过 Redis 的 Pub/Sub(发布/订阅)机制 将该元素广播给所有订阅者,实现“中继”效果。


✅ 方法定义

boolean offer(E e);
  • 参数e 是要添加的元素(可以是任意可序列化的对象)。
  • 返回值:如果元素成功入队,返回 true;否则返回 false
  • 不会阻塞:如果队列已满(虽然 Redisson 的队列通常是无界的),会立即返回 false

🔄 与 add() 的区别

方法 是否阻塞 是否抛出异常 是否广播
add(E e) 是(队列满时抛出异常)
offer(E e) 否(返回布尔值)

🔁 广播机制说明

当你调用:

RQueue<String> queue = redisson.getQueue("myQueue");
queue.offer("Hello");

Redisson 会:

  1. "Hello" 存入名为 myQueue 的 Redis 列表结构中。
  2. 同时将 "Hello" 发布到名为 myQueue 的 Redis 主题(RTopic)中。
  3. 所有监听 myQueue 主题的消费者都会收到这个消息(即时推送)。

🧪 示例代码

RedissonClient redisson = Redisson.create(config);

// 获取 relayed queue
RQueue<String> queue = redisson.getQueue("myQueue");

// 添加监听器,用于接收广播消息
RTopic<String> topic = redisson.getTopic("myQueue");
topic.addListener((channel, msg) -> {
    System.out.println("Broadcast received: " + msg);
});

// 使用 offer 添加消息
boolean success = queue.offer("Test message");
if (success) {
    System.out.println("Message enqueued successfully.");
} else {
    System.out.println("Failed to enqueue message.");
}

⚠️ 注意事项

  • 序列化要求:放入队列的对象必须是可序列化的,默认使用 Jackson 或自定义的 Codec
  • 广播性能:由于每次 offer() 都会触发广播,可能会增加网络流量,请根据业务需求评估是否需要监听。
  • 非阻塞特性:适合高并发场景,但需要注意处理返回值,避免消息丢失。

🧠 适用场景

  • 即时任务广播:如通知多个服务节点刷新缓存。
  • 分布式事件通知:如订单创建后通知多个下游服务。
  • 日志或监控消息分发:将日志消息广播给多个日志处理系统。

如果你需要使用 offer() 并指定超时时间(阻塞等待队列有空间),可以使用 offer(E e, long timeout, TimeUnit unit) 方法。

posted @ 2025-07-23 20:13  chuangzhou  阅读(51)  评论(0)    收藏  举报