Redis相关技术点
一,Redis持久化方式
方式一:RDB方式
Redis DataBase: 持久化内存数据到磁盘
Redis服务端,fork一个子进程,定时并且达到修改次数的时候写磁盘,写到rdb文件(dump.rdb)
fork函数的作用是创建一个子进程,并且和父进程运行同样的代码。
方式二:AOF方式
Append Only File :持久化修改数据的命令
客户端发起修改命令,到redis服务端,每秒、每个命令、不同步的方式到aof文件(appendonly.aof)
两种方式的对比
- 保存内容 RDB保存的是二进制文件,AOF保存的是Redis命令
- 数据恢复速度 RDB快照恢复速度快,AOF命令过多速度慢
- 数据恢复完整性 RDB可能会丢数据,AOF比RDB恢复完整性高
如何能够最大化保证恢复数据的速度以及数据的完整性?
混合持久化 Redis 4.0以后,以RDB的方式全量持久化内存数据,保证数据恢复的速度,并以增量的方式持久化修改命令,保证数据的完整性,最终以RDB和AOF共存的方式写入AOF文件。
二,Redis 单机、主从、哨兵、集群的架构模式
单机模式:
缓存服务中,只有一台Redis对我们的应用提供服务。 因为只有一台Redis,缺点比较明显。Redis宕机时,应用就无法使用。并且只有一台Redis,吞吐量也比较低。
主从模式:
缓存服务中,只有一台主Redis和多台从Redis,主Redis提供写,从Redis提供读。实现读写分离,减轻单台Redis的压力。但是主Redis宕机时,需要手动选择从Redis。
哨兵模式:
缓存服务中,任然有主从Redis对外提供服务,并且有哨兵去监控主从Redis的状态,如果主Redis发生宕机时,就会在从Redis自动选择一台对外提供服务
这种模式可以解决可用性问题,但是只有一台Redis对外提供写服务,大量写操作情况下,任然会有问题,所有引入集群模式,解决可用性和吞吐量大的问题。
集群模式:
是通过多个独立的主从Redis对外提供服务,可用性和吞吐量的问题。
但应用具体读写哪一台主从Redis?
集群模式下,有16384个hash slot (hash_slot=crc16(key) mod 16384) 分别分布在主从上,根据key去算出hash槽的位置,确定在哪一个主从。
三,Redis分布式锁的实现
什么是分布式锁?
比如有多个服务端A,B,C 经过分布式锁对共有资源进行访问,只有A可以成功,B和C失败。
这种在分布式系统中控制多个进程对共有资源的访问称为分布式锁。
分布式锁具有的性质
- 互斥性 同一时刻,只有一个客户端可以获取锁
- 安全性 锁的获取和释放是同一个客户端
- 可用性 高可用的分布式锁系统及避免产生死锁
怎样用Redis实现分布式锁
setnx + expire 加锁
setnx 如果key不存在 set成功返回1,失败返回0,保证互斥
expire 设置过期时间,防止锁的长期持有或死锁
这种方式是不对的,因为setnx + expire 会发生异常导致死锁
正确方式是:
set原子方法加锁
SET key value NX EX expire-time;
Redis 2.6.12以后,直接使用set方法进行加锁,避免死锁。NX和EX为固定值,前者表示SET IF NOT Exist,后者表示添加过期时间,具体时间取最后一个参数。
比较删除解锁
DEL Key 前判断是否为加锁的客户端,可以通过添加客户端的唯一id(具体实现自己决定)到value中,每次删除前比较,一致再进行删除解锁,保证安全性。
四,Redis缓存穿透、击穿、雪崩问题
缓存的使用场景:
当用户使用我们的网站或者app时候,他们操作的数据基本上来源于底层数据库,那么当用户量比较大的时候,数据库的读写压力也会随之增加。一般情况下,我们会缓存热点数据
缓存数据的目的是,一方面让网站和app可以直接从缓存拿数据,有很快的响应。另一方面可以减轻数据库的负担,redis就是常用的缓存数据库。
缓存存在的问题,只有一个不可用的问题。当缓存不可用时,用户的请求会落在db上,在高并发或者有人恶意攻击的情况下,可能会导致db的崩溃。
缓存穿透 当用户访问了一个本身就不存在的缓存,那么用户的请求最终都会落在db上,在高并发或者有人恶意攻击的情况下,可能会导致db的崩溃。
解决:
- 使用布隆过滤器判断缓存中是否存在
- 为请求设置一个值为null的缓存,设置较短的过期时间
缓存击穿 当用户访问缓存数据库,发现缓存已经过期失效,那么就要去db中重新拿缓存,并且写入缓存数据库中。如果在这时候有高并发的请求,就会导致瞬间db压力过大。
解决:
- 热点数据的缓存永不过期。可以解决瞬间数据库压力过大的问题
- 采用分布式锁,缓存失效后只有一个线程更新并写入缓存数据库
缓存雪崩 大面积的缓存击穿或者服务不可用
解决:
- 使用Redis哨兵或者集群等架构提升可用性
- 采用和缓存击穿一样的方式
- 错开缓存数据的过期时间点,防止缓存大面积失效
五,主从复制
主从复制的应用场景:
比如说在某一台的主机上安装Redis,这台主机发生宕机或者损坏,就会导致服务不可用,或者数据丢失,所以一般情况下,我们会为一个Redis服务器设置多个从服务器,以达到防止数据丢失的目的。这种模式也可以实现读写分离,然后来提升整个Redis对外的吞吐量,最后可以联合哨兵模式来提升系统的可用性以及扩展性。
一旦牵扯主从这种框架就会涉及复制的问题。
Redis支持两种复制模式:
全量复制 是指主从服务器之间建立连接,从服务器发送sync命令向主服务器请求数据,主服务器通过bgsave 生成RDB文件,并且将RDB文件传给从服务器,这个阶段又可以称之为数据同步的阶段。在这个阶段,主服务器可能会接收其他的写命令,这个时候需要将缓存中的写命令也给到从服务器去执行,这个又称为命令传播的阶段。
redis 2.8 后增加增量复制,全量复制的save效率较低,也比较消耗资源
增量复制
主从服务器之间什么时候需要数据复制?
- 从服务器断线重连,断线期间有可能数据是不一致的,需要进行增量复制
- 新增节点,必须进行全量复制
是否进行增量复制,也就是我们需要考虑从服务器复制了多少,首先可以按照主服务器的ID去判断,如果主服务器的ID变了,就需要进行全量复制。其次也需要偏移量来记录,主服务器和从服务器之间的差距有多少,并且主服务器中维护了一个积压命令的缓冲区,如果偏移量在缓冲区范围内,就进行增量复制。