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
0: 检查有没有足够的内存,没有的话就申请内存失败
1:允许redis使用内存直到用完为止
2:内存地址空间不能超过swap + 50%
如果是0的话,可能会导致类型fork等操作执行失败,因为申请不到足够的内存空间
cat /proc/sys/vm/overcommit_memory
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1
swapiness
cat /proc/version 查看linux内核版本
如果linux内核版本<3.5,那么swapiness设置为0,这样系统宁愿swap也不会oom killer杀掉进程;
如果linux内核版本》=3.5,那么swapiness设置为1,这样系统宁愿swap也不会oom killer杀掉进程;
保证redis不会被杀掉
echo 0 > /proc/sys/vm/swapiness
echo vm.swapiness=0 >> /etc/sysctl.conf
ulimit -n
ulimit -n 10032 10032 # 最大打开文件句柄设置
tcp backlog
cat /proc/sys/net/core/somaxconn
echo 511 > /proc/sys/net/core/somaxconn