Redis进阶学习

Redis进阶学习

一、发布订阅模式

Redis也可以实现类似与消息队列的功能,也就是发布订阅模式。拥有两个角色,发布者和订阅者。

  • 订阅者:可以订阅一个或多个频道(channel),但只能获取到订阅之后的消息。可以订阅同一个频道多次,这将会重复收到消息。

  • 发布者:发布的消息可以被多个订阅者消费,发布的消息不会进行持久化,这也是订阅者不能获取到订阅前的消息的原因。

1.简单使用
# 向test频道发送一条消息hello world
127.0.0.1:6379> publish test "hello world"
# 返回值表示这条消息被多少个消费者消费
(integer) 0
# 订阅test频道
127.0.0.1:6379> subscribe test
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:test"
3) (integer) 1

psubscribe可以订阅多个频道,若订阅相同频道,将收到多条重复消息。发布者也会显示有多个消费者。

2.总结

1). 这个模式经常被用于群聊,即时聊天等场景。在Redis中,我们可以对一个key进行发布订阅,那么在key上发布消息后,订阅者将收到消息。
2). 虽然Redis也提供了类似消息队列的功能,但仅仅是简单的发布订阅,和消息队列还是有很大差别的,比如说持久化,消息协议,消息传输保障等。所以redis仅适用于只需要简单实现发布订阅功能的项目,对于需要消息持久化,消息重发等场景的项目,还是要老老实实使用消息队列。


二、主从复制与哨兵模式

1.主从复制
1.1 简单介绍

默认的情况下,每个Redis实例都是以自己为主节点的(master),而生产环境下是必须保证高可用的,单机自然不可取的。

主从复制是指将数据从主Redis(master)复制到其他的从Redis(slave)。在使用主从复制时我们最少要保证一主二从,并且master节点用于写,slave节点用于读。主从复制有几个优点

  • 数据冗余:主从复制相当于数据的热备份。
  • 容灾恢复:可以理解为服务的冗余,当主节点出现问题,其他的节点可以进行替换。
  • 读写分离:主从复制配合读写分离,主节点负责写,从节点负责读,分摊了服务器的压力。
  • 高可用:主从复制是哨兵模式的基础,而哨兵模式是高可用的。
1.2原理

主从复制的原理是:从节点连接上主节点后,发送一条sync同步指令,然后master节点会收集所有的写命令,在后台收集完毕后发送给slave节点。主从复制有两种,一种是全量复制一种是增量复制,在slave连接上master后首先会进行一次全量复制,然后进行增量复制。

1.3简单使用
# 成为127.0.0.1:6379的子节点
slaveof 127.0.0.1:6379
info replication	# 查看信息

但这种通过命令的方式在每次重启都要重新搭建集群。更推荐使用修改redis配置文件的方式

replicaof 127.0.0.1 6379
masterauth <password>
1.4总结

大多是情况下我们都是对缓存进行读取,而读取的速率远高于写,所以读写分离是十分重要的。因为生产环境需要保证高可用,所以单机集群是不可取的,为了保证服务的稳定性,一主二从是最基本的结构


2.哨兵模式
2.1简单介绍

哨兵模式可以简单的理解为将主从复制自动化。主从复制当主节点出现问题的时候,我们需要手动的切换主节点,而哨兵模式则是自动检测各个节点,若master出现问题,则重新选举一个新的master。当旧master正常工作后,将成为一个slave节点。

2.2原理

启动一个新的进程,向各个节点发送指令让其返回运行状态,若发现master死亡,就通过发布订阅模式让slave节点自动选举并切换为master。如果有多个哨兵,哨兵之间也会互相监控

2.3简单使用

编写配置文件sentinel.conf

vim sentinel.conf

# 端口
port 26379
# sentinel monitor 名称 host port 1
# 监视的redis是master
sentinel monitor mymaster 127.0.0.1 6379 1

启动哨兵

redis-sentinel dtconfig/sentinel.conf
2.4总结

哨兵模式基于主从复制,所以具备主从复制的所有优点,并且不用手动切换master。哨兵模式主从之间可以切换,所以额外具备故障转移的优点。但哨兵模式配置比较麻烦,并且当集群容量达到上限时不好在线扩容。


三、缓存穿透、击穿、雪崩

1.缓存穿透
1.1 介绍

当用户需要查询一个redis中没有的数据时,这个请求就会去查询数据库,若数据库中也没有,则无法将该数据缓存在redis中。如果有人恶意攻击大量请求这条数据时,请求就会全部落在数据库上导致数据库承受不住压力而崩溃。

1.2 解决方法

其实理解了缓存穿透的原理就很好解决了,导致数据库崩溃的原因是redis和数据库中都没有这条数据,那么我们只需要允许redis缓存这条空值即可,或者拦截这条请求。

  • 布隆过滤器:布隆过滤器的原理就是对参数进行校验,将不符合规则的请求拦截在外,从而降低数据库的压力。

  • 缓存空对象:若数据库中没有这条数据,则保存一个空值到redis中。这样做虽然可以解决问题,但是也带来了问题:redis中可能存在过多的空值;redis和数据库可能出现数据不一致。

2.缓存击穿
2.1 介绍

一个热点key承载着高并发,在达到它失效时间的一瞬间,可能会导致大量的请求直接落在数据库上从而导致数据库瘫痪。

2.2 解决方案

解决之前首先要理解出现缓存击穿的原因,是因为一个承载高并发的key到达了失效时间,而由于高并发的原因,在没来得及更新redis中的数据之前,数据库就已经崩溃了。所以有两种解决方法

  • 设置热点key永不失效,这就让请求永远不会直接落在数据库上,但这样做实际不合理。
  • 数据库增加互斥锁:一次只能有一个请求进入数据库,其他的线程则等待一段时间。这样当其他请求恢复运行的时候就会发现redis中的数据已经更新了,就不会请求到数据库中。
3.缓存雪崩
3.1 介绍

当大量的key同时达到失效时间时,就会导致大量请求落在数据库中。

3.2 解决方案

因为时大量key同时过期导致的问题,所以我们可以给key设置不同的过期时间。

  • 分析用户行为,让key的过期时间尽可能的均匀分布。
  • 如果是因为redis宕机导致的雪崩,可以搭建redis主从集群,但也需要注意主从集群可能导致读到脏数据的问题。
  • 数据库加锁,同一时间只允许一个线程执行。
4.总结

穿透,击穿,雪崩的根本原因都是redis中无数据或数据过期导致数据库不能负担压力。同一的解决方法就是数据库加锁,但很明显会导致效率大大降低。对于可能出现的问题,我们可以从发生前,发生时,发生后入手。发生前我们可以做过滤,合理设置过期时间,发生时我们可以给数据库加锁,发生后我们可以对redis做集群扩展。


四、缓存与数据库更新

一般的项目里引入redis缓存后,数据就存在两份,一份在数据库中,一份在redis中。而为了保证数据的一致性,在更新数据时我们也需要对redis进行更新。那么就有几种方法

  1. 先更新数据库在更新缓存
  2. 先删缓存在更新数据库
  3. 先删除缓存再更新数据库最后再延迟删除缓存
  4. 先更新数据库再删除缓存

但其实这几种方法在高并发下各有各的问题:

  1. 先更新数据库在更新缓存,可能会导致数据不一致。线程A更新了数据库,在更新缓存之前,线程更新了数据库并更新了缓存,最后线程B又更新了缓存。这就导致了数据不一致。
  2. 先删缓存在更新数据库,redis中可能使脏数据。线程1删除了缓存,在更新数据库前,线程B将数据库中的数据读取到redis中,最后线程A才更新数据库。这就导致了redis中的数据使脏数据。
  3. 延迟双删,解决了数据一致性问题,但带来了性能问题。说一下为什么要延迟删除,因为要确保数据库已经更新之后再删除缓存
  4. 先更新数据库再删除缓存,当更新缓存的同时key过期,例如线程A读取数据,发现过期就读库,线程B更新数据库并删除缓存,此时线程A更新缓存,可能就会导致redis中的数据是脏数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值