Redis 序列化器和持久化

Redis 序列化器

针对数据的序列化/反序列化提供了多种可选择策略 比如RedisSerializer,接下来我们详细看看
1、JdkSerializationRedisSerializer 用于 POJO 对象的存取场景,使用 JDK 本身序列化机制,将 pojo 类通过ObjectInputStream/ObjectOutputStream 进行序列化操作,最终 redis-server 中将存储字节列。是目前最常
用的序列化策略。
2、StringRedisSerializer用于Key和value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是 new String(bytes, charset)和 string.getBytes(charset)的直接封装,是最轻量级和高效的策略。
3、JacksonJsonRedisSerializer 是 jackson-json 工具提供的 javabean 与 json 之间的转换能力,可以将 pojo 实例序列化成 json 格式存储在 redis 中,也可以将 json 格式的数据转换成 pojo 实例。因为 jackson 工具在序列化和反序列化时,需要明确指定 Class 类型,因此此策略封装起来稍微复杂。

缓存与数据库双写不一致
缓存可以提升性能、缓解数据库压力,但是使用缓存也会导致数据不一致性的问题。一般写数据操作使用缓存
有三种经典的缓存模式
Cache-Aside Pattern
Read-Through/Write through
Write behind
这三种常见的更新策略实际上都是保证数据的最终一致性的方法,可以总结为
1、先更新数据库再更新缓存,后续线程会读取旧数据
2、先删除缓存再新数据库,并发线程读取旧数据并写到缓存
3、先更新数据库再删除缓存,后续线程会读取旧数据常见解决方案是延时双删,但是延时的时长不好控制
小小总结一下
总结:
1、并发几率很小的数据,几乎不用考虑,加上缓存过期时间,缓存失效后查询主动更新
2、业务上是否能容忍一定时间的不一致,如能容忍的话,加上缓存过期时间;如果不能容忍缓存数据不一致,可以通过加分布式读写锁保证并发读写或写写的时候按顺序排好队,读读的时候相当于无锁。
3、可以用阿里开源的 canal 通过监听数据库的 binlog 日志及时的去修改缓存,但是引入了新的中间件,增加了系统的复杂度

Cache-Aside Pattern 即旁路缓存模式,读操作:读的时候,先读缓存,缓存命中的话,直接返回数据;缓存没
有命中的话,就去读数据库,从数据库取出数据,放入缓存后,同时返回响应。写操作:更新的时候,先更新
数据库,然后再删除缓存。
Read-Through/Write-Through 读写穿透模式中,读操作:从缓存读取数据,读到直接返回;如果读取不到的
话,从数据库加载,写入缓存后,再返回响应。写操作:Write-Through 模式下,当发生写请求时,也是由缓存抽象层完成数据源和缓存数据的更新Write behind 异步缓存,一般写入是同步更新缓存和数据,Write Behind 则是只更新缓存,不直接更新数据库,通过批量异步的方式来更新数据库。适合频繁写的场景,MySQL 的 InnoDB Buffer Pool 机制就使用到这种模式

Redis 持久化

Redis 为了保证效率,数据缓存在了内存中,但是会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件中,以保证数据的持久化。总的目的把数据保存到硬盘,有 RDB 和 AOF 两种。
RDB 持久化方案: RDB 是一次的全量备份,快照形式是周期性直接把内存中的数据保存到一个 dump 文件中,定时保存。是 redis 默认的存储方式,推荐使用。
优点: 性能消耗的比较小,速度快
缺点: 容易丢失数据
AOF 持久化方案:把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,是命令的集合。
优点: 不容易丢失数据
缺点: 性能差,给客户的体验度不好
当 Redis 重启时会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。甚至可以关闭持久化功能,让数据只在服务器运行时存储

RDB 持久化

RDB 是默认的持久化方案:推荐使用的。Redis 生成二进制压缩的快照文件 xxx.rdb 保存到磁盘。
RDB 工作原理:当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write。定时生成 RDB 快照非常便于进行数据库备份,并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度快。Redis4.0
支持同时开启 RDB 和 AOF,系统重后,Redis 会优先使用 AOF 来恢复数据,这样丢失的数据会最少。
需要查看配置文件,满足三个条件中一个触发生成快照 rdb 文件。可以配置符合快照触发条件,默认的是 1 分钟内改动 1 万次,或者 5 分钟改动 10 次,或者是 15 分钟改动一次
save 900 1
save 300 10
save 60 10000
启动服务器的时候需要通过命令行启动,进入 reids 的安装目录 redis-server.exe redis.conf
save 命令:save 时只管保存,其他不管,全部阻塞
bgsave 命令:redis 会在后台进行快照操作,快照操作的同时还可以响应客户端的请求,可以通过 lastsave 命令获取最后一次成功执行快照的时间。

AOF 持久化

AOF 日志存储的是 redis 服务器的顺序指令序列,即对内存中数据进行修改的指令记录。当 redis 收到客户端修改指令后,先进行参数校验,如果校验通过,把该指令存储到 AOF 日志文件中,也就是先存到磁盘,然后再执行该修改指令。当 redis 宕机后重启后,可以读取该 AOF 文件中的指令,进行数据恢复,恢复的过程就是
把记录的指令再顺序执行一次,这样就可以恢复到宕机之前的状态。
打开 AOF 配置 redis.conf 中的 appendonly yes 就可以打开 AOF 功能,例如 appendfsync no 当设置 appendfsync为 no 的时候,Redis 不会主动调用 fsync 去将 AOF 日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数 Linux 操作系统,是每 30 秒进行一次 fsync,将缓冲区中的数据写到磁盘上。
appendfsync everysec 当设置 appendfsync 为 everysec 的时候,Redis 会默认每隔一秒进行一次 fsync 调用,将缓冲区中的数据写到磁盘。但是当这一次的 fsync 调用时长超过 1 秒时。Redis 会采取延迟 fsync 的策略,再等一秒钟。也就是在两秒后再进行 fsync,这一次的 fsync 就不管会执行多长时间都会进行。这时候由于在
fsync 时文件描述符会被阻塞,所以当前的写操作就会阻塞。
在绝大多数情况下,Redis 会每隔一秒进行一次 fsync。在最坏的情况下,两秒钟会进行一次 fsync 操作。这一操作在大多数数据库系统中被称为 group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。
appendfsync always 每一次写操作都会调用一次 fsync,这时数据是最安全的,当然由于每次都会执行 fsync,所以其性能也会受到影响

AOF 重写
因为 AOF 持久化是通过保存被执行的写命令来记录数据库状态的,那么就会涉及到很多无用的命令,如 set ab 和 set a c 以及 set a d,其实就最后一条有意义。
Redis 会 fork 一个进程来读取现在 redis 生成的 AOF 文件,然后在内存中去除冗余命令,在此过程中不会影响原来 AOF 文件的继续写入,如果有新的命令,会缓存在重写缓冲中,当重写完全结束后会替换掉原来的 AOF文件
重写触发条件:手动命令 BGREWRITEAOF 和配置自动调用
RDB 与 AOF 的选择
宕机后会优先加载 AOF 文件。RDB 保存的数据,AOF 保存的命令,RDB 文件比 AOF 小。恢复速度 RDB 小,更快。RDB 一次写入的数据较多,时间间隔会比 AOF 长,出现宕机丢失的数据会更多各有优劣,如果能综合就好了,所幸的是在 redis4.0 后,通过配置 aof-use-rdbpreamble 就可以开启两者混合
持久化,取长补短。

单机性能建议
因为 RDB 文件只用作后备用途,只要 15 分钟备份一次就够了,只保留 save 900 1 这条规则。
如果 Enable AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load 自己的 AOF 文件就可以了。 代价一是带来了持续的 IO,二是 AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF 重写的基础大小默认值 64M 太小了,可以设到 5G 以上。 默认超过原大小 100%大小时重写可以改到适当的数值。

你可能感兴趣的:(redis)