发布订阅
Redis发布订阅(pub/sub)是一种消息通信模式:发步者发送消息,订阅者接收消息
使用场景:
公众号、关注系统、网络聊天室、实时广播、实时提醒
特点:
- Redis发布订阅模式中,发步者可以有多个订阅者,一个订阅者也可以订阅多个发步者
常用命令:
- psubscribe pattern1 pattern2:订阅一个或多个符合给定模式的频道
- pubsub subcommand argument1 argument2:查看订阅与发布系统状态
- pubsub channel message:将消息发送到指定的频道
- punsubscribe pattern1 pattern2:退订给定模式的频道
- subscribe channel1 channel2:订阅一个或多个频道的信息
- unsubscribe channel1 channel2:退订给定的频道
建立实例模型:
- 在1号终端进入redis客户端并通过命令:subscribe channel_name 订阅一个频道
- 在2号终端进入redis客户端并通过命令:publish channel_name xxx 像目标频道发送一条消息
- 在1号终端此时应该可以看到该条消息
原理:
- 当通过subscribe命令订阅某频道后,redis-server里就会建立一个字典,字典的键就是一个个频道,值则是一个链表,链表中保存了所有订阅该频道的客户端
- subscribe命令的作用就是将客户端添加到给定channel的订阅链表中
- 通过publish命令向订阅者发送消息,redis-server会在它维护的字典中查找该channel,并遍历其对应的链表,将消息发送给所有订阅者
Springboot中整合Redis发布订阅
-
引入相关依赖
-
创建消息监听类
package com.demo.common; import org.springframework.stereotype.Component; @Component public class RedisReceiver { public void receiveMessage(String message) { // TODO 这里是收到通道的消息之后执行的方法 System.out.println(message); } }
-
创建Redis消息订阅配置类
package com.demo.Redis; import com.demo.common.RedisReceiver; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; @Configuration @EnableCaching public class RedisCacheConfig { @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); // 可以添加多个 messageListener,配置不同的交换机 container.addMessageListener(listenerAdapter, new PatternTopic("channel:test")); return container; } /** * 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法 * @param receiver * @return */ @Bean MessageListenerAdapter listenerAdapter(RedisReceiver receiver) { System.out.println("消息适配器1"); return new MessageListenerAdapter(receiver, "receiveMessage"); } @Bean StringRedisTemplate template(RedisConnectionFactory connectionFactory) { return new StringRedisTemplate(connectionFactory); } }
-
创建接口测试
主从复制
指将一台Redis服务器的数据,复制到其他的Redis服务器
前者称为主节点(master/leader),后者称为从节点(slave/follower)
特点:
- 数据的复制是单向的,只能由主节点复制到从节点
- 一个主节点可以有多个从节点,一个从节点只能有一个主节点
- 默认情况下,每台Redis-server都是主节点
- 主节点一般用于处理写请求,从节点一般用于处理读请求
作用:
- 主从复制一般用于读写分离的实现,目的是减少单服务器读业务的压力,以达到负载均衡
- 主从复制实现了数据的热备份,是持久化之外的一种数据沉余方式
- 当主节点出现故障时,可以由从节点提供服务,以实现故障的快速修复
- 主从复制是哨兵模式和Redis集群能够实施的基础,即是Redis高可用的基础
建立主从复制模型:
redis-cli执行info replication命令,可以查看该服务主从复制相关配置信息
- 创建多个redis.conf配置文件,例如:redis-6379.conf、redis-6380.conf、redis-6381.conf
- 每个文件配置好port、pidfile、logfile、dbfilename四个属性(不能相同)
- 如过主服务设置有密码,从服务的conf文件里需要加上:masterauth
-
依次启动所有的Redis-server,执行
查看服务启动情况
-
分别进入从机cli,执行slaveof host port命令,认定主机
若要恢复为主机,可以执行命令:slaveof no one
通过命令配置是暂时的!重启后会失效,故一般通过修改配置文件建立主从复制
- redis.conf中配置replicaof
;masterauth 即可
须知:
- 主从模型建立好后,主机写入key,从机就可读取到key(自动增量复制)
- 一个主机变为从机,立刻会同步其主机的数据(进行一次全量复制)
- 只有主机可以写key,从机只能读key
- 主节点宕机,从节点还能进行数据的读取,主节点重启后,主从模型便恢复正常
哨兵模式
在上述的主从模型中,主节点宕机后,需要手动配置修改建立新的主从模型,或者重启主节点,才能恢复整个系统的读写功能,显然这不是一种推荐的方式!
Redis在2.8版本开始提供Sentinel(哨兵)架构来解决这一问题
特点:
- 能够监控主节点是否故障,若故障,根据投票自动将从节点转为主节点
- Sentinel是一个独立的进程,会独立运行
- 主节点宕机被替换后,再次启动,会变为从节点加入系统
原理:
- Sentinel通过发送命令,等待Redis服务器响应,从而监控运行多个redis-server实例
- 当哨兵监测到master宕机,会将一个slave切换成master,之后通过发布订阅模式通知其他的从节点,完成配置文件的修改,认到新的主节点
多哨兵模式:
- 一个哨兵进程也可能出现故障,从而使系统存在风险,为此,我们可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,这样就形成了多哨兵模式
- 若在上图模型中,master宕机,哨兵1先监测到这个结果,系统并不会马上进行failover(故障转移),在其他哨兵也监测到master不可用时(监测到的哨兵达到一定数量),哨兵之间就会进行一次投票,最终投票结果由一个哨兵发出,然后进行failover;最终主节点切换成功后,会通过发布订阅模式,让各个哨兵把自己监控的从节点切换其所认定的主节点
- 在哨兵1检测到master宕机时,称之为master的主观下线,其他哨兵也检测到并开始投票时,称之为客观下线
哨兵模式的使用:
-
bin目录建立sentinel.conf文件,进行sentinel的配置
-
sentinel monitor
-
如:sentinel monitor myredis 127.0.0.1 6379 1
-
表示当quorum个数的sentinel哨兵监测到master节点故障时,master客观下线,开始投票 - 若主机有密码,还需配置密码:sentinel auth-pass
-
-
启动哨兵进程:redis-sentinel myconfig/sentinel.conf
上面是简单的单哨兵的使用,多哨兵还需建立不同的配置文件,并分别配置端口等其他配置
缓存穿透
很多系统在把Redis作为缓存数据库来使用时,通常有这样的设定:读的请求先去缓存中查询,若缓存中没有,再去关系型数据中查询
这时若有人频繁查询一个或多个缓存数据库中没有的元素,就会加重关系型数据库的压力,这种情况被称之为缓存穿透
解决方案:
-
布隆过滤器
一种数据结构,对所有可能查询的参数以hash形式储存,在控制层先进行校验,不符合则丢弃,从而避免了对底层储存系统的查询压力
-
缓存空对象
当存储层不命中后,即使返回空对象,也将其缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,从而保护底层储存系统
缓存击穿
指一个key受到了高并发的访问,如新闻热搜,当这个key在失效的瞬间(过期),持续的大并发就会直接去请求底层储存系统,就像是在屏障上凿开了一个洞
解决方案:
-
设置热点数据永不过期
-
加分布式锁(在底层储存系统)
使用锁机制,保证对于每个key,在同一时间只有一个线程去访问,其他线程由于没有获得分布式锁的权限,从而进行等待;
这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
缓存雪崩
指某一时间段,缓存集中过期失效;如Redis宕机,或大量数据集中过期,而对于这些数据的访问,就会一时间落在底层上,对其产生周期性的压力
解决方案:
-
Redis集群的搭建,异地多活
-
流量降级
暂时停掉一些不重要的服务;分布式锁
-
数据预热
在发生大并发访问之前,手动缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀