fork耗时过长导致高并发请求延迟

问题描述
RDB和AOF做持久化的时候,会生成对应的RDB快照文件,或者AOF rewrite重写,这一个过程是耗费磁盘IO的过程,主进程会fork一个子进程,专门负责拷贝父进程的空间内存页表,这个过程会耗费一定的时间。
如果父进程的内存存在太多的数据,那对应的fork处理耗时也会相应变多,fork的处理过程会拖慢数据操作的请求时长。
可以通过info stats命令的latest_fork_usec来查看最近一次fork的时长。
优化思路
fork的耗时与redis主内存的容量有关系,一般控制redis的内存在10G以内,保证全量复制下,fork子进程做数据复制操作的耗时不会太大。

AOF阻塞问题

问题描述
redis会将数据写入AOF缓冲区,然后单独开一个线程做fsync操作,每秒一次将数据从AOF缓冲区异步写入到磁盘文件中。
redis的主线程会检查两次fsync操作的时间,如果距离上次fsync时间超过2秒,那么写请求就会被阻塞,保证最多只会丢失2秒的数据。
所以一旦fsync超过2秒的延迟,整个redis的操作就会受到影响。
优化思路
使用SSD固态硬盘,提升磁盘的读写速度。

主从复制延迟问题

问题描述
主从复制可能会超时严重,需要一个良好的监控和报警平台
info replication中,可以看到master和slave复制的offset,两个offset的差值就是对应的延迟量。
如果延迟过多,就进行报警。

主从复制风暴问题

问题描述
一个master节点下有多个slave节点,如果因为一些原因(比如master的run id变更)导致需要让所有的slave从master去执行全量复制。一份大的rdb快照文件就需要同时发送给所有的slave节点,导致网络带宽被严重占用。
优化思路
使用树状结构挂载slave节点。

Linux内核参数

vm.overcommit_memory

  1. 0: 检查有没有足够的内存,没有的话就申请内存失败
  2. 1:允许redis使用内存直到用完为止
  3. 2:内存地址空间不能超过swap + 50%
  4. 如果是0的话,可能会导致类型fork等操作执行失败,因为申请不到足够的内存空间
  1. cat /proc/sys/vm/overcommit_memory
  2. echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
  3. sysctl vm.overcommit_memory=1

swapiness

  1. cat /proc/version 查看linux内核版本
  2. 如果linux内核版本<3.5,那么swapiness设置为0,这样系统宁愿swap也不会oom killer杀掉进程;
  3. 如果linux内核版本》=3.5,那么swapiness设置为1,这样系统宁愿swap也不会oom killer杀掉进程;
  4. 保证redis不会被杀掉
  5. echo 0 > /proc/sys/vm/swapiness
  6. echo vm.swapiness=0 >> /etc/sysctl.conf

ulimit -n

  1. ulimit -n 10032 10032 # 最大打开文件句柄设置

tcp backlog

  1. cat /proc/sys/net/core/somaxconn
  2. echo 511 > /proc/sys/net/core/somaxconn