如何进行Redis性能优化?这一篇就够了( 四 )


8.开启AOF
前面我们分析了 RDB 和 AOF rewrite 对 Redis 性能的影响 , 主要关注点在 fork 上 。
其实,关于数据持久化方面 , 还有影响 Redis 性能的因素,这次我们重点来看 AOF 数据持久化 。
如果你的 AOF 配置不合理,还是有可能会导致性能问题 。
当 Redis 开启 AOF 后,其工作原理如下:
1)Redis 执行写命令后,把这个命令写入到 AOF 文件内存中(write 系统调用)
 
2)Redis 根据配置的 AOF 刷盘策略,把 AOF 内存数据刷到磁盘上(fsync 系统调用)
为了保证 AOF 文件数据的安全性,Redis 提供了 3 种刷盘机制:
1)Appendfsync always:主线程每次执行写操作后立即刷盘,此方案会占用比较大的磁盘 IO 资源 , 但数据安全性最高 。
2)appendfsync no:主线程每次写操作只写内存就返回,内存数据什么时候刷到磁盘,交由操作系统决定,此方案对性能影响最?。???莅踩?砸沧畹停?Redis 宕机时丢失的数据取决于操作系统刷盘时机 。
3)appendfsync everysec:主线程每次写操作只写内存就返回,然后由后台线程每隔 1 秒执行一次刷盘操作(触发fsync系统调用) , 此方案对性能影响相对较小 , 但当 Redis 宕机时会丢失 1 秒的数据 。
看到这里,我猜你肯定和大多数人的想法一样 , 选比较折中的方案 appendfsync everysec 就没问题了吧?
 
这个方案优势在于,Redis 主线程写完内存后就返回 , 具体的刷盘操作是放到后台线程中执行的,后台线程每隔 1 秒把内存中的数据刷到磁盘中 。
这种方案既兼顾了性能,又尽可能地保证了数据安全 , 是不是觉得很完美?
但是 , 这里我要给你泼一盆冷水了,采用这种方案你也要警惕一下,因为这种方案还是存在导致 Redis 延迟变大的情况发生,甚至会阻塞整个 Redis 。
你试想这样一种情况:当 Redis 后台线程在执行 AOF 文件刷盘时,如果此时磁盘的 IO 负载很高,那这个后台线程在执行刷盘操作(fsync系统调用)时就会被阻塞住 。
 
此时的主线程依旧会接收写请求,紧接着,主线程又需要把数据写到文件内存中(write 系统调用),当主线程使用后台子线程执行了一次 fsync,需要再次把新接收的操作记录写回磁盘时,如果主线程发现上一次的 fsync 还没有执行完,那么它就会阻塞 。
 
所以,如果后台子线程执行的 fsync 频繁阻塞的话(比如 AOF 重写占用了大量的磁盘 IO 带宽),主线程也会阻塞,导致 Redis 性能变慢 。

如何进行Redis性能优化?这一篇就够了

文章插图
 
看到了么?在这个过程中,主线程依旧有阻塞的风险 。
所以 , 尽管你的 AOF 配置为 appendfsync everysec,也不能掉以轻心,要警惕磁盘压力过大导致的 Redis 有性能问题 。
【如何进行Redis性能优化?这一篇就够了】那什么情况下会导致磁盘 IO 负载过大?以及如何解决这个问题呢?
我总结了以下几种情况,你可以参考进行问题排查:
1)进程正在执行 AOF rewrite,这个过程会占用大量的磁盘 IO 资源
2)有其他应用程序在执行大量的写文件操作,也会占用磁盘 IO 资源
 
对于情况1,说白了就是 , Redis 的 AOF 后台子线程刷盘操作 , 撞上了子进程 AOF rewrite!
9.绑定CPU
很多时候,我们在部署服务时 , 为了提高服务性能,降低应用程序在多个 CPU 核心之间的上下文切换带来的性能损耗,通常采用的方案是进程绑定 CPU 的方式提高性能 。
我们都知道,一般现代的服务器会有多个 CPU,而每个 CPU 又包含多个物理核心,每个物理核心又分为多个逻辑核心 , 每个物理核下的逻辑核共用 L1/L2 Cache 。
而 Redis Server 除了主线程服务客户端请求之外,还会创建子进程、子线程 。
其中子进程用于数据持久化,而子线程用于执行一些比较耗时操作,例如异步释放 fd、异步 AOF 刷盘、异步 lazy-free 等等 。
如果你把 Redis 进程只绑定了一个 CPU 逻辑核心上,那么当 Redis 在进行数据持久化时,fork 出的子进程会继承父进程的 CPU 使用偏好 。
而此时的子进程会消耗大量的 CPU 资源进行数据持久化(把实例数据全部扫描出来需要耗费CPU),这就会导致子进程会与主进程发生 CPU 争抢 , 进而影响到主进程服务客户端请求,访问延迟变大 。


推荐阅读