Redis(二)

154 阅读8分钟

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,而是应该把这个用户的所有信息存储到一张散列表里面