Redis高级应用--阻塞的原因
简介
Redis是单线程架构,如果该线程出现阻塞,将导致Redis不能提供服务。导致阻塞问题的场景大致分为两种原因:
- 内在原因:不合理使用API或数据库、CPU饱和、持久化阻塞
- 外在原因:CPU竞争、内存交换和网络问题等
内在原因
API或数据结构使用不合理
Redis可以使用慢查询功能获取慢查询命令,默认超过10毫秒的命令都记录到定长队列(默认128)中。如果命令执行时间是毫秒级,实际OPS只有1000多,因此需要找到慢的查询指令,并进行优化。Redis两个和慢查询日志相关的选项:发现慢查询后,可以对命令及时调整:1
2
3
4slowlog-log-slower-than 1 # 指定超过1毫秒的命令会被记录到日志上
slowlog-max-len 128 # 设置保存128条日志(先进先出,超过128条会丢掉前面的日志)
slowlog get {n} # 获取n条慢查询命令,不适用n则获取全部慢查询日志 - 修改为低时间复杂度的命令,禁用keys、sort等命令
- 调整大对象:将大对象拆分为多个小对象
CPU饱和
Redis使用单线程,CPU饱和是指Redis将CPU跑到接近100%,其他命令就无法执行,从而造成阻塞。使用top命令,可以看到Redis线程使用CPU达到92.3%。
1 | PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND |
持久化阻塞
持久化阻塞操作有:fork阻塞、AOF刷盘阻塞和HugePage写操作阻塞三种。
fork阻塞
Redis做RDB和AOF重写和持久化时,需要执行fork操作创建子进程(bgsave操作),子进程不拷贝父进程物理内存空间,但是会复制父进程的空间内存页表(10g的Redis进程,需要复制20MB的内存页表)。因此如果fork操作本身耗时过长,也会导致主线程的阻塞。
AOF刷盘阻塞
开启AOF持久化时,文件刷盘一般每秒一次,后台线程每秒对AOF文件做fsync操作。硬盘压力过大时,fsync操作需要等待,直到写入完成。如果主线程发现距离上次的fsync成功超过两秒,为了数据安全性会阻塞到后台线程fsync操作完成。
HugePage写操作阻塞
子进程在执行重写期间利用Linux写时复制降低内存开销,因此只有写操作是Redis才会复制要修改的内存页。如果开启Transparent HugePage,每次写入命令引起的复制内存页单位由4K变为2MB,放大512倍,拖慢写操作的执行时间。
外在原因
CPU竞争
- 进程竞争
如果其他进程过度消耗CPU,会严重影响Redis的吞吐量。 - 绑定CPU
部署Redis时,可以将Redis绑定在CPU上,但是一些情况下会出现问题。当Redis父进程创建子进程执行RDB/AOF持久化时,如果绑定了CPU,子进程和父进程有可能会共享一个CPU,影响Redis稳定性。内存交换
内存交换是指操作系统将Redis使用的部分内存换到硬盘上去,造成Redis性能急剧下降。因此需要保证机器有充足的内存,防止内存交换。1
2
3redis-cli info server | grep process_id #获取Redis进程号
cat /proc/4476/smaps | grep Swap 87 #根据进程号查询内存交换信息
网络问题
网络问题经常是引起Redis阻塞的问题。常见网络问题有:连接拒接、网络延迟、网卡软中断等