当前位置:数据分析 > 来说说Redis慢的原因以及排查方法

来说说Redis慢的原因以及排查方法

  • 发布:2023-10-05 14:58

数据库|Redis
redis
Database-Redis
网易云音乐网页源码,vm ubuntu16、tomcat日访问量、爬虫数据代码、php json面试题、seo厦门lzw
Redis视频教学
手游联运平台源码、vscode圆角代码、ubuntu关闭防火墙命令、war发布tomcat、sqlite.swift 、太原网页设计师、php支持的数据库、阿里云服务器带宽是、www.sychzs.cn上传插件、多端前端框架有哪些、快递爬虫、php网页源码、seo分类、springboot篇、移动手机标签设计、国外开源软件网站、易语言网页yy协议、游戏充值页面模板、网站后台管理系统开发、手机号码注册页面模板、家教网系统如何管理、asp程序实例lzw
原因一:实例内存已达到上限
图战源码、ubuntu安装mac模拟、爬虫gecko、php order()、本地社区seolzw
排查思路

如果您的 Redis 实例设置了 maxmemory 的内存限制,也可能会导致 Redis 变慢。

当我们使用Redis作为纯缓存时,通常会为本实例设置一个内存上限maxmemory,然后设置数据淘汰策略。当实例的内存达到maxmemory时,您可能会发现此后每次写入新数据时操作延迟都会增加。

减速原因

当Redis内存达到maxMemory时,每次写入新数据之前,Redis都要先从实例中踢出部分数据,使整个实例的内存保持在MaxMemory以下,然后才能写入新数据。

踢出旧数据的逻辑也需要时间,具体时间长短取决于你配置的淘汰策略:

allkeys-lru:无论key是否设置过期,最近最少访问的key都会被淘汰。 volatile-lru:只有设置了过期时间的最近最少访问的key才会被淘汰。 allkeys-random:无论key是否设置过期,keyvolatile-都会被随机淘汰。 random:只有设置了过期时间的key才会被随机淘汰。 allkeys-ttl:无论key是否设置过期,即将过期的keynoeviction都被淘汰:不淘汰任何key。实例内存达到maxmeory后,写入新数据,直接返回错误 allkeys-lfu:无论key是否设置过期,淘汰访问频率最低的key(4.0+版本支持) volatile-lfu:只剔除访问频率最低的key并设置过期时间(4.0+版本支持)

使用哪种策略取决于具体的业务场景。最常用的消除策略是 allkeys-lru / volatile-lru。他们的处理逻辑是每次从实例中随机取出一批key(这个数量是可配置的),然后淘汰一个访问最少的key,然后使用剩余的key。将密钥暂时存储在一个池中,继续随机选择一批密钥,与之前池中的密钥进行比较,然后淘汰访问次数最少的密钥。重复此操作,直到实例内存降至最大内存以下。

需要注意的是,Redis中删除数据的逻辑和删除过期key的逻辑是一样的。它也在命令实际执行之前执行。也就是说,也会增加我们操作Redis的延迟。而且写OPS越高,写OPS也越高。延迟也会更加明显。

另外,如果此时你的Redis实例中也存储了bigkey,那么同样需要很长时间才能消除并删除bigkey以释放内存。

你看到了吗? bigkey的危险无处不在,这也是我之前提醒大家尽量不要存储bigkey的原因。

解决方案

避免存储bigkey并减少释放内存的耗时过程。淘汰策略改为随机淘汰。随机淘汰比LRU快很多(根据业务情况调整)。拆分实例,将消除密钥的压力分散到多个实例。如果使用For Redis 4.0以上版本,开启layz-free机制,将消除key释放内存的操作放在后台线程(配置lazyfree-lazy-eviction = yes)原因2:启用大内存页

故障排除思路

我们都知道,应用程序向操作系统申请内存时,是按内存页来申请的,常规的内存页大小为4KB。从2.6.38开始,Linux内核支持内存大页机制,允许应用程序以2MB为单位向操作系统申请内存。应用程序每次向操作系统申请的内存单元变得更大,但这也意味着申请内存所花费的时间变得更长。

减速原因

Redis在执行后台RDB和AOF重写时,会使用fork子进程来处理。不过,主进程fork出子进程后,此时的主进程仍然可以接收写请求,传入的写请求会采用Copy On Write(写时复制)方式来操作内存数据。也就是说,一旦主进程有数据需要修改,Redis不会直接修改现有内存中的数据。相反,它会先复制内存数据,然后修改新内存中的数据。这就是所谓的“写时复制”。你也可以将copy-on-write理解为谁需要写就需要先复制,然后再修改。这样做的好处是,父进程的任何写操作都不会影响子进程的数据持久化(子进程只持久化fork时刻整个实例的所有数据,不关心新的数据变化) ,因为子进程只需要一个内存快照,然后将其持久化到磁盘)。但请注意,当主进程复制内存数据时,这个阶段涉及到新内存的申请。 如果此时操作系统开启了内存大页,那么在此期间,即使客户端只修改了10B的数据,Redis在申请内存时,也会以2MB为单位向操作系统申请。申请内存所花费的时间变长,进而导致每个写请求的延迟增加,影响Redis性能。 同样,如果这次写请求操作的是bigkey,那么主进程复制bigkey内存块时,一次请求的内存会更大,时间也会更长。可以看到bigkey这里又影响了性能。

解决方案

关闭内存大页机制。

首先需要检查Redis机器是否启用了大页:

$ cat /sys/kernel/mm/transparent_hugepage/enabled[always] madvise never

如果输出选项为always,则说明当前内存大页机制已启用,我们需要将其关闭:

$ echo never > /sys/kernel/mm/transparent_hugepage/enabled

其实操作系统提供的内存大页机制的好处就是可以减少某些程序申请内存的次数。

但是对于Redis这样对性能和延迟极其敏感的数据库,我们希望Redis每次申请内存的时间尽可能短,所以我不建议大家在Redis上启用这个机制机器。

原因 3:使用交换

故障排除思路

如果你发现Redis突然变得很慢,每次操作都要几百毫秒甚至几秒,那么你需要检查Redis是否使用了Swap。在这种情况下,Redis基本上已经不可能再提供高性能的服务了。

减速原因

什么是隔夜利息?为什么使用Swap会导致Redis性能下降?

如果对操作系统有所了解的话就会知道,为了缓解内存不足对应用程序的影响,操作系统允许将内存中的一部分数据交换到磁盘来缓冲内存由应用程序使用。数据被交换到磁盘上的区域,即Swap。

问题在于,当内存中的数据移至磁盘后,当Redis再次访问该数据时,需要从磁盘中读取。访问磁盘的速度比访问内存慢数百倍!尤其是对于Redis这种性能要求极高、对性能极其敏感的数据库来说,这种操作延迟是不可接受的。

此时需要检查Redis机器的内存使用情况,确认是否使用了Swap。您可以通过以下方式检查Redis进程是否使用了Swap:

# 首先找到Redis的进程ID$ ps -aux | grep redis-server # 查看Redis Swap的使用情况$ cat /proc/$pid/smaps | egrep '^(Swap|Size)'

输出结果如下

大小:1256 kBSwap:0 kBSize:4 kBSize:0 kBSize:132 kBSwap:0 kBSize:63488 kBSwap:0 kBSize:132 kBSwap:0 kBSize:65404 kBSwap:0 kBSize:1921024 kBSwap:0千伯...

该结果将列出Redis进程的内存使用情况。

Size的每一行代表Redis使用的一块内存的大小。 Size下面的Swap代表这个Size内存的大小以及已经交换到磁盘的数据量。如果这两个值相等,说明这块内存的数据已经完全交换到磁盘了。

如果只是少量数据交换到磁盘,比如每个Swap占用对应Size的一小部分,那么影响不是很大。如果数百兆甚至GB的内存被交换到磁盘,那么你需要保持警惕。在这种情况下,Redis的性能肯定会急剧下降。

解决方案

增加机器的内存,让Redis有足够的内存可以使用,整理内存空间,释放足够的内存供Redis使用,然后释放Redis的Swap,让Redis重新利用内存

Redis 释放 Swap 的过程通常需要重启实例。为了避免重启实例对业务的影响,通常会先进行一次主从切换,然后释放旧主节点的Swap,重启旧主节点实例,同步从库数据完全的。然后进行主从切换。

可以看到,当Redis使用Swap时,此时Redis的性能基本无法满足高性能要求(可以理解为武功废了),所以也需要提前预防这种情况。

预防的方法是需要监控Redis机器的内存和Swap使用情况,在内存不足或Swap使用时报警,并及时处理。

原因4:网络带宽过载

故障排除思路

如果你已经避免了上述导致性能问题的场景,并且Redis已经稳定运行了很长一段时间,但是在某个时间点之后,Redis的运行突然开始变慢,并且持续下去。造成这种情况的原因是什么?

这时需要检查Redis机器的网络带宽是否过载,是否有实例占满了整台机器的网络带宽。

减速原因

当网络带宽过载时,服务器会出现TCP层和网络层的报文发送延迟、丢包等情况。

Redis的高性能除了操作内存之外,还在于网络IO。如果网络IO出现瓶颈,也会严重影响Redis的性能。

解决方案

及时确认Redis实例的网络带宽已满。如果是正常业务访问,需要及时对实例进行扩容或迁移,避免因该实例流量过大而影响本机的其他实例。在运维层面,需要增加对Redis机器的各项指标的监控,包括网络流量。当网络流量达到一定阈值时,会提前向您发出提醒,并及时确认和扩大。 原因五:其他原因

1) 频繁短接

您的业务应用应该使用长连接来操作Redis,以避免频繁的短连接。

频繁的短连接会导致Redis花费大量的时间来建立和释放连接。 TCP的三路握手和四路挥手也会增加访问延迟。

2)运维监控

正如我之前提到的,为了提前预测Redis的减速,完整的监控是必不可少的。

监控其实就是Redis的各种运行时指标的集合。通常的做法是监控程序定期收集Redis的INFO信息,然后根据INFO信息中的状态数据进行数据显示和报警。

这里需要提醒大家的是,在编写一些监控脚本或者使用开源监控组件的时候不能掉以轻心。

在编写监控脚本访问Redis时,尽量使用长连接来收集状态信息,避免频繁的短连接。同时,还必须注意控制访问Redis的频率,避免影响业务请求。

在使用一些开源监控组件时,最好了解这些组件的实现原理,并正确配置这些组件,防止监控组件出现bug,导致短时间内大量的Redis操作,影响Redis的性能。

当时我们遇到这样的情况:DBA在使用一些开源组件时,由于配置和使用问题,导致监控程序与Redis频繁建立和断开,导致Redis响应缓慢。

3)其他程序争夺资源

我需要提醒您的最后一件事是,您的 Redis 机器最好是专用的,并且仅用于部署 Redis 实例。不要部署其他应用程序。尽量为Redis提供一个相对“安静”的环境,防止其他程序占用CPU。分配给Redis的资源不足会影响内存和磁盘资源。

Redis视频教程

相关文章

最新资讯

热门推荐