Redis 忽然变慢了怎样排查并办理?

开发者 2024-9-15 18:28:20 28 0 来自 中国
Redis 通常是我们业务体系中一个告急的组件,好比:缓存、账号登录信息、排行榜等。
一旦 Redis 哀求耽误增长,大概就会导致业务体系“雪崩”。
我在只身红娘婚恋范例互联网公司工作,在双十一推出下单就送女朋侪的活动。
谁曾想,破晓 12 点之后,用户量暴增,出现了一个技能故障,用户无法下单,其时老大火冒三丈!
颠末查找发现Redis。
获取不到毗连资源,而且集群中的单台 Redis 毗连量很高。
大量的流量没了 Redis 的缓存相应,直接打到了 MySQL,末了数据库也宕机了……
于是各种更改最大毗连数、毗连等待数,固然报错信息频率有所缓解,但还是连续报错
后来颠末线下测试,发现存放Redis字符数据很大,匀称 1s 返回数据
可以发现,一旦 Redis 耽误过高,会引发各种题目。
Redis 性能出题目了么?

最大耽误是客户端发出下令到客户端收到下令的相应的时间,正常情况下 Redis 处理处罚的时间极短,在微秒级别。
当 Redis 出现性能颠簸的时间,好比到达几秒到十几秒,这个很显着我们可以认定 Redis 性能变慢了。
有的硬件设置比力高,当耽误 0.6ms,我们大概就认定变慢了。硬件比力差的大概 3 ms 我们才以为出现题目。
那我们该怎样界说 Redis 真的变慢了呢?
以是,我们必要对当前情况的 Redis 基线性能做丈量,也就是在一个体系在低压力、无干扰情况下的基天性能。
当你发现 Redis 运行时时的耽误是基线性能的 2 倍以上,就可以判断 Redis 性能变慢了。
耽误基线丈量

redis-cli 下令提供了–intrinsic-latency 选项,用来监测和统计测试期间内的最大耽误(以毫秒为单元),这个耽误可以作为 Redis 的基线性能。
redis-cli --latency -h `host` -p `port`好比实行如下指令:
redis-cli --intrinsic-latency 100Max latency so far: 4 microseconds.Max latency so far: 18 microseconds.Max latency so far: 41 microseconds.Max latency so far: 57 microseconds.Max latency so far: 78 microseconds.Max latency so far: 170 microseconds.Max latency so far: 342 microseconds.Max latency so far: 3079 microseconds.45026981 total runs (avg latency: 2.2209 microseconds / 2220.89 nanoseconds per run).Worst run took 1386x longer than the average latency.
注意:参数100是测试将实行的秒数。我们运行测试的时间越长,我们就越有大概发现耽误峰值。
通常运行 100 秒通常是符合的,足以发现耽误题目了,固然我们可以选择差别时间运行反复,制止弊端。
运行的最大耽误是 3079 微秒,以是基线性能是 3079 (3 毫秒)微秒。
必要注意的是,我们要在 Redis 的服务端运行,而不是客户端。如许,可以制止网络对基线性能的影响
可以通过 -h host -p port 来毗连服务端,如果想监测网络对 Redis 的性能影响,可以使用 Iperf 丈量客户端到服务端的网络耽误。
如果网络耽误几百毫秒,分析网络大概有其他大流量的步伐在运行导致网络拥塞,必要找运维和谐网络的流量分配。
慢指令监控

怎样判断是否是慢指令呢?
看操纵复杂度是否是O(N)。官方文档对每个下令的复杂度都有先容,尽大概使用O(1) 和 O(log N)下令。
涉及到聚集操纵的复杂度一样平常为O(N),好比聚集全量查询HGETALL、SMEMBERS,以及聚集的聚合操纵:SORT、LREM、 SUNION等。
有监控数据可以观测呢?代码不是我写的,不知道有没有人用了慢指令。
有两种方式可以排查到:

  • 使用 Redis 慢日记功能查出慢下令;
  • latency-monitor(耽误监控)工具。
别的,可以使用本身(top、htop、prstat 等)快速查抄 Redis 主进程的 CPU 消耗。如果 CPU 使用率很高而流量不高,通常表明使用了慢速下令。
慢日记功能

Redis 中的 slowlog 下令可以让我们快速定位到那些超出指定实行时间的慢下令,默认情况下下令如果实行时间凌驾 10ms 就会被纪录到日记。
slowlog 只会纪录其下令实行的时间,不包罗 io 来回操纵,也不纪录单由网络耽误引起的相应慢。
我们可以根据基线性能来自界说慢下令的尺度(设置成基线性能最大耽误的 2 倍),调解触发纪录慢下令的阈值。
可以在 redis-cli 中输入以下下令设置纪录 6 毫秒以上的指令:
redis-cli CONFIG SET slowlog-log-slower-than 6000也可以在 Redis.config 设置文件中设置,以微秒为单元。
想要检察全部实行时间比力慢的下令,可以通过使用 Redis-cli 工具,输入 slowlog get 下令检察,返回结果的第三个字段以微秒位单元表现下令的实行时间。
如果只必要检察末了 2 个慢下令,输入 slowlog get 2 即可。
示例:获取最近2个慢查询下令127.0.0.1:6381> SLOWLOG get 21) 1) (integer) 6   2) (integer) 1458734263   3) (integer) 74372   4) 1) "hgetall"      2) "max.dsp.blacklist"2) 1) (integer) 5   2) (integer) 1458734258   3) (integer) 5411075   4) 1) "keys"      2) "max.dsp.blacklist"以第一个 HGET 下令为例分析,每个 slowlog 实体共 4 个字段:

  • 字段 1:1 个整数,表现这个 slowlog 出现的序号,server 启动后递增,当前为 6。
  • 字段 2:表现查询实行时的 Unix 时间戳。
  • 字段 3:表现查询实行微秒数,当前是 74372 微秒,约 74ms。
  • 字段 4: 表现查询的下令和参数,如果参数许多或很大,只会表现部分参数个数。当前下令是hgetall max.dsp.blacklist。
Latency Monitoring

Redis 在 2.8.13 版本引入了 Latency Monitoring 功能,用于以秒为粒度监控各种变乱的发生频率。
启用耽误监督器的第一步是设置耽误阈值(单元毫秒)。只有凌驾该阈值的时间才会被纪录,好比我们根据基线性能(3ms)的 3 倍设置阈值为 9 ms。
可以用 redis-cli 设置也可以在 Redis.config 中设置;
CONFIG SET latency-monitor-threshold 9工具纪录的干系变乱的详情可检察官方文档:https://redis.io/topics/latency-monitor
如获取最近的 latency
127.0.0.1:6379> debug sleep 2OK(2.00s)127.0.0.1:6379> latency latest1) 1) "command"   2) (integer) 1645330616   3) (integer) 2003   4) (integer) 2003

  • 变乱的名称;
  • 变乱发生的最新耽误的 Unix 时间戳;
  • 毫秒为单元的时间耽误;
  • 该变乱的最大耽误。
怎样办理 Redis 变慢?

Redis 的数据读写由单线程实行,如果主线程实行的操纵时间太长,就会导致主线程壅闭。
一起分析下都有哪些操纵会壅闭主线程,我们又该怎样办理?
网络通讯导致的耽误

客户端使用 TCP/IP 毗连或 Unix 域毗连毗连到 Redis。1 Gbit/s 网络的典范耽误约为 200 us。
redis 客户端实行一条下令分 4 个过程:
发送下令-〉 下令列队 -〉 下令实行-〉 返回结果
这个过程称为 Round trip time(简称 RTT, 来回时间),mget mset 有效节省了 RTT,但大部分下令(如 hgetall,并没有 mhgetall)不支持批量操纵,必要消耗 N 次 RTT ,这个时间必要 pipeline 来办理这个题目。
Redis pipeline 将多个下令毗连在一起来淘汰网络相应来回次数。
慢指令导致的耽误

根据上文的慢指令监控查询文档,查询到慢查询指令。可以通过以下两种方式办理:

  • 好比在 Cluster 集群中,将聚合运算等 O(N) 操纵运行在 slave 上,大概在客户端完成。
  • 使用高效的下令取代。使用增量迭代的方式,制止一次查询大量数据,详细请检察SCAN、SSCAN、HSCAN和ZSCAN下令。
除此之外,生产中禁用KEYS 下令,它只适用于调试。由于它会遍历全部的键值对,以是操纵延时高。
Fork 天生 RDB 导致的耽误

天生 RDB 快照,Redis 必须 fork 配景进程。fork 操纵(在主线程中运行)本身会导致耽误。
Redis 使用操纵体系的多进程写时复制技能 COW(Copy On Write) 来实现快照长期化,淘汰内存占用。
2.png 但 fork 会涉及到复制大量链接对象,一个 24 GB 的大型 Redis 实例必要 24 GB / 4 kB * 8 = 48 MB 的页表。
实行 bgsave 时,这将涉及分配和复制 48 MB 内存。
别的,从库加载 RDB 期间无法提供读写服务,以是主库的数据量大小控制在 2~4G 左右,让从库快速的加载完成
内存大页(transparent huge pages)

通例的内存页是按照 4 KB 来分配,Linux 内核从 2.6.38 开始支持内存大页机制,该机制支持 2MB 大小的内存页分配。
Redis 使用了 fork 天生RDB 做长期化提供了数据可靠性包管。
当天生 RDB 快照的过程中,Redis 采取写时复制技能使得主线程依然可以接收客户端的写哀求。
也就是当数据被修改的时间,Redis 会复制一份这个数据,再举行修改。
采取了内存大页,天生 RDB 期间,纵然客户端修改的数据只有 50B 的数据,Redis 必要复制 2MB 的大页。当写的指令比力多的时间就会导致大量的拷贝,导致性能变慢。
使用以下指令禁用 Linux 内存大页即可:
echo never > /sys/kernel/mm/transparent_hugepage/enabledswap:操纵体系分页

当物理内存(内存条)不敷用的时间,将部分内存上的数据交换到 swap 空间上,以便让体系不会因内存不敷用而导致 oom 大概更致命的情况出现。
当某进程向 OS 哀求内存发现不敷时,OS 会把内存中暂时不消的数据交换出去,放在 SWAP 分区中,这个过程称为 SWAP OUT。
当某进程又必要这些数据且 OS 发现尚有空闲物理内存时,又会把 SWAP 分区中的数据交换回物理内存中,这个过程称为 SWAP IN。
内存 swap 是操纵体系里将内存数据在内存和磁盘间来回换入和换出的机制,涉及到磁盘的读写。
触发 swap 的情况有哪些呢?
对于 Redis 而言,有两种常见的情况:

  • Redis 使用了比可用内存更多的内存;
  • 与 Redis 在同一呆板运行的其他进程在实行大量的文件读写 I/O 操纵(包括天生大文件的 RDB 文件和 AOF 配景线程),文件读写占用内存,导致 Redis 得到的内存淘汰,触发了 swap。
我要怎样排查是否由于 swap 导致的性能变慢呢?
Linux 提供了很好的工具来排查这个题目,以是当猜疑由于交换导致的耽误时,只需按照以下步调排查。
获取 Redis 实例 pid

$ redis-cli info | grep process_idprocess_id:13160进入此进程的 /proc 文件体系目次:
cd /proc/13160在这里有一个 smaps 的文件,该文件形貌了 Redis 进程的内存布局,运行以下指令,用 grep 查找全部文件中的 Swap 字段。
$ cat smaps | egrep '^(Swap|Size)'Size:                316 kBSwap:                  0 kBSize:                  4 kBSwap:                  0 kBSize:                  8 kBSwap:                  0 kBSize:                 40 kBSwap:                  0 kBSize:                132 kBSwap:                  0 kBSize:             720896 kBSwap:                 12 kB每行 Size 表现 Redis 实例所用的一块内存大小,和 Size 下方的 Swap 对应这块 Size 大小的内存地区有多少数据已经被换出到磁盘上了。
如果 Size == Swap 则分析数据被完全换出了。
可以看到有一个 720896 kB 的内存大小有 12 kb 被换出到了磁盘上(仅交换了 12 kB),这就没什么题目。
Redis 本身会使用许多大小不一的内存块,以是,你可以看到有许多 Size 行,有的很小,就是 4KB,而有的很大,比方 720896KB。差别内存块被换出到磁盘上的大小也不一样。
敲重点了
如果 Swap 齐备都是 0 kb,大概零星的 4k ,那么齐备正常。
当出现百 MB,乃至 GB 级别的 swap 大小时,就表明,此时,Redis 实例的内存压力很大,很有大概会变慢。
办理方案


  • 增长呆板内存;
  • 将 Redis 放在单独的呆板上运行,制止在同一呆板上运行必要大量内存的进程,从而满意 Redis 的内存需求;
  • 增长 Cluster 集群的数目分担数据量,淘汰每个实例所需的内存。
AOF 和磁盘 I/O 导致的耽误

为了包管数据可靠性,Redis 使用 AOF 和 RDB 快照实现快速规复和长期化。
可以使用 appendfsync 设置将 AOF 设置为以三种差别的方式在磁盘上实行 write 大概 fsync (可以在运行时使用 CONFIG SET下令修改此设置,好比:redis-cli CONFIG SET appendfsync no)。

  • no:Redis 不实行 fsync,唯一的耽误来自于 write 调用,write 只必要把日记纪录写到内核缓冲区就可以返回。
  • everysec:Redis 每秒实行一次 fsync。使用配景子线程异步完成 fsync 操纵。最多丢失 1s 的数据。
  • always:每次写入操纵都会实行 fsync,然后用 OK 代码回复客户端(现实上 Redis 会实行将同时实行的许多下令聚集到单个 fsync 中),没有数据丢失。在这种模式下,性能通常非常低,剧烈发起使用快速磁盘和可以在短时间内实行 fsync 的文件体系实现。
我们通常将 Redis 用于缓存,数据丢失完全恶意从数据获取,并不必要很高的数据可靠性,发起设置成 no 大概 everysec。
除此之外,制止 AOF 文件过大, Redis 会举行 AOF 重写,天生缩小的 AOF 文件。
可以把设置项 no-appendfsync-on-rewrite设置为 yes,表现在 AOF 重写时,不举行 fsync 操纵。
也就是说,Redis 实例把写下令写到内存后,不调用配景线程举行 fsync 操纵,就直接返回了。
expires 镌汰逾期数据

Redis 有两种方式镌汰逾期数据:

  • 惰性删除:当接收哀求的时间发现 key 已经逾期,才实行删除;
  • 定时删除:每 100 毫秒删除一些逾期的 key。
定时删除的算法如下:

  • 随机采样 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP个数的 key,删除全部逾期的 key;
  • 如果发现尚有凌驾 25% 的 key 已逾期,则实行步调一。
ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP默认设置为 20,每秒实行 10 次,删除 200 个 key 题目不大。
如果触发了第二条,就会导致 Redis 划一在删除逾期数据去开释内存。而删除是壅闭的。
触发条件是什么呀?
也就是大量的 key 设置了雷同的时间参数。同一秒内,大量 key 逾期,必要重复删除多次才华低沉到 25% 以下。
简而言之:大量同时到期的 key 大概会导致性能颠簸。
办理方案

如果一批 key 简直是同时逾期,可以在 EXPIREAT 和 EXPIRE 的逾期时间参数上,加上一个肯定大小范围内的随机数,如许,既包管了 key 在一个相近时间范围内被删除,又制止了同时逾期造成的压力。
bigkey

通常我们会将含有较大数据或含有大量成员、列表数的 Key 称之为大 Key,下面我们将用几个现实的例子对大 Key 的特性举行形貌:

  • 一个 STRING 范例的 Key,它的值为 5MB(数据过大)
  • 一个 LIST 范例的 Key,它的列表数目为 10000 个(列表数目过多)
  • 一个 ZSET 范例的 Key,它的成员数目为 10000 个(成员数目过多)
  • 一个 HASH 格式的 Key,它的成员数目固然只有 1000 个但这些成员的 value 总大小为 10MB(成员体积过大)
bigkey 带来题目如下:

  • Redis 内存不绝变大引发 OOM,大概到达 maxmemory 设 置值引发写壅闭或告急 Key 被逐出;
  • Redis Cluster 中的某个 node 内存远超别的 node,但因 Redis Cluster 的数据迁移最小粒度为 Key 而无法将 node 上的内存均衡化;
  • bigkey 的读哀求占用过大带宽,自身变慢的同时影响到该服务器上的别的服务;
  • 删除一个 bigkey 造成主库较长时间的壅闭并引发同步停止或主从切换;
查找 bigkey

使用 redis-rdb-tools 工具以定制化方式找出大 Key。
办理方案

对大 key 拆分

如将一个含有数万成员的 HASH Key 拆分为多个 HASH Key,并确保每个 Key 的成员数目在公道范围,在 Redis Cluster 布局中,大 Key 的拆分对 node 间的内存均衡可以大概起到显著作用。
异步清算大 key

Redis 自 4.0 起提供了 UNLINK 下令,该下令可以大概以非壅闭的方式痴钝渐渐的清算传入的 Key,通过 UNLINK,你可以安全的删除大 Key 乃至特大 Key。
总结

如下查抄清单,资助你在遇到 Redis 性能变慢的时间能高效办理题目。

  • 获取当前 Redis 的基线性能;
  • 开启慢指令监控,定位慢指令导致的题目;
  • 找到慢指令,使用 scan 的方式;
  • 将实例的数据大小控制在 2-4GB,制止主从复制加载过大 RDB 文件而壅闭;
  • 禁用内存大页,采取了内存大页,天生 RDB 期间,纵然客户端修改的数据只有 50B 的数据,Redis 必要复制 2MB 的大页。当写的指令比力多的时间就会导致大量的拷贝,导致性能变慢。
  • Redis 使用的内存是否过大导致 swap;
  • AOF 设置是否公道,可以将设置项 no-appendfsync-on-rewrite 设置为 yes,制止 AOF 重写和 fsync 竞争磁盘 IO 资源,导致 Redis 耽误增长。
  • bigkey 会带来一系列题目,我们必要举行拆分防止出现 bigkey,并通过 UNLINK 异步删除。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-22 16:08, Processed in 0.127028 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表