Redis的CLIENT LIST命令我用了快十年但每次排障都还能挖出点新东西。刚开始做某电商项目的缓存运维时应用一压测Redis就卡死大家第一反应都是“加机器”“调maxmemory”结果两条CLIENT LIST输出甩出来问题一目了然一堆不健康的客户端连接把内存缓冲区撑爆了。也是从那以后这个命令成了我排查Redis问题时必看的第一项。CLIENT LIST能干什么一句话把当前Redis实例上所有客户端连接的快照列出来包括每个连接的地址、名字、状态、空闲时间、缓冲区使用、正在执行的命令等。它不是给监控系统看指标的而是给运维和开发“透视”连接真实状态的。适合谁用只要你的Redis实例出现过连接数突增、延迟抖动、OOM内存告警、命令阻塞或者你想搞明白客户端连接池到底有没有复用、有没有泄漏这篇文章就能帮你省掉大把抓瞎时间。1. 为什么需要CLIENT LIST先讲几个真实场景1.1 什么情况下你想起来用它我印象最深的几次都是“常规监控看不出来”的场景。比如某次大促前夜某应用服务刚上线Redis的CPU和内存都很正常但P99延迟涨了好几倍。用info命令看连接数也不高内存也没到上限。后来我通过CLIENT LIST发现有个客户端连接正在执行一个KEYS *命令bigkey瞬间阻塞了实例。CLIENT LIST里直接写着cmdkeys那一刻你就知道是谁的锅。再比如连接数耗尽的问题。Redis默认maxclients是10000到了临界值后新连接报“max number of clients reached”。这时候你光看连接总数没用还得知道哪些IP占得最多、哪个应用没关连接、哪个连接池没设置合理size。CLIENT LIST把每个连接的地址都列出来了按IP聚合一下就能定位源头。还有一类场景是分析空闲连接。很多客户端库如果没配keepalive或空闲超时连接会一直挂着看似无害但它们在连接数计算和内存占用上都会消耗资源。CLIENT LIST里的idle字段能告诉你每条连接空置了多久方便你设计合理的超时策略。1.2 对应到实际运维的工作流我一般排查Redis相关故障会按这个顺序做先看info clients拿整体连接数和阻塞连接数。然后CLIENT LIST | grep flag重点看Sslave和Mmaster之外的用户连接。再按addr和cmd字段做简单聚合找出异常源头。最后配合CLIENT KILL或CLIENT PAUSE做临时止血。这套流程的核心就是CLIENT LIST。因为info只告诉你“有多少”而CLIENT LIST告诉你“都是谁、在干嘛”。生产环境下的Redis排障缺了这层信息基本就是盲猜。2. 命令输出字段逐项拆解把每列都看明白CLIENT LIST的输出是一行一个客户端字段用空格分隔常见的有几十个。很多人只看前几个字段就完事了其实后面那些才是定位问题的关键。2.1 基础字段id、addr、laddr、name、age、idle、flags、db先说id和addr。id是连接的唯一编号单调递增NewRelic那类APM工具里经常会引用它。addr是客户端IP和端口比如127.0.0.1:53412。注意这个端口是客户端的临时端口不是Redis端口。laddr是当前连接在本机上的地址和端口也就是客户端连到了Redis的哪个IP端口上。在多网卡或端口复用场景下laddr还挺重要。name是客户端连接名默认空。CLIENT SETNAME命令可以给连接起个名字像“order-service-pool-01”。如果你用了客户端连接池且没有显式setname排查时就只能靠IP猜弱爆了。age是连接已存在的秒数idle是空闲秒数。这两个放一起就能看出连接池是否长连接复用得比较好如果age很大但idle很小说明连接很活跃如果idle接近age说明这条连接建了但一直没用明显是池子配置问题。flags字段类型比较多常见的有N普通客户端连接S从库连接M主库连接O被monitor命令监视的连接x处于Multi/Exec事务中b被阻塞的命令比如BLPOP、WAITd脏连接等待被关闭u连接未认证A连接关闭中P连接在Pub/Sub模式我每次都会优先看有没有b和d。有b说明存在阻塞命令可能是业务侧执行了BLPOP且没有数据或WAIT等主从同步有d说明系统检测到连接异常可能TCP层面已经断了但应用还没感知。2.2 缓冲区与内存字段qbuf、qbuf-free、obl、oll、omem这几个字段是最容易被忽略但往往是最致命的。Redis为每个客户端维护了输入缓冲区和输出缓冲区一旦业务没做好限流或者命令返回结果过大缓冲区就会疯长。qbuf是输入缓冲区已用字节数qbuf-free是剩余字节数。默认输入缓冲区上限是1GB超过后Redis会直接关闭连接。正常情况下qbuf很小几十字节到几百字节。如果你看到qbuf很大比如几百KB甚至几MB说明有客户端在源源不断发命令但Redis处理不过来或者客户端在发一个超大命令比如批量插入一条几十MB的数据。obl是输出缓冲区中固定缓冲区已用字节数oll是输出缓冲区中链表缓冲区已用字节数omem是这条连接输出缓冲区占用的总内存字节数。omem是重点它包含固定缓冲和链表缓冲以及协议转换临时内存的总和。正常情况下omem一般只有几千字节。如果某条连接的omem达到几MB甚至几十MB那就是典型的“慢消费”问题Redis处理命令很快把结果一股脑写到了输出缓冲区但客户端读取太慢导致数据堆在服务端内存里。这类问题通常出现在做KEYS *、SMEMBERS大集合、LRANGE大列表、或发布订阅大量消息时。如果这种情况持续Redis的used_memory会被撑高极端情况下直接OOM。我在实际排障中看到过一条连接的omem达到200多MB那基本就是有人在用客户端工具直接执行了返回几十万条数据的命令而工具界面还在慢慢渲染。2.3 命令与转发字段cmd、argv、redir、usercmd字段表示这个连接当前正在执行的命令如果空闲则为NULL或上次执行命令的名称。注意它不代表历史上执行过什么只代表“此刻”在跑什么。如果你想排查慢查询CLIENT LIST里看到的cmd不一定准因为命令可能执行完了但如果是阻塞类命令它就会一直显示在那里。argv是当前命令的最近几个参数长度有限制Redis版本不同显示长度也不同。如果是GET foo会显示类似[GET,foo]。这个字段很敏感如果命令参数带有敏感数据在CLIENT LIST里也会显示需要注意安全审计。不过正常情况下你不容易看到太长参数因为Redis只保留了有限长度。redir字段只在客户端处于Monitor模式时才有意义表示重定向目标客户端ID。一般我们不用太关注但如果你看到常规连接带了这个字段说明它被monitor订阅了需要检查是谁在开着monitor因为monitor对性能影响很大。user字段是Redis 6.0 ACL功能开启后才有的显示连接认证的用户名。默认是default。如果你用了多用户权限隔离可以通过它快速定位谁在用哪个账号接入排查权限问题时很好用。3. 常用变体与参数组合不只是裸跑一条命令3.1 CLIENT LIST的ID和TYPE过滤很多人只会直接敲CLIENT LIST然后从一大坨输出里grep。其实Redis从4.0开始支持CLIENT LIST ID id1 id2这种写法可以只返回指定ID的连接配合刚才提到的redir字段和monitor场景很好用。比如你在日志里看到某个慢命令对应的客户端ID就可以这样精确查。从Redis 5.0开始增加了CLIENT LIST TYPE normal|master|replica|pubsub可以按连接类型过滤。我最常用的就是TYPE normal把主从复制的连接过滤掉只看业务连接输出瞬间干净很多。注意老版本里replica写作slave如果脚本要兼容老版本得留意这个差异。3.2 与CLIENT INFO、CLIENT GETNAME/SETNAME配套使用CLIENT INFO是Redis 6.2引入的只返回当前连接自身的信息格式和CLIENT LIST的一行一样。适合在客户端脚本里诊断自己这个连接的状态。比如你写了一个脚本想在Redis里跑点东西又不想查整个列表可以用CLIENT INFO判断当前连接的db、flags、name等。CLIENT SETNAME和CLIENT GETNAME跟CLIENT LIST配合是绝配。强烈建议所有应用在初始化连接池之后执行一下CLIENT SETNAME把连接名设置为“服务名-实例名-用途”。这样后续看CLIENT LIST就能直接认出哪类连接对应哪个服务不用再拿IP找开发确认。我在某公司做过一个规范强制要求所有Redis客户端在连接时设置name排障效率提高了一个级别。3.3 实战组合CLIENT KILL、CLIENT UNBLOCK、CLIENT PAUSECLIENT KILL可以对异常连接做精确清理。老语法是CLIENT KILL addr:port新语法支持CLIENT KILL ID id或者带过滤条件CLIENT KILL TYPE normal、CLIENT KILL ADDR ip:port、CLIENT KILL LADDR ip:port、CLIENT KILL USER username、CLIENT KILL MAXAGE age。很多人在清理时直接用IP kill但同一个IP可能有多个连接精准杀的时候用ID更安全。CLIENT UNBLOCK是给阻塞中连接用的。如果某个客户端执行了BLPOP且一直没等到数据你可以执行CLIENT UNBLOCK TIMEOUT|ERROR让那条连接恢复。注意这个命令并不会中断事务只是解除阻塞。生产上比如发布时想快速让阻塞命令退出就可以用这个。CLIENT PAUSE则是对所有连接做暂停常用于主从切换或维护窗口。CLIENT PAUSE 10000 WRITE表示10秒内暂停所有写命令但读命令不受影响。注意它不影响主从复制的内部连接。这个命令配合CLIENT LIST能帮你做“优雅摘流”。4. 真实排障案例与脚本化解析一条命令定位问题4.1 用awk快速聚合IP和连接数裸看CLIENT LIST输出是很难受的几百行的不好扫。我一般现场就直接套awkredis-cli -a yourpassword client list | awk {print $2} | awk -F: {print $1} | sort | uniq -c | sort -rn | head -20$2是addr127.0.0.1:12345这样的字段再按冒号切出IP统计每个IP的连接数。如果某个IP连接数几千基本可以确定是那个应用或那台机器连接泄漏或连接池设置过大。这时候不需要马上kill先用CLIENT LIST的名字字段确认一下连接名。另外统计空闲连接也很简单redis-cli client list | awk -Fidle {split($2,a, ); if(a[1]300) print $0} | head -30把空闲超过300秒的连接列出来看是不是有客户端没做空闲回收。我曾经在某个Java应用里发现连接池的minIdle设得很大结果压测结束后几百条连接一直挂着idle字段全部超过上千秒。调小minIdle之后内存占用直接降下来。4.2 利用flags和omem定位阻塞与缓冲区问题排查P99延迟高的那次我是这么做的先执行CLIENT LIST | grep -E flags.*b|flags.*d看看有没有阻塞或脏连接。果然发现一条目标连接flagsbcmdkeysaddr对应某运维工具的IP。直接联系那边确认原来在用客户端工具浏览key不小心点了全局匹配。CLIENT KILL ID 之后延迟立刻恢复。再看omem异常的场景。某次某业务的Redis内存使用率飙到80%查内存却找不到大key。后来执行CLIENT LIST我按omem从大到小排序redis-cli client list | awk -Fomem {print $2, $0} | sort -rn | head -20发现一条连接omem85673421上下文cmdsmembers果然后台任务在拉取一个大集合的全量成员客户端消费又慢导致Redis端堆积了85MB输出缓冲。这个案例再次验证used_memory过高不一定是key大也可能是客户端输出缓冲区大。4.3 与monitor和latency配合的一整套排查CLIENT LIST并不是孤立使用的。我的习惯是如果看cmd有大量get/set的简单命令但延迟高就开latency monitor或者用redis-cli --latency看实例级延迟。如果看cmd有慢命令比如keys、hgetall、smembers、lrange这类直接定位到对应连接。如果连接数很多但没人执行命令那多半是连接池问题用CLIENT LIST的idle和name辅助判断。如果连接全部正常再去看网络层面比如网卡丢包、TCP重传。有一次某业务反馈Redis偶尔超时CLIENT LIST里没看到阻塞连接omem也正常。后来用tcpdump看发现是客户端所在宿主机网络抖动跟Redis无关。不装CLIENT LIST这步你都不敢这么笃定地和网络团队说“问题不在Redis”。5. 使用CLIENT LIST的注意事项与避坑心得5.1 版本差异与字段变化CLIENT LIST的输出结构在不同Redis版本里是有变化的。比如Redis 2.8时代只有二十几个字段到Redis 6.2增加了laddr、redir、user、tot-net-in、tot-net-out等。你的脚本如果直接用固定字段位置版本升级就可能错乱。我的建议是不要按位置解析字段而是按“字段名值”的方式解析。因为顺序不保证稳定但有的结构一直稳定。用awk split成kv再取值这样跨版本更安全。另外需要注意的是Redis 5.0之前TYPE replica写的是TYPE slave如果要在老实例上用脚本过滤需要注意这个词。我吃过这个亏线上脚本在4.x实例上执行TYPE replica没报错但返回了全部连接因为老版本不认识replica就直接忽略了过滤条件。5.2 对性能的影响与频率控制CLIENT LIST命令本身是O(N)的N是连接数。如果连接数上万执行一次CLIENT LIST的耗时会在几毫秒到几十毫秒。虽然比KEYS快多了但频率过高会给Redis增加额外CPU开销也会影响主线程。我建议不要把CLIENT LIST放在每秒执行的监控脚本里。合理的做法是常规监控用info clients的connected_clients和blocked_clients就行当出现告警时再手动或低频任务去拉CLIENT LIST分析。如果确实要实时监控客户端连接状态可以用Redis 6.2里的CLIENT NO-EVICT和相应INFO字段或者借助外部指标而不是频繁调CLIENT LIST。5.3 高版本命令的安全与ACL权限Redis 6.0之后CLIENT类命令受ACL控制。如果你给应用账号只授权了读写权限没授权client管理权限CLIENT LIST会报NOPERM。所以有些自动化脚本升级到Redis 6后突然失效先检查ACL。另外CLIENT LIST输出中包含命令参数(argv字段)如果存储了敏感信息需要小心日志泄露。我记得某金融项目里审计要求禁止在日志中记录CLIENT LIST原始输出就是因为argv可能带有密码或者身份证号。处理方式是用脚本摘掉argv字段再落日志。在生产环境执行CLIENT KILL、CLIENT PAUSE这类操作前一定先确认作用范围。特别是CLIENT PAUSE会影响所有客户端最好在低峰期或者带上WRITE参数只暂停写命令。CLIENT KILL用ID比用IP安全因为IP粒度太粗可能误杀同一台机器的其他应用连接。5.4 从实战中总结的几条检查清单最后分享一个我每次处理Redis连接类问题都会对照的清单先看连接总数是否接近maxclients。CLIENT LIST里flagsd的脏连接多不多多就检查TCP keepalive。flagsb的阻塞连接对应什么命令确认是否符合预期。omem超过10MB的连接结合cmd确认是不是有批量拉取大key。qbuf特别大的连接关注是否客户端在批量发送命令。idle很大的连接核对连接池空闲回收策略。name是否规范不规范的让对应应用补上连接名。主从复制的连接也用TYPE replica过滤后看看如果是主实例确认slave连接是否都正常。这套清单帮我处理过至少几十个线上案例。CLIENT LIST最厉害的地方在于它把“连接”这个黑盒透明化了。你不需要猜客户端是怎么连的直接看实例输出就行。如果你还没把CLIENT LIST纳入自己的Redis排障工具箱下一次出问题的时候第一件事记得跑一下它。