Redis 子进程开销监控和优化方式
Redis子进程负责AOF或者RDB文件的重写,它的运行过程主要涉及CPU、内存、硬盘三部分的消耗
CPU
CPU开销分析。子进程负责把进程内的数据分批写入文件,这个过程 属于CPU密集操作,通常子进程对单核CPU利用率接近90%
CPU消耗优化。Redis是CPU密集型服务,不要做绑定单核CPU操作。由于子进程非常消耗CPU,会和父进程产生单核资源竞争
不要和其他CPU密集型服务部署在一起,造成CPU过度竞争
如果部署多个Redis实例,尽量保证同一时刻只有一个子进程执行重写 工作,具体见下一篇文章的“多实例部署”
内存
内存消耗分析
子进程通过 fork 操作产生, 占用内存大小等同于父进程, 理论上需要两倍的内存来完成持久化操作, 但 Linux 有写时复制机制 (copy-on-write)。父子进程会共享相同的物理内存页, 当父进程处理写请求时会把要修改的页创建副本, 而子进程在 fork 操作过程中共享整个父进程内存快照。
内存消耗监控
RDB 重写: 被修改的内存页可以等价认为 RDB 重写的消耗
AOF 重写: 被修改的内存页 + AOF 重写缓冲区
内存消耗优化
如果部署多个 Redis 实例, 尽量保证同一时刻只有一个子进程在工作
避免在大量写入时做子进程重写操作, 这样将导致父进程维护大量页副本, 造成内存消耗
Transparent Huge Pages(THP) 是 Linux kernel 在2.6.38增加的功能, 支持 huge page (2MB) 页分配, 会降低 fork 速度, 默认开启. 当开启时, 在 fork 后会大幅增加重写期间父进程的内存消耗, 建议关闭:
磁盘
硬盘开销分析
子进程主要职责是把 AOF 或者 RDB 文件写入硬盘持久化。势必造成硬盘写入压力。根据 Redis 重写 AOF/RDB 的数据量, 结合系统工具如 sar、iostat、iotop 等, 可分析出重写期间硬盘负载情况
硬盘开销优化
不要和其他高硬盘负载的服务部署在一起。如: 存储服务、消息队列服务等
AOF 重写时会消耗大量硬盘 IO, 可以开启配置 no-appendfsync-on-rewrite, 默认关闭。表示在 AOF 重写期间不做 fsync 操作
当开启 AOF 功能的 Redis 用于高流量写入场景时, 如果使用普通机械磁盘, 写入吞吐一般在 100MB/s 左右, 这时 Redis 实例的瓶颈主要在 AOF 同步硬盘上
对于单机配置多个 Redis 实例的情况, 可以配置不同实例分盘存储 AOF 文件, 分摊硬盘写入压力
配置 no-appendfsync-on-rewrite=yes 时, 在极端情况下可能丢失整个 AOF 重写期间的数据,需要根据数据安全性决定是否配置
总结
配Redis持久化前后前后整理了三篇文章,归纳起来大致可分为下面几点
Redis 提供了两种持久化方式: RDB 和 AOF
RDB 使用一次性生成内存快照的方式, 产生的文件紧凑压缩比更高, 因此读取 RDB 恢复速度更快。由于每次生成 RDB 开销较大, 无法做到实时持久化, 一般用于数据冷备和复制传输
save 命令会阻塞主线程不建议使用, bgsave 命令通过 fork 操作创建子进程生成 RDB 避免阻塞
AOF 通过追加写命令到文件实现持久化, 通过 appendfsync 参数可以控制实时/秒级持久化。因为需要不断追加写命令, 所以 AOF 文件体积逐渐变大, 需要定期执行重写操作来降低文件体积
AOF 重写可以通过 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数控制自动触发, 也可以使用 bgrewriteaof 命令手动触发
子进程执行期间使用 copy-on-write 机制与父进程共享内存, 避免内存消耗翻倍。AOF 重写期间还需要维护重写缓冲区, 保存新的写入命令避免数据丢失
持久化阻塞主线程场景有: fork 阻塞和 AOF追加阻塞。fork 阻塞时间跟内存量和系统有关, AOF 追加阻塞说明硬盘资源紧张
单机下部署多个实例时, 为了防止出现多个子进程执行重写操作, 建议做隔离控制, 避免 CPU 和 IO 资源竞争
Redis持久化推荐
版权声明: 本文为 InfoQ 作者【码农架构】的原创文章。
原文链接:【http://xie.infoq.cn/article/c44e76b6f600b4e836730f976】。文章转载请联系作者。
评论