Redis 的发布/订阅(Pub/Sub)机制允许消息的发布者和订阅者之间进行松耦合的消息传递。发布者将消息发布到特定的频道,而订阅者可以订阅该频道以接收消息。这种机制非常适合用于实时通知、消息广播等场景。
Redis 发布/订阅机制的基本使用
以下是 Redis 发布/订阅机制的详细使用方法和示例代码。
1. 启动 Redis 服务
确保 Redis 服务器正在运行。你可以通过命令行启动 Redis:
bash
redis-server
2. 使用 Redis 客户端发布消息
可以使用 Redis 提供的客户端(如 Jedis)来发布和订阅消息。
发布者代码示例
java
import redis.clients.jedis.Jedis;
public class RedisPublisher {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
// 发布消息到频道 "my_channel"
jedis.publish("my_channel", "Hello, Redis!");
jedis.publish("my_channel", "Another message.");
}
}
}
订阅者代码示例
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class RedisSubscriber {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
// 创建订阅者
JedisPubSub jedisPubSub = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
};
// 订阅频道 "my_channel"
jedis.subscribe(jedisPubSub, "my_channel");
}
}
}
3. 运行发布者和订阅者
- 首先运行订阅者代码,订阅者将会等待接收来自
my_channel频道的消息。 - 然后运行发布者代码,发布者将消息发布到
my_channel频道。订阅者将接收到并打印这些消息。
4. 详细示例:多个发布者和多个订阅者
发布者示例
java
import redis.clients.jedis.Jedis;
public class RedisPublisher {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
for (int i = 0; i < 5; i++) {
String message = "Message " + i;
System.out.println("Publishing message: " + message);
jedis.publish("news_channel", message);
try {
Thread.sleep(1000); // 等待1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
订阅者示例
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class RedisSubscriber {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
// 创建订阅者
JedisPubSub jedisPubSub = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
System.out.println("Subscribed to channel: " + channel);
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
System.out.println("Unsubscribed from channel: " + channel);
}
};
// 订阅频道 "news_channel"
jedis.subscribe(jedisPubSub, "news_channel");
}
}
}
5. 使用模式匹配订阅
除了订阅特定的频道外,Redis 还支持模式匹配订阅。模式订阅者可以订阅符合特定模式的所有频道。
模式订阅示例
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class RedisPatternSubscriber {
public static void main(String[] args) {
try (Jedis jedis = new Jedis("localhost")) {
// 创建模式订阅者
JedisPubSub jedisPubSub = new JedisPubSub() {
@Override
public void onPMessage(String pattern, String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel + " matching pattern: " + pattern);
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
System.out.println("Subscribed to pattern: " + pattern);
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
System.out.println("Unsubscribed from pattern: " + pattern);
}
};
// 订阅匹配 "news.*" 模式的所有频道
jedis.psubscribe(jedisPubSub, "news.*");
}
}
}
6. 发布订阅注意事项
- 消息丢失:Redis Pub/Sub 机制不保证消息的持久化。如果没有订阅者在线,消息将被丢弃。
- 消息顺序:消息按照发布的顺序被订阅者接收,但如果有多个订阅者,顺序不保证在所有订阅者之间一致。
- 性能:对于高流量或需要消息持久化的场景,可以考虑使用 Redis Streams 或其他消息队列系统(如 Kafka、RabbitMQ)。
7. 高级示例:多线程环境下的发布订阅
多线程发布者
java
import redis.clients.jedis.Jedis;
public class MultiThreadRedisPublisher implements Runnable {
private String channel;
private String message;
public MultiThreadRedisPublisher(String channel, String message) {
this.channel = channel;
this.message = message;
}
@Override
public void run() {
try (Jedis jedis = new Jedis("localhost")) {
jedis.publish(channel, message);
System.out.println("Published message: " + message + " to channel: " + channel);
}
}
public static void main(String[] args) {
Thread publisher1 = new Thread(new MultiThreadRedisPublisher("channel1", "Hello from publisher 1"));
Thread publisher2 = new Thread(new MultiThreadRedisPublisher("channel2", "Hello from publisher 2"));
publisher1.start();
publisher2.start();
}
}
多线程订阅者
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class MultiThreadRedisSubscriber implements Runnable {
private String channel;
public MultiThreadRedisSubscriber(String channel) {
this.channel = channel;
}
@Override
public void run() {
try (Jedis jedis = new Jedis("localhost")) {
JedisPubSub jedisPubSub = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
};
jedis.subscribe(jedisPubSub, channel);
}
}
public static void main(String[] args) {
Thread subscriber1 = new Thread(new MultiThreadRedisSubscriber("channel1"));
Thread subscriber2 = new Thread(new MultiThreadRedisSubscriber("channel2"));
subscriber1.start();
subscriber2.start();
}
}
通过这些示例代码,展示了如何使用 Redis 的发布/订阅机制,包括基本的发布和订阅、模式匹配订阅以及多线程环境下的发布和订阅。Redis 的发布/订阅机制非常强大,可以用于各种实时消息传递的场景。