一、慢操作排查处理步骤
- 判断当前情况是否属于慢操作(基线性能);
- 系统性排查慢操作的原因(Redis本身、AOF文件操作磁盘IO、操作系统内存swap磁盘IO);
- 从应对方案中选择合适的方法加快Redis响应速度。
二、 如何判断是否是慢操作:
用指令查询当前环境下Redis的基线性能,再查询当前应用Redis的延迟,如果达到两倍以上基线性能说明当前是慢操作。
三、 排查慢操作
3.1 针对Redis本身 |
A) sql语句慢造成延迟:
可以用 Redis日志查看sql语句的执行情况,判断是否变慢了(类似于Mysql的explain);
解决方法:
- 查询Set集合中所有元素时用 SSCAN分批次返回数据给客户端;
- 在客户端进行集合的聚合操作,避免使用SORT,SUNION,SINTER等命令;
- 不建议使用KEYS命令来遍历查询所有满足要求的key(可以用SCAN命令代替);
B) 过期key自动删除阻塞Redis:
Redis默认每隔100ms删除指定个数过期key,重复删除直到过期key占所有key的比例低于25%(大量key过期Redis就会一直在这执行删除操作,影响主线程),原因是程序一次性给大量key设置了同样的过期时间,同一刻大量key过期(会造成雪崩)。
解决方法:
- 尽量 给key设置不同的过期时间,可以在过期时间上加一个随机数。
3.2 针对文件系统(AOF写入磁盘,产生磁盘IO,RDB读写复制时fork拷贝内存页过大) |
A) AOF日志:
主线程调用子线程按照三种策略进行AOF写操作,会产生磁盘IO(每执行一个操作就记录到AOF中,每秒记录一次AOF,间隔一定时间记录一次AOF);
在子进程中AOF会进行重写,会产生磁盘IO,会和子线程中的AOF写入操作竞争磁盘资源;
主线程阻塞过程:如果AOF重写操作占据了磁盘IO,导致主线程上一次执行的AOF写操作阻塞,那么当主线程再次执行AOF写入操作时,会阻塞等待子线程执行完成上一次AOF写入才能将其交由子线程执行(fsnyc操作: 主线程在此处等待将第二次AOF交由子线程执行)本次AOF写入。
解决方法:
- 根据业务需求选择主线程 多久进行一次AOF文件写入;
- 考虑主线程不使用fsync操作,每次都直接将AOF写入请求交给子线程,这样主线程不会阻塞,但是AOF文件中可能有数据丢失;
- 采用高速固态硬盘存储AOF日志文件。
B) RDB快照:
如果操作系统采用的是 大内存页机制(内存被分配成2MB每份,常规是4kB),当RDB持久化时,主线程会fork子线程,此时子线程要拷贝一份和主线程一样的内存,那么必须以2MB为单位拷贝内存页,当主线程中内存一页中只占用了几kB,却要 花更多的时间浪费在拷贝空数据页上,导致fork过程影响主线程执行。
解决方法:
- 关闭大内存页机制。
3.3 操作系统Swap操作(数据在内存和磁盘之间来回传输) |
当Redis所需的内存空间不够时, 数据会在内存页和磁盘中来回移动,极大提高磁盘IO,影响Redis主线程。
产生原因:
- Redis实例存储占用过多内存;
- 其他应用程序进行大量文件读写占用内存,导致Redis可用内存变少。
解决方法:
- 增加机器内存;
- 采用Redis集群减少redis所需的内存空间。