Redis阻塞排查
定位问题方向
- redis持久化导致阻塞
- 是否存在慢查询
- 主从存在频繁全量同步)
- value值是否过大
- 架构问题,当前所有业务读取仅在一个从库读取
- 网络问题
- 连接数问题
API或数据结构使用不合理
影响
在理想状态下,Redis单实例能处理8~10w的QPS, 如果大量的redis命令大量耗时大于1ms, 其实QPS只能达到1000基于几百。
Redis出现耗时大的命令,导致其他所有请求被阻塞等待,redis处理能力急剧退化,易导致整个服务链雪崩。
slowlog命令排查
示例:获取最近2个慢查询命令
127.0.0.1:6381> SLOWLOG get 2
1) 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"
分析slowlog query:
以第一个HGET命令为例分析,每个slowlog实体共4个字段:
* 字段1:1个整数,表示这个slowlog出现的序号,server启动后递增, 当前为6.
* 字段2:表示查询执行时的Unix时间戳.
* 字段3:表示查询执行微妙数,当前是74372微妙,约74ms.
* 字段4: 表示查询的命令和参数,如果参数很多或很大,只会显示部分并给数参数个数;
当前命令是"hgetall" "max.dsp.blacklist"
慢查询排查
keys *
sort
hgetall
hmget
大对象排查
redis-cli -p 6380 --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
[00.00%] Biggest string found so far 'sgn_蚂蚁宝卡特权提醒' with 153 bytes
[00.00%] Biggest string found so far 'sgn_六安移动' with 218 bytes
[00.00%] Biggest hash found so far 'cst_115.api:56ce6aa50be29e554d2ea53b' with 3 fields
[00.00%] Biggest string found so far 'cmm_08332609921' with 2152 bytes
[00.08%] Biggest string found so far 'portal:session:bfd1bdfeb17f8b7be3a955a6ea125728' with 15840 bytes
[00.17%] Biggest string found so far 'portal:session:14b456954c80c34da1e647a0d3f4b0da' with 21652 bytes
[03.54%] Biggest hash found so far 'cst_110.api:568a11507566cfbb4e8b461a' with 4 fields
[06.43%] Biggest set found so far 'imeif_5d8dc523e87f2972903adc4e' with 12 members
[08.16%] Biggest string found so far 'portal:session:ccf43964a35b35e666d989c42712fe58' with 21665 bytes
[19.27%] Biggest hash found so far 'cst_oneplus.api:5c41ae695e8d372a4e6a2182' with 5 fields
[32.21%] Biggest set found so far 'imeif_5dbc2bffe87f295602c9a101' with 1009250 members
[64.37%] Biggest list found so far 'blk_sign' with 1 items
[66.45%] Biggest set found so far 'imeif_5dc404a0e87f2967afb51489' with 1021411 members
[87.03%] Biggest string found so far 'portal:session:234B80E3EA16225476BC93EB271085B9' with 22432 bytes
-------- summary -------
Sampled 705519 keys in the keyspace!
Total key length in bytes is 14653444 (avg len 20.77)
Biggest string found 'portal:session:234B80E3EA16225476BC93EB271085B9' has 22432 bytes
Biggest list found 'blk_sign' has 1 items
Biggest set found 'imeif_5dc404a0e87f2967afb51489' has 1021411 members
Biggest hash found 'cst_oneplus.api:5c41ae695e8d372a4e6a2182' has 5 fields
698252 strings with 114776273 bytes (98.97% of keys, avg size 164.38)
1 lists with 1 items (00.00% of keys, avg size 1.00)
14 sets with 2481633 members (00.00% of keys, avg size 177259.50)
7252 hashs with 20654 fields (01.03% of keys, avg size 2.85)
0 zsets with 0 members (00.00% of keys, avg size 0.00)
CPU饱和
单线程的Redis处理命令时只能使用一个CPU。 而CPU饱和是指Redis把单核CPU使用率跑到接近100%。 使用top命令很容易识别出对应Redis进程的CPU使用率。 CPU饱和是非常危险的, 将导致Redis无法处理更多的命令, 严重影响吞吐量和应用方的稳定性。 对于这种情况, 首先判断当前Redis的并发量是否达到极限, 建议使用统计命令redis-cli-h{ip}-p{port}–stat获取当前Redis使用情况, 该命令每秒输出一行统计信息, 运行效果如下
redis-cli -p 6380 --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
705516 404.05M 1919 0 449841044 (+0) 3011244
705516 406.58M 1919 0 449847750 (+6706) 3011315
705516 404.24M 1919 0 449854731 (+6981) 3011329
705516 404.75M 1919 0 449861512 (+6781) 3011355
705516 404.61M 1920 0 449867974 (+6462) 3011373
705516 406.29M 1920 0 449874423 (+6449) 3011418
705516 404.14M 1920 0 449881252 (+6829) 3011418
如果只有几百或几千OPS的Redis实例就接近CPU饱和是很不正常的, 有可能使用了高算法复杂度的命令。 还有一种情况是过度的内存优化, 这种情况有些隐蔽, 需要我们根据info commandstats统计信息分析出命令不合理开销时间,比如命令执行的次数、命令耗费的 CPU 时间、执行每个命令耗费的平均 CPU 时间等等 。对于每种类型的命令,这个部分都会添加一行以下格式的信息
cmdstat_XXX:calls=XXX,usec=XXX,usecpercall=XXX
使用如下命令:
redis-cli -p 6380 info commandstats
# Commandstats
cmdstat_psync:calls=1,usec=5722,usec_per_call=5722.00
cmdstat_exists:calls=2242429,usec=2356209,usec_per_call=1.05
cmdstat_slowlog:calls=1,usec=56,usec_per_call=56.00
cmdstat_set:calls=546,usec=3245,usec_per_call=5.94
cmdstat_hmset:calls=369,usec=5480,usec_per_call=14.85
cmdstat_ping:calls=10107937,usec=3569523,usec_per_call=0.35
cmdstat_replconf:calls=105617,usec=116086,usec_per_call=1.10
cmdstat_command:calls=5,usec=1678,usec_per_call=335.60
cmdstat_info:calls=244,usec=94019,usec_per_call=385.32
cmdstat_cluster:calls=466,usec=51560,usec_per_call=110.64
cmdstat_type:calls=705519,usec=350383,usec_per_call=0.50
cmdstat_scan:calls=144535,usec=66939901,usec_per_call=463.14
cmdstat_hget:calls=2,usec=7,usec_per_call=135.0
cmdstat_strlen:calls=698252,usec=339424,usec_per_call=0.49
cmdstat_setex:calls=92,usec=1124,usec_per_call=12.22
cmdstat_del:calls=713,usec=6303,usec_per_call=8.84
cmdstat_get:calls=363273995,usec=474297381,usec_per_call=1.31
cmdstat_publish:calls=981,usec=23550,usec_per_call=24.01
cmdstat_dbsize:calls=1,usec=1,usec_per_call=1.00
cmdstat_hlen:calls=7252,usec=5161,usec_per_call=0.71
cmdstat_subscribe:calls=41,usec=257,usec_per_call=6.27
cmdstat_expire:calls=8917,usec=19285,usec_per_call=2.16
cmdstat_llen:calls=1,usec=1,usec_per_call=1.00
cmdstat_hgetall:calls=74256666,usec=155559966,usec_per_call=2.09
cmdstat_lrange:calls=108,usec=635,usec_per_call=5.88
cmdstat_sismember:calls=559344,usec=1049039,usec_per_call=1.88
cmdstat_scard:calls=14,usec=8,usec_per_call=0.57
查看这个统计可以发现一个问题, hset命令算法复杂度只有O(1) 但平均耗时却达到135微秒, 显然不合理, 正常情况耗时应该在10微秒以下。 这是因为上面的Redis实例为了追求低内存使用量, 过度放宽ziplist使用条件(修改了hash-max-ziplist-entries和hash-max-ziplist-value配置) 。 进程内的hash对象平均存储着上万个元素, 而针对ziplist的操作算法复杂度在O(n)到O(n2) 之间。 虽然采用ziplist编码后hash结构内存占用会变小, 但是操作变得更慢且更消耗CPU。 ziplist压缩编码是Redis用来平衡空间和效率的优化手段, 不可过度使用
持久化阻塞
对于开启了持久化功能的Redis节点, 需要排查是否是持久化导致的阻塞。 持久化引起主线程阻塞的操作主要有: fork阻塞、 AOF刷盘阻塞、HugePage写操作阻塞。
fork阻塞
fork操作发生在RDB和AOF重写时, Redis主线程调用fork操作产生共享内存的子进程, 由子进程完成持久化文件重写工作。 如果fork操作本身耗时过长, 必然会导致主线程的阻塞。可以执行info stats命令获取到latest_fork_usec指标, 表示Redis最近一次fork操作耗时, 如果耗时很大, 比如超过1秒, 则需要做出优化调整, 如避免使用过大的内存实例和规避fork缓慢的操作系统等
redis-cli -p 6380 info stats |grep latest_fork_usec
latest_fork_usec:7578
Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化 。 Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以将父子进程想像成一个连体婴儿,共享身体。这是 Linux 操作系 统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的
增长几乎没有明显变化。
子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。
这个时候就会使用操作系统的 COW 机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
随着父进程修改操作的持续进行,越来越多的共享页面被分离出来,内存就会持续增长。但是也不会超过原有数据内存的 2 倍大小。另外一个 Redis 实例里冷数据占的比例往往是比较高的,所以很少会出现所有的页面都会被分离,被分离的往往只有其中一部分页面。每个页面的大小只有 4K,一个 Redis 实例里面一般都会有成千上万的页面。子进程因为数据没有变化,它能看到的内存里的数据在进程产生的一瞬间就凝固了,再也不会改变,这也是为什么 Redis 的持久化叫「快照」的原因。接下来子进程就可以非常安心的遍历数据了进行序列化写磁盘了。
AOF刷盘阻塞
当我们开启AOF持久化功能时, 文件刷盘的方式一般采用每秒一次, 后台线程每秒对AOF文件做fsync操作。 当硬盘压力过大时, fsync操作需要等待, 直到写入完成。 如果主线程发现距离上一次的fsync成功超过2秒, 为了数据安全性它会阻塞直到后台线程执行fsync操作完成。 这种阻塞行为主要是硬盘压力引起, 可以查看Redis日志识别出这种情况, 当发生这种阻塞行为时, 会打印如下日志:
Asynchronous AOF fsync is taking too long (disk is busy). Writing the AOF
buffer without waiting for fsync to complete, this may slow down Redis.
也可以查看info persistence统计中的aof_delayed_fsync指标, 每次发生fdatasync阻塞主线程时会累加。
提示:
硬盘压力可能是Redis进程引起的, 也可能是其他进程引起的, 可以使用iotop查看具体是哪个进程消耗过多的硬盘资源。
HugePage写操作阻塞
子进程在执行重写期间利用Linux写时复制技术降低内存开销, 因此只有写操作时Redis才复制要修改的内存页。 对于开启Transparent HugePages的操作系统, 每次写命令引起的复制内存页单位由4K变为2MB, 放大了512倍, 会拖慢写操作的执行时间, 导致大量写操作慢查询。 例如简单的incr命令也会出现在慢查询中。
Redis官方文档阻塞问题分类说明
详细介绍, 细节请见: http://www.redis.io/topics/latency。
CPU竞争
通过top、 sar等命令定位到CPU消耗的时间点和具体进程
内存交换
内存交换(swap) 对于Redis来说是非常致命的, Redis保证高性能的一个重要前提是所有的数据在内存中。 如果操作系统把Redis使用的部分内存换出到硬盘, 由于内存与硬盘读写速度差几个数量级, 会导致发生交换后的Redis性能急剧下降。 识别Redis内存交换的检查方法如下:
查询redis进程号
redis-cli -p 6380 info server | grep process_id
process_id:10702
根据进程号查询内存交换信息
cat /proc/10702/smaps | grep Swap
Swap: 0 kB
Swap: 0 kB
Swap: 4 kB
Swap: 0 kB
Swap: 0 kB
如果交换量都是0KB或者个别的是4KB, 则是正常现象, 说明Redis进程内存没有被交换。 同时还可以打印内存映射的大小来进行判断:
$ cat smaps | egrep '^(Swap|Size)'
Size: 316 kB
Swap: 0 kB
Size: 4 kB
Swap: 0 kB
Size: 8 kB
Swap: 0 kB
Size: 40 kB
Swap: 0 kB
Size: 132 kB
Swap: 0 kB
Size: 720896 kB
Swap: 12 kB
Size: 4096 kB
Swap: 156 kB
Size: 4096 kB
Swap: 8 kB
Size: 4096 kB
Swap: 0 kB
从输出中可以看到,有一张720896 kB的映射(仅交换了12 kB),在另一张映射中还有156 kb的交换:基本上我们的内存被交换的很少,所以这不会造成任何问题.
相反,如果在磁盘上交换了少量的进程内存,则延迟问题很可能与交换有关。如果您的Redis实例属于这种情况,则可以使用vmstat命令进一步验证它:
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 3980 697932 147180 1406456 0 0 2 2 2 0 4 4 91 0
0 0 3980 697428 147180 1406580 0 0 0 0 19088 16104 9 6 84 0
0 0 3980 697296 147180 1406616 0 0 0 28 18936 16193 7 6 87 0
0 0 3980 697048 147180 1406640 0 0 0 0 18613 15987 6 6 88 0
2 0 3980 696924 147180 1406656 0 0 0 0 18744 16299 6 5 88 0
0 0 3980 697048 147180 1406688 0 0 0 4 18520 15974 6 6 88 0
^C
我们需要的输出中有趣的部分是两列si 和so,它计算了从交换文件交换到交换文件的内存量。如果在这两列中看到非零计数,则系统中存在交换活动。
最后,可以使用iostat命令来检查系统的全局I / O活动。
$ iostat -xk 1
avg-cpu: %user %nice %system %iowait %steal %idle
13.55 0.04 2.92 0.53 0.00 82.95
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util
sda 0.77 0.00 0.01 0.00 0.40 0.00 73.65 0.00 3.62 2.58 0.00
sdb 1.27 4.75 0.82 3.54 38.00 32.32 32.19 0.11 24.80 4.24 1.85
预防内存交换的方法有:
-
保证机器充足的可用内存。
-
确保所有Redis实例设置最大可用内存(maxmemory) , 防止极端情况下Redis内存不可控的增长。
网络问题
网关带宽
通过监控工具查看网关带宽是否耗尽的情况
通过命令查看每秒执行指令数
redis-cli -p 6380 info stats |grep ops
instantaneous_ops_per_sec:8344
redis连接拒绝
linux命令:
ss -s
Total: 3768 (kernel 3804)
TCP: 3668 (estab 3657, closed 1, orphaned 0, synrecv 0, timewait 1/0), ports 0
Transport Total IP IPv6
* 3804 - -
RAW 0 0 0
UDP 4 3 1
TCP 3667 3667 0
INET 3671 3670 1
FRAG 0 0 0
redis命令:
redis-cli -p 6379 info clients
# Clients
connected_clients:1 # 这个就是正在连接的客户端数量
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
这个信息也是比较有用的,通过观察这个数量可以确定是否存在意料之外的连接。如果发现这个数量不对劲,接着就可以使用 client list 指令列出所有的客户端链接地址来确定源头
redis-cli -p 6379 client list
id=16959205 addr=192.168.20.173:55202 fd=616 name= age=17 idle=17 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping
id=16959206 addr=192.168.20.173:55204 fd=820 name= age=17 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=hgetall
id=16959207 addr=192.168.20.173:55206 fd=1205 name= age=17 idle=3 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=hgetall
查看客户端连接数:
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n
82 192.168.20.206
82 192.168.21.190
82 192.168.22.37
82 192.168.22.39
83 192.168.20.183
83 192.168.20.188
83 192.168.20.216
83 192.168.21.100
83 192.168.21.191
83 192.168.21.64
83 192.168.21.99
83 192.168.6.28
84 192.168.21.224
关于客户端的数量还有个重要的参数需要观察,那就是 rejected_connections,它表示因为超出最大连接数限制而被拒绝的客户端连接次数,如果这个数字很大,意味着服务器的最大连接数设置的过低需要调整 maxclients 参数。
redis-cli -p 6380 info stats | grep rejected_connections
rejected_connections:0
连接溢出
-
进程限制
操作系统一般会对进程使用的资源做限制, 其中一项是对进程可打开最大文件数控制, 通过ulimit-n查看, 通常默认1024。 由于Linux系统对TCP连接也定义为一个文件句柄, 因此对于支撑大量连接的Redis来说需要增大这个值, 如设置ulimit-n 65535, 防止Too many open files错误。
ulimit -n 65535
-
网络延迟
Redis提供了测量机器之间网络延迟的工具, 在redis-cli-h{host}-p{port}命令后面加入如下参数进行延迟测试:
- –latency: 持续进行延迟测试, 分别统计: 最小值、 最大值、 平均值、
采样次数。 - –latency-history: 统计结果同–latency, 但默认每15秒完成一行统计,
可通过-i参数控制采样时间。–latency-dist: 使用统计图的形式展示延迟统计, 每1秒采样一次。
- –latency: 持续进行延迟测试, 分别统计: 最小值、 最大值、 平均值、
-
backlog队列溢出
系统对于特定端口的TCP连接使用backlog队列保存。 Redis默认的长度为511, 通过tcp-backlog参数设置。 如果Redis用于高并发场景为了防止缓慢连接占用, 可适当增大这个设置, 但必须大于操作系统允许值才能生效。 当Redis启动时如果tcp-backlog设置大于系统允许值将以系统值为准, Redis打印如下警告日志:
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/ net/core/somaxconn is set to the lower value of 128.
可以通过netstat-s命令获取因backlog队列溢出造成的连接拒绝统计, 如下
# netstat -s | grep overflowed 663 times the listen queue of a socket overflowed
如果怀疑是backlog队列溢出, 线上可以使用cron定时执行netstat-s|grep overflowed统计, 查看是否有持续增长的连接拒绝情况
全量复制导致fork阻塞
全量复制是一个非常消耗资源的操作, 因此如何规避全量复制是需要重点关注的运维点。 下面我们对需要进行全量复制的场景逐个分析:
·第一次建立复制:
由于是第一次建立复制, 从节点不包含任何主节点数据, 因此必须进行全量复制才能完成数据同步。 对于这种情况全量复制无法避免。 当对数据量较大且流量较高的主节点添加从节点时, 建议在低峰时
进行操作, 或者尽量规避使用大数据量的Redis节点。
·节点运行ID不匹配:
当主从复制关系建立后, 从节点会保存主节点的运行ID, 如果此时主节点因故障重启, 那么它的运行ID会改变, 从节点发现主节点运行ID不匹配时, 会认为自己复制的是一个新的主节点从而进行全量复制。 对于这种情况应该从架构上规避, 比如提供故障转移功能。 当主节点发生故障后, 手动提升从节点为主节点或者采用支持自动故障转移的哨兵或集群方案。
·复制积压缓冲区不足:
当主从节点网络中断后, 从节点再次连上主节点时会发送psync{offset}{runId}命令请求部分复制, 如果请求的偏移量不在主节点的积压缓冲区内, 则无法提供给从节点数据, 因此部分复制会退化为全量复制。 针对这种情况需要根据网络中断时长, 写命令数据量分析出合理的积压缓冲区大小。 网络中断一般有闪断、 机房割接、 网络分区等情况。 这时网络中断的时长一般在分钟级(net_break_time) 。 写命令数据量可以统计高峰期主节点每秒info replication的master_repl_offset差值获取(write_size_per_minute) 。 积压缓冲区默认为1MB, 对于大流量场景显然不够, 这时需要增大积压缓冲区, 保证repl_backlog_size>net_break_time*write_size_per_minute, 从而避免因复制积压缓冲区不足造成的全量复制。
client list
redis > client list
id=254487 addr=10.2.xx.234:60240 fd=1311 name= age=8888581 idle=8888581 flags=N
db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=300210 addr=10.2.xx.215:61972 fd=3342 name= age=8054103 idle=8054103 flags=N
db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=5448879 addr=10.16.xx.105:51157 fd=233 name= age=411281 idle=331077 flags=N
db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ttl
id=2232080 addr=10.16.xx.55:32886 fd=946 name= age=603382 idle=331060 flags=N
db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=7125108 addr=10.10.xx.103:33403 fd=139 name= age=241 idle=1 flags=N db=0
sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=del
id=7125109 addr=10.10.xx.101:58658 fd=140 name= age=241 idle=1 flags=N db=0
输入缓冲区: qbuf、 qbuf-free
Redis为每个客户端分配了输入缓冲区, 它的作用是将客户端发送的命令临时保存, 同时Redis从会输入缓冲区拉取命令并执行, 输入缓冲区为客户端发送命令到Redis执行命令提供了缓冲功能,每个客户端缓冲区的大小不能超过1G, 超过后客户端将被关闭 。
**输入缓冲区过大主要是因为Redis的处理速度跟不上输入缓冲区的输入速度, 并且每次进入输入缓冲区的命令包含了大量bigkey, 从而造成了输入缓冲区过大的情况。 还有一种情况就是Redis发生了阻塞, 短期内不能处理命令, 造成客户端输入的命令积压在了输入缓冲区,造成了输入缓冲区过大**
通过info命令的info clients模块, 找到最大的输入缓冲区, 例如下面命令中的其中client_biggest_input_buf代表最大的输入缓冲区, 例如可以设置超过10M就进行报警
> info clients
# Clients
client_biggest_input_buf:2097152
输出缓冲区: obl、 oll、 omem
Redis为每个客户端分配了输出缓冲区, 它的作用是保存命令执行的结果返回给客户端, 为Redis和客户端交互返回结果提供缓冲。
输出缓冲区的容量可以通过参数client-outputbuffer-limit来进行设置, 并且输出缓冲区做得更加细致, 按照客户端的不同分为三种: 普通客户端、 发布订阅客户端、 slave客户端
对应的配置规则是:
client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
·
·
·
通过定期执行client list命令, 收集obl、 oll、 omem找到异常的连接记录并分析, 最终找到可能出问题的客户端或者通过info命令的info clients模块, 找到输出缓冲区列表最大对象数, 例如:
> info clients
# Clients
client_longest_output_list:4869