当前位置:首页 > 问答 > 正文

Redis查询慢到底是咋回事,背后那些不为人知的原因分析探讨

很多人觉得Redis就是个速度飞快的内存家伙,一旦它变慢了,第一反应往往是“是不是内存不够了?”或者“是不是服务器不行了?”,但其实,Redis变慢的原因远比想象中复杂,很多问题都藏在那些容易被忽略的角落里,今天我们就来挖一挖这些不为人知的原因。

Redis查询慢到底是咋回事,背后那些不为人知的原因分析探讨

最容易被忽视的“元凶”之一,其实是操作系统的一种机制,叫做“内存交换”(Swap),根据阿里云开发者社区的一篇文章分析,当Redis实例使用的物理内存不够时,操作系统为了保命,会把内存中一部分暂时不用的数据挪到硬盘上一个叫交换区的空间里,硬盘的速度跟内存比,那可是乌龟和火箭的差距,一旦发生这种情况,Redis要读取的数据如果恰好在硬盘上,那这次查询就会卡住,延迟瞬间飙升,你可能会说:“我明明看着服务器总内存还够啊!”但问题可能出在别处:比如同一个服务器上跑了其他也很吃内存的应用,和Redis抢资源;或者操作系统本身因为某些原因(如内核参数设置)提前开始了交换,监控Swap的使用情况,是诊断Redis莫名变慢的首要步骤。

Redis查询慢到底是咋回事,背后那些不为人知的原因分析探讨

一个听起来很技术但实际上很常见的坑,叫做“透明大页”(Transparent Huge Pages, THP),这本是Linux内核的一个优化功能,目的是减少内存管理的开销,但Redis的官方文档和多位性能优化专家的实践都明确指出,THP对于Redis这种内存分配模式来说,简直就是个“性能杀手”,因为它会导致Redis在操作内存时产生大量的延迟毛刺,简单理解就是,操作系统好心办坏事,把内存块合并来合并去,反而让Redis频繁等待,解决这个方法通常很简单,就是在操作系统层面关闭THP功能,往往能带来立竿见影的效果。

Redis查询慢到底是咋回事,背后那些不为人知的原因分析探讨

第三点,我们得看看Redis的内部机制,Redis是单线程工作的(指处理命令的核心模块),这意味着它一个时刻只能认真服务一个客人,这个设计避免了多线程的复杂问题,保证了简单高效,但也成了一个“阿喀琉斯之踵”,如果某个命令执行得特别慢,比如一次性用keys *模式匹配几百万个键,或者对一个超大的集合、列表进行操作,那么在这个命令执行期间,整个Redis服务器就会被它“卡住”,后面所有的命令都得排队等着,这种慢查询不是服务器资源不足,而是你让Redis干了件太重太耗时的活儿,严禁在生产环境使用keys命令,对于大数据量的操作,一定要用scan系列命令来分批进行。

第四,网络问题也常常被误判为Redis自身问题,Redis的高性能是建立在低网络延迟基础上的,如果客户端和Redis服务器之间的网络链路出现波动、丢包或者带宽打满,表现出来的现象就是客户端觉得Redis响应变慢了,这时候你需要用ping命令检查延迟,或者用traceroute等网络工具排查一下中间链路是否稳定,问题可能出在客户端本身,比如客户端所在的机器负载过高,没有足够的CPU资源来及时处理Redis返回的响应,也会造成“慢”的假象。

我们来谈谈持久化操作带来的影响,Redis为了数据安全,提供了两种持久化方式:RDB快照和AOF日志,根据腾讯云社区的技术文章分析,在执行bgsave生成RDB快照或者AOF重写时,Redis会fork出一个子进程来干活。fork操作本身,在Redis内存数据量非常大的时候,可能会因为复制父进程的内存页表而瞬间阻塞主线程一段时间,虽然子进程干活一般不影响主进程,但如果服务器是机械硬盘,或者CPU资源本来就紧张,那么子进程密集的磁盘IO操作也会和主进程抢资源,间接导致主进程处理命令的速度变慢,监控latest_fork_usec指标可以了解最后一次fork的耗时。

除了以上这些,键值对的大小(大Key问题)、不合理的数据结构选择、没有设置过期时间导致内存中堆积大量不再使用的冷数据等等,都是潜伏在暗处,拖慢Redis性能的常见原因,所以说,当Redis变慢时,别急着给服务器升级配置,不妨从这些“不为人知”的角落入手,一步步排查,很可能就能找到问题的关键。