redis实践中的常见问题及解决
1.fork耗时导致高并发请求延时
RDB和AOF的时候,其实会有生成RDB快照,AOF rewrite,耗费磁盘IO的过程,主进程fork子进程,fork的时候,子进程是需要拷贝父进程的空间内存页表的,也会耗费时间,一般父进程内存有1个G的数据,那么fork可能会耗费20ms左右;如果是10G-30G,那么就会耗费几百毫秒。info stats中的latest_fork_usec可以看到,最近一次fork的时长,redis单机QPS一般在几万,fork可能一下子拖慢几万条操作的时长,从几毫秒变成1秒。优化思路:fork耗时跟redis主进程的内存有关系,一般限制redis的内存在10GB以内。
2.AOF阻塞问题
redis将数据写入AOF缓冲区,单独有个线程负责fsync,每秒一次,但是redis主线程会检查两次fsync时间,如果距离上次fsync时间超过了2秒,那么写请求就会阻塞,everysec,最对丢失两秒数据,一旦fsync超过2秒的延时,整个redis就会被拖慢。优化思路:优化硬盘写入速度,建议采用SSD,不要用普通的机械硬盘。
3.主从复制延迟问题
主从复制可能超时严重,这个时候需要良好的监控和报警机制。在info replication中,可以看到master和slave复制的offset,做差值可以看到对应的延迟量,如果延迟过多,那么进行报警。
4.主从复制风暴问题
多个slave从master去执行全量复制,一份大的rdb同时发送到多个slave,会导致网络带宽被严重占用,如果是多slave,建议配置成树状而不是星状。
5.vm.overcommit_memory
redis建议设置为1,是为了让fork能够在低内存下也执行成功。设置为1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。
6.最大打开文件句柄
ulimit -n 10032 10032
7.swapiness,内存不足时使用交换空间。
8.tcp backlog
syns queue用于保存半连接状态的请求,accept queue用于保存全连接状态的请求。syns queue大小通过/proc/sys/net/ipv4/tcp_max_syn_backlog
指定,一般默认512,设置有效的前提是syncookies功能被禁用。accept queue大小通过/proc/sys/net/core/somaxconn指定,在使用listen函数时,内核会根据传入的backlog参数与系统参数somaxconn,取二者最小值。如果accept queue队列满了,server将会发送一个ECONNEREFUSED错误信息Connection refused到client。netty实现中,也用到了backlog参数。