再说完了Redis自身命令层面的波动问题排查和解决方案之后,我们说下还可能造成影响的命令操作层面的排查和解决问题的两种方案
分别是文件系统和操作系统
1.文件系统
因为Redis会持久化数据到磁盘,整个过程要依赖文件系统完成,所以文件系统将数据写回磁盘的机制,也会影响到Redis持久化的效率
在持久化的过程中,Redis还在接受其他的请求,持久化的效率高低会影响到Redis请求处理的性能
那么从文件持久化的角度来讲,Redis一般会采用AOF或者RDB快照来进行持久化,AOF日志提供了三种日志写回策略 no everysec always
而根据三种不同的写回策略,Redis调用文件系统提供的write和fsync也是不一致的
对于everysec,因为write和fysnc是不一致的,write是每次操作都会调用,而fsync则是每秒进行一次调用,所以everysec可以使用后台的子线程来异步的完成fsync的操作
而对于always策略来说,Redis需要确保每个操作记录都要落盘后才能给客户端返回信息,所以要求每次都write后同步的调用fsync
然后在使用AOF日志之后,为了避免日志文件不断的扩大,AOF重写机制就上线了,AOF重写也需要和文件系统进行交互,AOF重写会对磁盘进行大量的IO操作,故AOF重写也会调用fsync,而主线程在尝试出发子线程的fsync的时候,发现上一次的fsync还没有执行完成,那么就会阻塞
稍微总结一下持久化时候阻塞情况,就是AOF持久化调用的fsync和AOF重写子进程调用的fsync导致的阻塞
那么就是需要确定Redis实例使用哪些AOF日志写回策略
对于AOF写回策略,根据自己对数据可靠性的要求,明确是使用everysec还是always,毕竟always存在阻塞的安全隐患
其次是对AOF重写机制,则有着一些简单的优化,比如讲配置项 no-appendfsync-on-rewrite 设置为yes
配置项为yes的时候,表示在AOF重写的时候,不进行fsync操作,Redis实例在只是进行调用write,不会真正的调用后台线程进行fsync操作
最后对于AOF相关问题的解决,还可以从硬件层面进行解决,可以考虑使用固态硬盘作为写入设备
2.操作系统
操作系统存在着Swap机制,如果操作系统中的内存不足了,那么系统可能会将内存保存在磁盘中,故如果触发了Swap机制,无论换入还是换出操作,性能都会受到慢速磁盘的读写影响
Reids是内存数据库,如果操作系统开启了Swap,并且没有控制好内存的使用量,都可能会受到Swap的影响
而解决的方案都很简单,要么是加大机器的物理内存,要么是减少Redis实例的大小,以及关闭操作系统的swap
而除了Swap导致的问题,操作系统中,还存在内存大页机制,也会影响Redis性能,即将原本的4KB内存页扩展到2MB,虽然从表面上看,内存大页可以减少分配的次数,减少等待分配时间,,但是在AOF这样数据持久化的时候,是利用了写时复制机制,一旦有数据有修改的时候,就会将数据拷贝一份从而进行修改
而内存大页机制在这种时候,就会显示一些弊端,即常规的内存页,只需要拷贝4KB,而内存大页会导致至少拷贝2MB的内存,从而影响了Redis的正常访问操作,导致性能变慢
而对于此机制,只需要在Reids机制上配置关闭内存大页就行
只需要将 /sys/kernel/mm/transparent_hugepage/enabled 中写入never,来禁止内存大页机制
那么总结一下,本章,我们从文件系统和操作系统两个维度,来介绍了应对Redis变慢的方法
整体总结这两章,对于Redis存在的波动检查list总结为了下面的List,包含9个属性
1.获取Redis实例在当前环境下的基线性能
2.是否使用了慢查询命令
3.是否对Key设置了相同的过期时间
4.是否存在Bigkey,以及对bigKey进行删除操作
5.Redis 实例的内存使用是否过大,发生swap了吗,如果是的话,就增加内存假期
6.AOF的配置级别是否合适,业务层面是否需要这个级别吗
7.Redis实例运行环境中,是否启动了透明大页机制
8.主从集群,主库实例大小是否控制了吗,是否存在从库加载RDB文件阻塞的问题?
9.是否存在多核导致的内存切换问题?
那么总结完成之后,还有一个小问题,就是日常使用中,是否遇到过Redis变慢的情况吗
对于Swap机制,关闭应该是最方便的解决方案,包括在Kubernetes集群中,对于部署的节点也是要求关闭swap的,关闭方式如下swapoff -a