1. Redis持久化
1.1 为什么要持久化
- Redis是内存数据库,宕机后数据会消失。
- Redis重启后快速恢复数据,要提供持久化机制
- Redis持久化是为了快速的恢复数据而不是为了存储数据
- Redis有两种持久化方式:RDB和AOF
注意:Redis持久化不保证数据的完整性。
- 当Redis用作DB时,DB数据要完整,所以一定要有一个完整的数据源(文件、mysql)
- 在系统启动时,从这个完整的数据源中将数据load到Redis中 数据量较小,不易改变,比如:字典库(xml、Table) 通过info命令可以查看关于持久化的信息
1.2 RDB
1.2.1 RDB(Redis DataBase)
- 是redis默认的存储方式,RDB方式是通过快照完成的。
- 在指定的时间间隔内,将内存中的数据集的快照写入磁盘
- 默认保存在/usr/local/bin中,文件名dump.rdb;
1.2.2 参数配置
- 在redis.conf中配置:save 多少秒内 数据变了多少
save "" #不使用RDB存储 不能主从
save 900 1 # 表示15分钟(900秒钟)内至少1个键被更改则进行快照。
save 300 10 # 表示5分钟(300秒)内至少10个键被更改则进行快照。
save 60 10000 # 表示1分钟内至少10000个键被更改则进行快照。
1.2.3 RDB的优缺点
(1)优点
- RDB是二进制压缩文件,占用空间小,便于传输(传给slaver)
- 主进程fork子进程,可以最大化Redis性能,主进程不能太大,Redis的数据量不能太大,复制过程中主进程阻塞。
(2)缺点
- 不保证数据完整性,会丢失最后一次快照以后更改的所有数据。
1.3 AOF
1.3.1 AOF(append only file)
- AOF是Redis的另一种持久化方式。
- Redis默认情况下是不开启的。开启AOF持久化后Redis将所有对数据库进行过写入的命令(及其参数)(RESP)记录到 AOF 文件, 以此达到记录数据库状态的目的,
- 当Redis重启后只要按顺序回放这些命令就会恢复到原始状态了。
- AOF会记录过程,RDB只管结果。
1.3.2 AOF持久化实现
- 配置 redis.conf
#可以通过修改redis.conf配置文件中的appendonly参数开启 appendonly yes
#AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。
dir ./
# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof
#追写策略
appendfsync
always #每次数据变更,就会立即记录到磁盘,性能较差,但数据完整性好
everysec #默认设置,异步操作,每秒记录,如果一秒内宕机,会有数据丢失
no #不追写
1.4 RDB与AOF对比
- 1、RDB存某个时刻的数据快照,采用二进制压缩存储,AOF存操作命令,采用文本存储(混合)
- 2、RDB性能高、AOF性能较低
- 3、RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF设置为每秒保存一次,则最多丢2秒的数据
- 4、Redis以主服务器模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。
- 5、AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令。
1.5 RDB与AOF应用场景
- 内存数据库 rdb+aof 数据不容易丢
- 有原始数据源: 每次启动时都从原始数据源中初始化 ,则 不用开启持久化 (数据量较小)
- 缓存服务器 rdb 一般 性能高
在数据还原时
- 有rdb+aof 则还原aof,因为RDB会造成文件的丢失,AOF相对数据要完整。
- 只有rdb,则还原rdb
拉勾的配置策略
- 追求高性能:都不开 redis宕机 从数据源恢复
- 字典库 : 不驱逐,保证数据完整性 不开持久化
- 用作DB 不能主从 数据量小
- 做缓存 较高性能: 开rdb
- Redis数据量存储过大,性能突然下降,fork 时间过长 阻塞主进程,则只开启AOF
2. 缓存过期和淘汰策略
- 长期使用,key会不断增加,Redis作为缓存使用,物理内存也会满
- 内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降
2.1 缓存过期
2.1.1 expire
- 在Redis中可以使用expire命令设置一个键的存活时间(ttl: time to live),过了这段时间,该键就会自动 被删除。
set name yang
OK
127.0.0.1:6379> ttl name
(integer) -1 #永久有效
127.0.0.1:6379> expire name 20 #20秒失效
(integer) 1
127.0.0.1:6379> get name
"yang"
127.0.0.1:6379> ttl name #还有16秒失效
(integer) 16
127.0.0.1:6379> ttl name
(integer) 15
127.0.0.1:6379> ttl name
(integer) 9
127.0.0.1:6379> ttl name
(integer) 0
127.0.0.1:6379> ttl name #失效
(integer) -2
127.0.0.1:6379> get name
(nil)
2.1.2 setex
- 注意语法:setex key seconds value
127.0.0.1:6379> setex name 20 yang
OK
127.0.0.1:6379> get name
"yang"
127.0.0.1:6379> ttl name
(integer) 13
127.0.0.1:6379> get name
(nil)
2.2 maxmemory
- 在redis.conf中 maxmemory 默认为0 不限制 无最大内存限制
- maxmemory-policy 默认为noeviction (禁止驱逐) 不淘汰
- 设置maxmemory maxmemory-policy 要配置
2.2.1 不设置maxmemory的场景
- Redis的key是固定的,不会增加
- Redis作为DB使用,保证数据的完整性,不能淘汰 , 可以做集群,横向扩展
2.2.2 设置maxmemory的场景
- Redis是作为缓存使用,不断增加Key
- 设置多少与业务有关,1个Redis实例,保证系统运行 1 G ,剩下的就都可以设置Redis,约物理内存的3/4
- 命令: 获得maxmemory数
CONFIG GET maxmemory
- 设置maxmemory后,当趋近maxmemory时,通过缓存淘汰策略,从内存中删除对象
2.3 Redis的过期策略(过期键的删除策略)
- Redis中同时使用了惰性过期和定期过期两种过期策略。
2.3.1 定时过期(定时删除)
- 在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
- 需要创建定时器,而且消耗CPU,一般不推荐使用。
2.3.2 惰性过期(惰性删除)
- 在key被访问时如果发现它已经失效,那么就删除它。
- 只有当访问一个key时,才会判断该key是否已过期,过期则清除。
- 该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
2.3.3 定期过期(主动删除)
- 每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。
- 在redis.conf文件中可以配置主动删除策略,默认是no-enviction(不删除)
maxmemory-policy allkeys-lru
2.4 Redis的缓存淘汰策略(配置主动删除策略)
2.4.1 全局的键空间选择性移除
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
2.4.2 设置过期时间的键空间选择性移除
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
2.4.3 总结
- Redis的缓存淘汰策略的选取并不会影响过期的key的处理
- 缓存淘汰策略用于处理内存不足时的需要申请额外空间的数据
- 过期策略用于处理过期的缓存数据。
2.4.4 缓存淘汰策略的选择
- allkeys-lru : 在不确定时一般采用策略。 冷热数据交换
- volatile-lru : 比allkeys-lru性能差 存 : 过期时间
- allkeys-random:希望请求符合平均分布(每个元素以相同的概率被访问)
- 自己控制:volatile-ttl 缓存穿透
2.4.5 案例分享:字典库失效
-
拉勾早期将字典库,设置了maxmemory,并设置缓存淘汰策略为allkeys-lru,结果造成字典库某些字段失效,缓存击穿 , DB压力剧增,差点宕机。
-
分析:
字典库 : Redis做DB使用,要保证数据的完整性 maxmemory设置较小,采用allkeys-lru,会对没有经常访问的字典库随机淘汰当再次访问时会缓存击穿,请求会打到DB上。
- 解决方案:
1、不设置maxmemory
2、使用noenviction策略 Redis是作为DB使用的,要保证数据的完整性,所以不能删除数据。可以将原始数据源(XML)在系统启动时一次性加载到Redis中。
3、Redis做主从+哨兵 保证高可用
2.4.6 Redis如何做内存优化
- 尽可能使用散列表(hash),hash使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。
- 比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面