Redis支持数据持久化,众多数据结构存储,master-slave模式数据备份等多种功能。
Redis持久化
持久化主要是Redis故障后,从备份中读取数据,尽快恢复对外提供服务。
Redis持久化的两种方式
RDB
RDB(Redis DataBase)持久化机制,对Redis中的数据执行周期性的持久化。
- RDB会生成多个数据文件,每个数据文件都代表了某一时刻中的redis数据,这种多个文件的方式非常适合做冷备(冷备是主服务器停止运行后,备用服务器开始运行);
- RDB备份时对性能影响很小,Redis主进程会fork一个子进程执行磁盘IO,如果文件特别大,可能导致对客户端提供服务暂停数毫秒,甚至数秒;
- 相比AOF通过写入指令,RDB直接恢复数据时更快;
- RDB可能丢失数据,一般RDB快照文件间隔5分钟,如果Redis宕机,那么就可能丢失最大5分钟的数据。
AOF
AOF(Append Only File)对每条写入指令作为日志,以append-only
的模式写入一个日志文件中,在Redis重启的时候,以回放AOF日志中的写入指令重新构建整个数据库。
- AOF可以更好的保护数据不丢失,一般AOF会间隔1s通过一个后台进程执行一次
fsync
操作,最多丢失1s的数据; - AOF日志以
append-only
模式写入,所有没有任何磁盘寻址的开销,写入性能非常高,而且文件不易损坏。 - AOF日志文件即使很大的适合,需要重写操作,也不会影响客户端的读写。因为在
rewrite
log的时候,会对其中的指令进行压缩,创建一份恢复数据需要最小的文件。在创建新日志文件的时候,老日志文件照常写入,当新的日志文件ready后,再进行交换。 - AOF开启后,支持的QPS(Queries Per Second,每秒能处理查询数目)会比RDB支持的低,因为AOF一般配置成每秒
fsync
一次日志文件。
RDB or AOF?
Redis支持同时开启两种持久化方式,所以可以综合两种持久化机制,用AOF保证数据不丢失,作为数据恢复的第一选择;用RDB来做不同程度的冷备,在AOF文件都丢失或损坏的情况下使用RDB来进行文件的快速修复。
Redis数据淘汰策略
当Redis内存超出物理内存限制,或者超出maxmemory
时,Redis就需要使用淘汰策略淘汰无用的key。Redis策略如下
- volatile-lru:从设置过期时间的数据集中挑选出最近最少使用的数据淘汰,没有设置过期时间的key不会被淘汰。
- volatile-ttl:从设置过期时间的数据集中挑选出最早过期的数据淘汰,没有设置过期时间的key不会被淘汰。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。当内存达到限制无法写入非过期时间的数据集时,可以通过该淘汰策略在主键空间中随机移除某个key。
- allkeys-lru:从数据集挑选最近最少使用的数据淘汰,该策略要淘汰的key面向的是全体key集合,而非过期的key集合。
- allkeys-random:从数据集中选择任意数据淘汰。
- no-enviction:禁止驱逐数据,也就是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失,这也是系统默认的一种淘汰策略。
补充几个指令
# 获取当前maxmemory 64bit系统0代表无限制
CONFIG GET maxmemory
# 设置maxmemory
CONFIG SET maxmemory 100MB
常见面试问题
问:mysql里有2000w条数据,redis只存20w条热点数据,如何保证redis中的数据都是热点数据?
答:可以设置最大内容,然后设置淘汰策略volatile-lru或者volatile-ttl。
Redis缓存穿透
恶意用户模拟大量请求缓存中不存在的key,由于缓存中不存在,所以会进行数据库查询,造成数据库异常。
解决方案:
- 使用互斥锁,当请求key获取value为空时上锁,单机环境下使用同步锁,分布式环境使用分布式锁。从数据库获取数据后再释放锁。其他线程请求失败,需要等待一段时间再试。
- 接口限流和降级。重要的接口需要做好限流策略,防止用户恶意刷接口,同时做好降级准备,当接口中某些服务不可用时,进行熔断,失败快速返回机制。应对接口级故障:服务降级、熔断、限流、排队
- bloomfilter,布隆过滤器。快速判断key是否存在于集合中。
Redis缓存雪崩
多个key的过期时间相同,在同一时刻会出现大面积的缓存失效,在这时发生的请求会进行数据库查询导致连接异常。
解决方案:
- 使用互斥锁,同上
- 建立备份缓存,缓存A和缓存B,A设置超时时间,B不设超时时间。先从A读取缓存,A没有则读取B,并且更新A和B
- 设置缓存过期时间时加上一个随机时间,比如12h加上几分钟,避免缓存雪崩。
Redis缓存分区
就是将数据分布到不同的redis实例中,最常用的方式是范围分区和hash分区。
范围分区
映射一定范围的数据到特定的Redis实例,比如ID为1-10000的数据到R0,ID为10001-20000的数据到R1。
Hash分区
根据hash的一致性算法进行分区。
分区是多台redis共同作用的,如果其中一台宕机,则整个分片都不能用,虽然缓解了内存压力,但没有实现高可用,可以采用哨兵机制实现主从复制实现高可用(@标记,下一篇写这个)。