【DB系列】Redis高级特性之发布订阅

文章目录
  1. I. 基本使用
    1. 1. 配置
    2. 2. 使用姿势
      1. a. 消息发布
      2. b. 订阅消息
      3. c. 测试case
    3. 3. 使用说明与应用场景
  2. II. 其他
    1. 0. 项目
    2. 1. 一灰灰Blog

通常来讲,当我们业务存在消息的业务逻辑时更多的是直接使用成熟的rabbitmq,rocketmq,但是一些简单的业务场景中,真的有必要额外的引入一个mq么?本文将介绍一下redis的发布订阅方式,来实现简易的消息系统逻辑

I. 基本使用

1. 配置

我们使用SpringBoot 2.2.1.RELEASE来搭建项目环境,直接在pom.xml中添加redis依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果我们的redis是默认配置,则可以不额外添加任何配置;也可以直接在application.yml配置中,如下

1
2
3
4
5
spring:
redis:
host: 127.0.0.1
port: 6379
password:

2. 使用姿势

redis的发布/订阅,主要就是利用两个命令publish/subscribe; 在SpringBoot中使用发布订阅模式比较简单,借助RedisTemplate可以很方便的实现

a. 消息发布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class PubSubBean {
@Autowired
private StringRedisTemplate redisTemplate;

public void publish(String key, String value) {
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.publish(key.getBytes(), value.getBytes());
return null;
}
});
}
}

b. 订阅消息

消息订阅这里,需要注意我们借助org.springframework.data.redis.connection.MessageListener来实现消费逻辑

1
2
3
4
5
6
7
8
9
public void subscribe(MessageListener messageListener, String key) {
redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.subscribe(messageListener, key.getBytes());
return null;
}
});
}

c. 测试case

写一个简单的测试case,来验证一下上面的发布订阅,顺带理解一下这个MessageListener的使用姿势;我们创建一个简单的WEB工程,提供两个rest接口

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
@RestController
@RequestMapping(path = "rest")
public class DemoRest {
@Autowired
private PubSubBean pubSubBean;

// 发布消息
@GetMapping(path = "pub")
public String pubTest(String key, String value) {
pubSubBean.publish(key, value);
return "over";
}

// 新增消费者
@GetMapping(path = "sub")
public String subscribe(String key, String uuid) {
pubSubBean.subscribe(new MessageListener() {
@Override
public void onMessage(Message message, byte[] bytes) {
System.out.println(uuid + " ==> msg:" + message);
}
}, key);
return "over";
}
}

下面通过一个动图来演示一下case

a.gif

我们先创建了两个消费者,然后发送消息时,两个都收到;再新增一个消费者,发送消息时,三个都能收到

3. 使用说明与应用场景

redis的发布订阅,只适用于比较简单的场景,从上面的使用说明也能看出,它就是一个简单的发布订阅模型,支持1对N,而且发送的消息,只有在线的消费者才能get到(至于不在线的,那就只能说遗憾了)而且对于redis而言,消息推出去之后就完事了,至于消费者能不能正常消费,那就不care了

划重点:

  • 只有在线的消费者能接收到消息
  • 对于消费者一个消息只能拿到一次

接下来的问题就来了,什么样的场景下可以使用redis的发布订阅呢?

基于内存的缓存失效

利用reids + 内存做二级缓存,可以说是比较常见的方式了,借助基于内存的缓存,可以有效的提高系统的负载,但是问题也很明显,内存中缓存数据失效是个问题,特别是当一个应用部署多台服务器时,如果我希望同时失效所有服务器的某个内存缓存,使用redis的发布/订阅就是一个比较好的选择

SpringCloud Config配置刷新

使用SpringCloud Config做配置中心的小伙伴可能会经常遇到这个问题,配置修改之后的动态刷新是个问题(当然官方是支持通过mq走bus总线来同步,也可以通过spring boot admin来强刷)

借助redis发布/订阅,实现配置动态刷新也是一个不错的备选方案(后面给出一个具体的实现demo,如有兴趣请持续关注一灰灰Blog)

redis key失效订阅

我们在使用redis做缓存时,通常会设置一个过期时间,redis提供了一个过期的事件,当然默认是不开启的;我们也是可以通过subscribe来订阅缓存失效的事件

修改配置,开启key失效事件

1
notify-keyspace-events Ex

重启redis之后,订阅失效事件即可

1
subscribe __keyevent@0__:expired

II. 其他

0. 项目

系列博文

工程源码

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到