Redis性能诊断

yichen
yichen
发布于 2024-05-13 / 92 阅读
0
0

Redis性能诊断

Redis 作为一款业内使用率最高的内存数据库,其拥有非常高的性能,单节点的QPS压测能达到18万以上。但也正因此如此,当应用访问 Redis 时,如果发现响应延迟变大时就会给业务带来非常大的影响。

  本文详细梳理了可能引起Redis性能问题的原因并剖析对应的解决方案。

Redis性能诊断-1665279556600

一、数据持久化的影响

为了保证 Redis 数据的安全性,我们可能会开启Redis的持久化将数据落盘,避免Redis服务崩溃或者服务器宕机导致的数据丢失。

  Redis当前支持两种典型的持久化模式:RDB、AOF。

  RDB持久化,称为内存快照。这种模式是把当前Redis服务的内存数据在某一点dump生成快照保存到磁盘上的过程,由于是某一时刻的快照,开启快照后发起后所有操作命令都不会再被记录。
  AOF 持久化。AOF持久化以日志的形式记录Redis所执行的每个写操作,注意查询操作不会记录,可以打开磁盘文件看到每条详细的操作记录。

1、RDB镜像落盘及AOF重写时的影响

  Redis开始执行RDB或者AOF Rewrite后,主进程都会创建出一个子进程进行数据的持久化落盘操作。在这个过程中,则会调用操作系统的 fork 操作。

  通过 fork 对内存数据的 copy-On-Write 机制最廉价的实现内存镜像。虽然内存是 copy on write 的,但是虚拟内存表是在 fork 的瞬间就需要分配,所以这个操作会造成主线程短时间的卡顿(停止所有读写操作),这个卡顿时间和当前 Redis 的内存使用量有关。

  根据经验 GB 量级的 Redis 进行 fork 操作的时间在毫秒级。

  如果这个Redis实例很大,CPU负载再高些,那么 fork 的耗时就会更长,甚至达到秒级,也就会严重影响 Redis 的访问响应时间。

  为了避免这种情况,可以采取以下优化方式:

  • 关闭RDB和AOF的自动触发机器,避免业务高峰自动触发执行;

  • 控制 Redis 使用内存大小,建议控制在20G 以下,因为执行 fork 的耗时与数据内存大小有关,数据越多,耗时会越久;

  • 对于主从集群架构,建议关闭主库AOF,从库开启;对于有备份需求的集群,也可以在从库发起RDB备份操作;

  • 合理配置 repl-backlog-size大小,降低主从全量重传【2.8版本之前的节点强烈建议升级】;

  • 尽量不要使用虚拟机,fork 的耗时也与系统也有关,虚拟机比物理机耗时更长。

2、AOF持久化磁盘IO带来的影响

针对AOF持久化对Redis性能可能带来的影响可以参考如下几种解决方案:

  • SSD 磁盘存储,确保AOF刷盘时有充足的IO能力

  • 对于主从集群架构,建议关闭主库AOF,从库开启

  • 将no-appendfsync-on-rewrite参数设置为yes, 确保aof文件rewrite期间不做fsync操作,减少IO争用

  • 单台服务器不要部署过多持久化实例节点,避免磁盘IO争抢带来持久化压力

二、内存碎片过大及整理带来的性能损耗

  Redis 的所有数据都在内存中,当应用频繁修改时,就会导致产生内存碎片。过高的内存碎片率,不仅会浪费内存资源还会影响请求处理的效率。

  那么,是什么原因导致Redis 产生碎片的呢?原理是什么,能避免吗?

  当前Redis 都默认使用jemalloc内存分配器来分配内存,它一般是按固定大小来分配内存空间,而不会按照应用程序申请的内存大小给实际分配。当程序申请的内存大小最接近某个固定值时,如8 byte、16 byte,…,2KB、4KB 等,jemalloc 会给它分配相应大小的空间。

  这样的方式好处是为了减少分配次数。假设Redis申请一个 10 byte的内存空间存储数据,jemalloc 会分配 16 byte,此时,如果应用还要再写入 4 byte的数据,Redis 就不用再向操作系统申请空间了,因为刚才分配的 16 byte已经够用了,也就避免了一次额外分配操作开销。

  所以Redis每次分配的内存空间一般都会比申请的实际需求空间大一些,这种分配方式就自然会导致形成碎片。

  从目前Redis内存的分配机制来看,目前碎片无法完全避免。

  Redis 的内存利用率的高低除了成本外,也会直接影响到 Redis 运行效率的高低。可以使用如下命令查看Redis内存使用、碎片率、分配器版本等详细信息:

redis> info Memory
used_memory:6617819416
used_memory_human:6.16G
used_memory_rss:9788588032
used_memory_rss_human:9.12G
…
rss_overhead_ratio:1.00
rss_overhead_bytes:-21159936
mem_fragmentation_ratio:1.48
mem_fragmentation_bytes: 3250855264
…
mem_allocator:jemalloc-5.1.0
…

mem_fragmentation_ratio 就是Redis 当前的内存碎片率大小,碎片率计算方法:mem_fragmentation_ratio=used_memory_rss/used_memory

  used_memory 表示存储的数据实际占用内存的大小,而used_memory_rss 指操作系统分配给 Redis进程服务的实际大小,也就是使用top命令查看Redis进程占用的内存。

  一般当mem_fragmentation_ratio>1.5时,就说明内存碎片率已经超过了50%,此时建议采取措施来降低内存碎片大小。

如何清理内存碎片呢?根据版本的不同有两种方式:

  • Redis 4.0 以前的低版本,只能通过重启实例来解决,不能自动配置回收

  • 从 4.0版本以后,提供了一种内存碎片自动回收的方法,可以通过配置动态开启碎片整理

  但要注意:开启内存碎片整理,会导致 Redis 服务性能下降。

  Redis 的碎片整理工作是在主线程中执行的,当其进行碎片整理时,操作系统会把多份数据拷贝到新位置以把原有空间释放出来,这会带来时间开销,而这个过程就会阻塞Redis处理请求。

  为了降低碎片整理带来的性能影响,Redis 为自动内存碎片整理功机制提供了多个参数,具体有:

  • activedefrag yes #是否开启碎片整理

  • active-defrag-ignore-bytes 500mb #碎片大小超过 500MB 时才会触发整理

  • active-defrag-threshold-lower 20 #碎片大小占操作系统分配总空间比超过 20% 时触发整理

  • active-defrag-cycle-min 15 #碎片整理过程占用的CPU比例不低于 15%,保证整理可以正常执行

  • active-defrag-cycle-max 70 #碎片整理过程占用的CPU比例不高于70%,一旦超过就暂停整理,避免大量的内存拷贝等整理过程占用过多的CPU进而影响正常请求

  • active-defrag-max-scan-fields 500 #碎片整理过程中,对于 Hash、List、Set、ZSet 等成员集合类型一次扫描的元素数量

  在开启碎片自动整理时,一定要优先评估当前 Redis 服务的负载状态,以及应用程序可接受的响应延迟,合理设置碎片整理的参数值和回收时间段【比如放到凌晨程序定时触发】,来尽可能降低碎片整理期间对Redis服务的影响。

三、常见不合理操作

1、使用复杂度过高的命令

之前的文章我们已经介绍了Redis的底层数据结构,它们的时间复杂度如下表所示:

序号

名称

时间复杂度

1

dict(字典)

O(1)

2

ziplist (压缩列表)

O(n)

3

zskiplist(跳表)

O(logN)

4

quicklist(快速列表)

O(n)

5

intset(整数集合)

O(n)

「单元素操作」:对集合中的元素进行增删改查操作和底层数据结构相关,如对字典进行增删改查时间复杂度为O(1),对跳表进行增删查时间复杂为O(logN)
「范围操作」:对集合进行遍历操作,比如Hash类型的HGETALL,Set类型的SMEMBERS,List类型的LRANGE,ZSet类型的ZRANGE,时间复杂度为O(n),避免使用,用SCAN系列命令代替。(hash用hscan,set用sscan,zset用zscan)
「聚合操作」:这类操作的时间复杂度通常大于O(n),比如SORT、SUNION、ZUNIONSTORE
「统计操作」:当想获取集合中的元素个数时,如LLEN或者SCARD,时间复杂度为O(1),因为它们的底层数据结构如quicklist,dict,intset保存了元素的个数
「边界操作」:list底层是用quicklist实现的,quicklist保存了链表的头尾节点,因此对链表的头尾节点进行操作,时间复杂度为O(1),如LPOP、RPOP、LPUSH、RPUSH。

(1)应用中高频使用了 O(N) 及以上复杂度的命令,例如:SUNION、SORT、ZUNIONSTORE、ZINTERSTORE 聚合类命令。SORT命令的时间复杂度:O(N+M*log(M)), N 为要排序的列表或集合内的元素数量, M 为要返回的元素数量。

  这种导致Redis请求变慢的原因是,Redis 在操作数据排序时,时间复杂度过高,要花费更多的 CPU计算资源。

(2)使用 O(N) 复杂度的命令,但 N 的值非常大,比如hgetall、smembers、lrange、zrange等命令。

  这种变慢的原因在于,Redis 一次需要返回给客户端的数据过多,需要花费更多时间在数据组装和网络传输中。对于hgetall、smembers这种命令,需要警惕项目刚上线之初hash、set或者list存储的成员个数较少,但是随着业务发展成员数量极有可能会膨胀的非常大,如果仍然采用上述命令不加控制,会极大拖累整个Redis服务的响应时间。

  针对这两种情况还都可以从资源使用率层面来分析,如果应用程序访问 Redis 的QPS不是很大,但 Redis 实例的 CPU 使用率却很高,那么很有可能是使用了复杂度过高的命令导致的。

  因为Redis 是单线程处理请求的,如果你经常使用以上复杂度较高的命令,那么当 Redis 处理程序请求时,一旦前面某个命令发生耗时较长,就会导致后面的请求发生阻塞排队,对于应用程序来说,响应延迟也会变长。

2、操作bigkey

  如果一个key对应的value非常大,那么这个key就被称为bigkey。写入bigkey在分配内存时需要消耗更长的时间。同样,删除bigkey释放内存也需要消耗更长的时间
在分析慢日志发现很多请求并不是复杂度高的命令,都是一些del、set、hset等的低复杂度命令,那么就要评估是否写入了大key。

  当然这个描述仍然比较宽泛,因为Redis中的数据库结构类型比较多,更完善的一些说法可以这么定义:将含有较大数据或含有大量成员、列表数的Key定义为bigkey。

  我们一般要求研发使用Redis时,对于String类型Value大小不要超过1KB。

大Key带来的问题比较多,主要有下面几种情况:

  • 由于大Key的内存分配及释放开销变大,直接影响就是导致应用访问Redis的响应变慢;

  • 删除时会造成较长时间的阻塞并有可能造成集群主备节点切换【4.0之前的版本有这个问题】;

  • 内存占用过多甚至达到maxmemory配置,会造成新写入阻塞或一些不应该被提前删除的Key被逐出,甚至导致OOM发生;

  • 并发读请求因为Key过大会可能打满服务器带宽,如果单机多实例部署则同时会影响到该服务器上的其它服务【假设一个bigkey为1MB,客户端每秒访问量为1000,那么每秒产生1000MB的流量】;

  • 运维麻烦,比如RedisCluster的数据跨节点均衡,因为均衡迁移原理是通过migrate命令来完成的,这个命令实际是通过dump + restore + del三个命令组合成原子命令完成,如果是bigkey,可能会使迁移失败,而且较慢的migrate也会阻塞Redis正常请求;

  • 分片集群RedisCluster中的出现严重的数据倾斜,导致某个节点的内存使用过大;

如何定位bigkey?

Redis提供了扫描bigkey的命令:

$ redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

...
-------- summary -------

Sampled 829675 keys in the keyspace!
Total key length in bytes is 10059825 (avg len 12.13)

Biggest string found 'key:291880' has 10 bytes
Biggest   list found 'mylist:004' has 40 items
Biggest    set found 'myset:2386' has 38 members
Biggest   hash found 'myhash:3574' has 37 fields
Biggest   zset found 'myzset:2704' has 42 members

36313 strings with 363130 bytes (04.38% of keys, avg size 10.00)
787393 lists with 896540 items (94.90% of keys, avg size 1.14)
1994 sets with 40052 members (00.24% of keys, avg size 20.09)
1990 hashs with 39632 fields (00.24% of keys, avg size 19.92)
1985 zsets with 39750 members (00.24% of keys, avg size 20.03)

可以看到命令的输入有如下3个部分

  1. 内存中key的数量,已经占用的总内存,每个key占用的平均内存

  2. 每种类型占用的最大内存,已经key的名字

  3. 每种数据类型的占比,以及平均大小
    这个命令的原理就是redis在内部执行了scan命令,遍历实例中所有的key,然后正对key的类型,分别执行strlen,llen,hlen,scard,zcard命令,来获取string类型的长度,容器类型(list,hash,set,zset)的元素个数。

使用这个命令需要注意如下两个问题:

  1. 对线上实例进行bigkey扫描时,为避免ops(operation per second 每秒操作次数)突增,可以通过-i增加一个休眠参数,上面的含义为,每隔100条scan指令就会休眠0.01s;

  2. 对于容器类型(list,hash,set,zset),扫描出的是元素最多的key,但一个key的元素数量多,不一定代表占用的内存多;

  3. 对于集合类型的Hash、List、Set、ZSet仅仅统计的是包含的成员个数,个数多并代表占用的内存大,仅仅是个参考;

  4. 对于高并发访问的集群,使用该命令会造成QPS增加,带来额外的性能开销,建议在业务低峰或者从节点进行扫描。

如何解决bigkey带来的性能问题?

  1. 对大Key进行拆分——如将一个含有数万成员的HASH Key拆分为多个HASH Key,并确保每个Key的成员数量在合理范围。特别是在RedisCluster架构下中,大Key的拆分对各节点间的内存平衡能够起到显著作用;

  2. 优化使用删除Key的命令——Redis自4.0起提供了UNLINK命令,该命令可以替换DEL,能够以非阻塞的方式放到后台线程中缓慢逐步的清理大Key所占用的内存块,从而减轻了对Redis的影响;Redis 6.0 以上版本,建议开启 lazy-free 机制(配置参数:lazyfree-lazy-user-del = yes,6.2版本之后默认开启了),这样在 DEL删除大Key时,释放内存的动作也是在后台线程中执行的;

  3. 尽量不写入大Key——首先评估使用其他的存储形式,比如文档性数据库 MongoDB等;如果还无法避免使用BigKey,可以将大Key进行压缩后存储,并尽量根据业务精简Value的内容;建议单个Key的大小不要超过1K。

3、大量key集中过期

我们可以给Redis中的key设置过期时间,那么当key过期了,它在什么时候会被删除呢?
如果让我们写Redis过期策略,我们会想到如下三种方案:

  1. 定时删除,在设置键的过期时间的同时,创建一个定时器。当键的过期时间来临时,立即执行对键的删除操作

  2. 惰性删除,每次获取键的时候,判断键是否过期,如果过期的话,就删除该键,如果没有过期,则返回该键

  3. 定期删除,每隔一段时间,对键进行一次检查,删除里面的过期键 定时删除策略对CPU不友好,当过期键比较多的时候,Redis线程用来删除过期键,会影响正常请求的响应

  定时删除策略对CPU不友好,当过期键比较多的时候,Redis线程用来删除过期键,会影响正常请求的响应。
  惰性删除读CPU是比较有好的,但是会浪费大量的内存。如果一个key设置过期时间放到内存中,但是没有被访问到,那么它会一直存在内存中;
  定期删除策略则对CPU和内存都比较友好。

  redis过期key的删除策略选择了如下两种:

  1. 惰性删除——客户端在访问key的时候,对key的过期时间进行校验,如果过期了就立即删除;

  2. 定期删除——在Redis 内部维护了一个定时任务,默认每隔 100 毫秒(1秒10次)从全局的过期哈希表中随机取出 20 个 key,判断然后删除其中过期的 key,如果过期 key 的比例超过了 25%,则继续重复此过程,直到过期 key 的比例下降到 25% 以下,或者这次任务的执行耗时超过了 25 毫秒,才会退出循环;

注意:Redis的key主动过期清理的定时任务,是在 Redis 主线程中执行的,也就意味着会阻塞正常的请求命令。进一步说就是如果在执行主动过期的过程中,出现了需要大量删除过期 key 的请求,那么此时应用程序在访问 Redis 时,必须要等待这个过期任务执行结束,Redis 才可以继续处理新请求。此时现象就是上面说的应用访问 Redis 延时突然变大了。

  特别是由于批量清理Key这个操作的命令是内部发起的并不会记录在慢日志中,但我们的应用程序却感知到了延迟变大,其实时间都花费在了删除过期 key 上,这种情况就经常被忽略。

  为了避免主线程一直在删除key,我们可以采用如下两种方案:

  1. 给同时过期的key增加一个随机数,打散过期时间,降低清除key的压力;

  2. 如果你使用的是redis4.0版本以上的redis,可以开启lazy-free机制(lazyfree-lazy-expire yes),当删除过期key时,把释放内存的操作放到后台线程中执行;

4、使用keys命令进行正则匹配

  Keys的正则匹配是阻塞式的、全量扫描过滤,这对于单线程服务的Redis来说是致命的,仅仅几十万个Key的匹配查询在高并发访问下就有可能将Redis打崩溃!这其实就像MySQL的无索引查询大表数据,全表扫描状态下几个并发查询就可能会将数据库堵死。

redis> SLOWLOG get 5
1) (integer) 42343
2) (integer) 1653659194
3) (integer) 73536

1) "KEYS"
2) "Testper::userList:*"
5) "192.168.1.10:20504"
6) ""

2) 1) (integer) 42342
2) (integer) 1653659194
3) (integer) 73650
4) 1) "KEYS"
2) "TestuserPermission:*"
5) "192.168.1.11:20362"
6) ""

1) (integer) 42341
2) (integer) 1653659193
3) (integer) 81505

1) "KEYS"
2) "TestuserRole:*"
5) "192.168.1.12:19926"
6) ""

上述示例中使用Keys来模糊查询某些Key,每次的执行都在70ms以上,严重影响了正常的Redis响应时长和吞吐。

  针对这种问题的一个解决方案是使用scan代替keys。这是一个查询迭代命令,用于迭代当前数据库中的缓存数据。它是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为Scan命令的游标参数, 以此来延续之前的迭代过程。具体的命令语法这里不再详述。

5、不合理使用批处理命令

  网上有不少关于批量处理的一些优化,使用mget、mset代替多次的get、set等,减少网络IO开销以此提高redis的处理效率,特别是对于一些php短连接效果尤其明显。

  但是对于这些批量处理命令原生的mget、mset,非原生命令如pipeline,一定要注意控制单次批量操作的元素个数,否则会阻塞其它请求命令!建议控制在500以内。针对该种场景的优化方案:

  • 降低使用 O(N) 以上复杂度的命令,对于数据的计算聚合操作等可以适当的放在应用程序侧处理;

  • 使用O(N) 复杂度的命令时,保证 N 尽量的小(推荐 N <= 500),每次处理的更小的数据量,降低阻塞的时长;

  • 对于Hgetall、Smembers操作的集合对象,应从应用层面保证单个集合的成员个数不要过大,可以进行适当的拆分等。

6、内存达到上限,触发淘汰策略

内存淘汰策略

Redis是一个内存数据库,当Redis使用的内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,交换会导致Redis性能急剧下降。所以在生产环境中我们通过配置参数maxmemoey来限制使用的内存大小。
  当实际使用的内存超过maxmemoey后,Redis提供了如下几种可选策略。

  • noeviction:写请求返回错误

  • volatile-lru:使用lru算法删除设置了过期时间的键值对 volatile-lfu:使用lfu算法删除设置了过期时间的键值对 volatile-random:在设置了过期时间的键值对中随机进行删除 volatile-ttl:根据过期时间的先后进行删除,越早过期的越先被删除

  • allkeys-lru:在所有键值对中,使用lru算法进行删除 allkeys-lfu:在所有键值对中,使用lfu算法进行删除 allkeys-random:所有键值对中随机删除

Redis的淘汰策略也是在主线程中执行的。但内存超过Redis上限后,每次写入都需要淘汰一些key,导致请求时间变长。

可以通过如下几个方式进行改善:

  1. 增加内存或者将数据放到多个实例中;

  2. 淘汰策略改为随机淘汰,一般来说随机淘汰比lru快很多;

  3. 避免存储bigkey,降低释放内存的耗时;

  4. 合理预估内存占用,避免达到内存的使用上限。

7、写AOF日志的方式为always

写AOF日志方式

Redis的持久化机制有RDB快照和AOF日志,每次写命令之后后,Redis提供了如下三种刷盘机制

  • always:同步写回,写命令执行完就同步到磁盘;

  • everysec:每秒写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,每隔1秒将缓冲区的内容写入磁盘;

  • no:操作系统控制写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回到磁盘;

  当aof的刷盘机制为always,redis每处理一次写命令,都会把写命令刷到磁盘中才返回,整个过程是在Redis主线程中进行的,势必会拖慢redis的性能;
  当aof的刷盘机制为everysec,redis写完内存后就返回,刷盘操作是放到后台线程中去执行的,后台线程每隔1秒把内存中的数据刷到磁盘中;
  当aof的刷盘机制为no,宕机后可能会造成部分数据丢失,一般不采用。
一般情况下,aof刷盘机制配置为everysec即可

8、fork耗时过长

  我们知道,Redis生成rdb文件和aof日志重写,都是通过主线程fork子进程的方式,让子进程来执行的,主线程的内存越大,阻塞时间越长。

  可以通过如下方式优化:

  1. 控制Redis实例的内存大小,尽量控制到10g以内,因为内存越大,阻塞时间越长;

  2. 配置合理的持久化策略,如在slave节点生成rdb快照。

9、实际请求量超过了Redis的处理能力

  Redis处理速度再快,也有达到上限的时候。特别是一些大促活动时,业务流量往往出现暴涨,很容易就会达到Redis的处理瓶颈。这种在业务上的表现除了访问Redis变慢,一些简单的命令如get、set也开始出现在慢日志中。

  这时如果查看Redis的CPU使用情况,基本是100%的状态,那么大概率就是达到Redis的处理能力上限了。

  为了解决这种问题,就需要评估当前集群的处理吞吐力,参考官方的测评结果QPS 10W行不行?我们在上一篇文章介绍基本的压测有过说明,每个Redis所在的服务器配置不一样,处理能力就不一样。

  更进一步说,每个Redis承载的服务模型不同,比如使用的命令类型、访问比例等,那么处理的吞吐也会有很大不同。针对这种情况最好的方案就是业务上线前,可以模拟真实的业务进行压力测评,给出一个大概的吞吐处理能力。如果评估单节点无法承载过多请求,建议进行读写分离架构或者拆分为多套集群扩容.

  最后就是不要忽略运维监控,可以对使用的CPU使用率、访问的QPS等进行有效监控,提前发现是否达到集群的处理瓶颈,并决定是否进行扩容或架构调整。

四、慢日志分析

  分析Redis访问变慢,其中有个最基础的方法就是先去看Redis是否有慢日志【就像MySQL的慢SQL一样】。Redis提供了一个简单的慢命令统计记录功能,它会记录有哪些命令在执行时耗时较长。Redis慢日志功能由两个核心参数控制:

#慢日志命令执行阈值,这里指超过1ms就会被记录【单位为微秒】
slowlog-log-slower-than 1000

#保留慢日志命令的个数,类似一个先进先出的队列,超过4096个最早的就会被清理
slowlog-max-len 4096

Redis的这个慢日志功能比较粗糙简单,有个严重的不足:没有持久化记录能力

  由于Redis的慢日志记录都在内存中,不像MySQL会持久化到文件里,那么如果慢日志产生较快,即使设置的slowlog-max-len比较大也会很快被填满,诊断问题时也就不能统计到那个时间段产生的所有慢命令详情。

  为了避免产生的慢日志被清理,目前一个折中的解决方案是写一个收集程序周期性的将新增慢命令查出并记录到MySQL或者本地文件中,以备事后分析。但是这个频率一般都是分钟级,Redis处理的吞吐能力又太大,在慢命令较多的情况下往往也不能全部记录下来。

配置好慢日志相关阈值后,可以执行以下命令查询最近的慢日志记录了:

127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 42343
2) (integer) 1653659194 #慢日志产生的时间戳
3) (integer) 73536 #慢日志执行的耗时
4) 1) "KEYS" #慢日志命令详情
2) "permission::userMenuList:*"
5) "192.168.1.11:20504" #慢日志命令发起来源IP【4.0及以后版本支持】
6) ""2) 1) (integer) 42342
2) (integer) 1653659194
3) (integer) 73650
4) 1) "KEYS"
2) "userPermission:*"
5) "192.168.1.10:20362"
6) ""
3) 1) (integer) 42341
2) (integer) 1653659193
3) (integer) 81505
4) 1) "KEYS"
2) "userRole:*"
5) "192.168.1.13:19926"
6) ""

五、Redis访问架构(未完待续)


评论