Redis优化之持久化

1.Redis高可用

在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。

但是在Redis语境中,高可用的含义似乎要宽泛一些,除了保证提供正常服务(如主从分离、快速容灾技术),还需要考虑数据容量的扩展、数据安全不会丢失等。

在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和 Cluster集群,下面分别说明它们的作用,以及解决了什么样的问题。

  • 持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
  • 主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
  • 哨兵:在主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
  • Cluster集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

2.Redis 持久化

持久化的功能:Redis是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

Redis 提供两种方式进行持久化:

  • RDB 持久化:原理是将 Reids在内存中的数据库记录定时保存到磁盘上。
  • AOF 持久化(append only file):原理是将 Reids 的操作日志以追加的方式写入文件,类似于MySQL的binlog。

由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。

RDB 持久化定时的将redis在内存中的数据进行快照并压缩保存到硬盘里

  • 手动触发:bgsave命令
  • 自动触发:满足配置文件中 save n m 的规则(在n秒内发生了m次数据更新就会自动触发);主从复制在做全量复制时;执行shutdown命令关闭数据库时
  • 工作流程:redis父进程会fork子进程来进行RDB持久化快照保存内存数据到硬盘里,文件名:dump.rdb
  • 优缺点:RDB持久化保存的文件占用空间较小,网络传输快,恢复速度比AOF更快,性能影响比AOF更小; 实时性不如AOF,兼容性较差,持久化期间在fork子进程时会阻塞redis父进程

AOF持久化 实时的以追加的方式将redis写操作的命令记录到aof文件中

  • 工作流程:命令追加(将写操作命令追到aof_buf缓冲区)
  • 文件写入和同步(文件名:appendonly.aof,同步策略:appendfsync everysec|always|no)文件重写(减少aof文件占用空间的大小和加快恢复速度,定期执行bgrewriteaof命令触发)
  • 优缺点:实时性比RDB更好,支持秒级持久化,兼容性较好;持久化保存的文件占用空间更大,恢复速度更慢,性能影响更大,AOF文件重写期间在fork子进程时也会阻塞redis父进程,且IO压力更大

RDB和AOF的区别可根据 工作方式、实时性、占用空间、恢复速度、兼容性、IO性能影响 这几方面进行描述。

3.Redis性能管理

内存碎片:

通过 info memory 命令查看内存的使用情况。

复制代码
mem_fragmentation_ratio的值如果超过了1.5,建议可以考虑进行内存碎片的清理了。
mem_fragmentation_ratio的值如果小于1,说明物理内存不够真实数据的保存了,此时已经开始使用swap交换空间了,会导致redis性能的严重下降。应该考虑增加物理内存或减少redis内存占用。

config set activedefrag yes    #开启自动内存碎片清理
memory purge                   #手动内存碎片清理
注:由于内存碎片清理是redis主线程执行的,会发生阻塞。因此需要合理配置对应的参数和方式,保证redis的高性能。

4.Redis优化

1)开启AOF持久化,设置AOF刷盘策略为everysec(每隔1秒执行一次刷盘操作),只在业务低峰期执行AOF文件重写,减少磁盘的开销

2)缩短键值对存储长度,避免存储bigkey导致操作耗时

3)给key设置合理的过期时间,尽量避免大量key集中过期

4)设置内存上限(maxmemory),并设置内存数据淘汰策略(maxmemory-policy),一般最常使用的是volatile-lru(只删除最近最少访问并设置了过期时间的键)或 allkeys-lru

5)开启自动内存碎片清理(activedefrag yes)

6)开启lazy-free机制(lazyfree-lazy-eviction yes、lazyfree-lazy-expire yes、lazyfree-lazy-server-del yes),将删除过期key的操作放到后台线程执行,以减少删除对Redis主线程的阻塞

7)使用物理机而非虚拟机部署Redis服务,使用高速固态盘作为AOF日志的写入盘。

8)使用分布式架构(主从复制、哨兵模式、集群)增加读写速度,并实现高可用

9)禁用内存大页(echo never > /sys/kernel/mm/transparent_hugepage/enabled),因开启内存大页会导致fork的速度变慢,也会拖慢写操作的执行时间

5.Redis的三大缓存问题

  • 正常情况下,大部分的访问请求应该是先被redis响应的,在redis那里得不到响应的小部分访问请求才会去请求MySQL数据库获取数据,这样MySQL数据库的负载压力是非常小的,且可以正常工作。
  • 缓存雪崩/穿透/击穿问题的根本原因在于redis缓存命中率下降,大量请求会直接发给MySQL数据库,导致MySQL数据库压力过大而崩溃。

缓存雪崩

  • redis中大量不同的缓存key集体过期

解决方案:使用随机数设置key的过期时间,防止集群过期

设置二级缓存

数据库使用排他锁,实现加锁等待

缓存穿透

  • 大量请求访问redis和MySQL数据库都不存在的资源

解决方案:对空值也进行缓存

使用布隆过滤器进行判断拦截一定不存在的无效请求

使用脚本实时监控,进行黑名单限制

缓存击穿

  • redis中一个热点key过期,此时又有大量请求访问这个热点key

解决方案:设置永不过期

预先对热点数据进行缓存预热

数据库使用排他锁,实现加锁等待

6.如何保证MySQL和redis的数据一致性

复制代码
读取数据时,先从redis读取数据,如果redis没有,再从MySQL读取,并将读取到的数据同步到redis缓存中。
更新数据时,先更新MySQL数据,再更新redis缓存
删除数据时,先删除redis缓存,再删除MySQL数据
对于一些关键数据,可以使用定时任务,定时自动进行缓存预热,或使用MySQL触发器来实现同步redis缓存
相关推荐
爱怪笑的小杰杰29 分钟前
浏览器端缓存地图请求:使用 IndexedDB + ajax-hook 提升地图加载速度
ajax·okhttp·缓存
TDengine (老段)44 分钟前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349841 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE1 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102162 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎2 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP2 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t2 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb
睡前要喝豆奶粉2 小时前
在.NET Core Web Api中使用redis
redis·c#·.netcore
安当加密2 小时前
Nacos配置安全治理:把数据库密码从YAML里请出去
数据库·安全