RedissonRelayedQueue
RedissonRelayedQueue 是 Redisson 提供的一个分布式队列实现,它基于 Redis 的发布/订阅机制(Pub/Sub)和队列结构来实现高效的分布式消息传递。RedissonRelayedQueue 是一种特殊的队列,它结合了 RQueue 和 RTopic 的特性,适用于需要在多个节点之间进行消息广播或任务分发的场景。
主要特点
-
Relay(中继)机制:
- 当一个生产者向
RedissonRelayedQueue添加元素时,该元素不仅会被放入队列中,还会被发布到一个相关的主题(topic)上。 - 所有订阅该主题的消费者都会收到这个消息的副本(即“中继”),从而实现消息的广播功能。
- 当一个生产者向
-
队列 + 广播:
- 它结合了传统队列(FIFO)和发布/订阅(Pub/Sub)的特性。
- 每个消费者都可以从队列中获取元素(像普通队列一样),同时也能通过订阅主题即时收到新元素(像 Pub/Sub 一样)。
-
分布式支持:
- 支持多节点部署,适用于分布式系统中任务的分发和广播。
-
异步处理:
- 支持异步操作,适合高并发场景。
使用场景
- 任务广播:当你希望将一个任务广播给多个消费者节点处理。
- 事件通知:用于在分布式系统中通知多个节点某个事件发生。
- 缓存一致性:当某个数据发生变化时,通知所有节点更新本地缓存。
- 日志聚合:将日志消息广播到多个日志处理服务。
示例代码
以下是一个简单的使用示例:
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)。
- 性能与资源:由于每个消息都会广播到所有订阅者,可能会增加网络流量和内存使用,需根据实际情况评估。
与 RQueue 和 RTopic 的区别
| 特性 | 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 会:
- 将
"Hello"存入名为myQueue的 Redis 列表结构中。 - 同时将
"Hello"发布到名为myQueue的 Redis 主题(RTopic)中。 - 所有监听
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) 方法。
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/19001488

浙公网安备 33010602011771号