1.工作原理

Redis的发布订阅(pub/sub)是一种消息通信模式,客户端指定某个频道(channel)进行消息的发布和订阅,向channel发送消息的客户端称为发布者(pub),订阅并接收消息的客户端称为订阅者(sub)。
图片

2.存储结构

图片

图中可看出结构与Java的HashMap类似,并且关系结构中并没有涉及到发布者,可以断定客户端可以通过命令随意向channel发送消息。当消息发送到channel后,会遍历所有订阅此channel的客户端,逐个进行消息的推送。

3.终端命令

1
2
3
4
5
publish [channel] [message] // 向某个频道发布消息

subscribe [channel-0] [channel-1] // 订阅一个或多个频道消息

unsubscribe [channel] // 退订某频道消息

4.客户端命令

4.1 发布消息

RedisTemplate客户端提供了发布消息的API:

1
redisTemplate.convertAndSend("频道名称", "消息Object");

4.2 接受消息

关于订阅的配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Configuration
public class RedisConfig{

/**
* Redis消息监听器容器
* 这个容器加载了RedisConnectionFactory和消息监听器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
* @param connectionFactory 链接工厂
* @param adapter 适配器
* @return redis消息监听容器
*/
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter adapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//可以添加多个 messageListener
container.addMessageListener(adapter, new PatternTopic("频道名称1"));
container.addMessageListener(adapter, new PatternTopic("频道名称2"));
return container;
}

/**
* 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
* 将MessageReceiver注册为一个消息监听器,可以自定义消息接收的方法(handleMessage)
* 如果不指定消息接收的方法,消息监听器会默认的寻找MessageReceiver中的onMessage这个方法作为消息接收的方法
* @param messageReceiver 消息接受
* @return 适配器
*/
@Bean
public MessageListenerAdapter adapter(MessageReceiverSupport messageReceiver) {
return new MessageListenerAdapter(messageReceiver, "onMessage");
}
}

监听类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
@Slf4j
public class MessageReceiverSupport implements MessageListener {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Override
public void onMessage(Message message, byte[] pattern) {
RedisSerializer<String> redisSerializer = redisTemplate.getStringSerializer();
String msg= redisSerializer.deserialize(message.getBody());
System.out.println("接收到的消息是:"+ msg);
log.info("Received <" + msg + ">");
}
}

5.与MQ的区别

Redis仅仅提供了最基础的发布订阅功能,无法做到消息的持久化、重试等可靠机制,消息丢失概率较大,不适用消息密集或者可靠性要求很高的场景,甚至说有些鸡肋。另外各种MQ提供的负载均衡、消费模式、消息延迟、消息过滤、事务等可以满足各种复杂的业务场景,也是Redis无法实现的。

最后Redis的发布订阅完全基于内存操作,不过目前流行的MQ都会尽可能的将磁盘IO进行顺序读写,性能不会拉开太多差距,另外还可以通过增加队列来均摊压力,不考虑运维成本的情况下,性能也是优于Redis的。总体上说Redis发布订阅可以满足的场景,各种MQ都可以满足,因此在已经有MQ中间件的前提下,尽量不要考虑Redis的发布订阅。

6.应用场景

Redis内部的哨兵集群模式在相互监控的时候使用了此功能进行通信。

评论