ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Redis连通性测试:从PING到业务读写,完整排查链路

Redis连通性测试:从PING到业务读写,完整排查链路 “连接超时”“NOAUTH”“Redis command timed out”……面试官问到你崩溃的瞬间往往就是因为这道看似简单、人人都能说两句的测试连通性问题。很多人背了三天三夜的数据结构、持久化、分布式锁八股文一上来就咔咔输出。真遇到“你怎么测试 Redis 连通性”当场只会丢一句“用 ping”然后就没了。说实话如果你只答到这一步这道题你顶多拿 3 分。不是说 ping 不对而是“测试连通性”这几个字背后面试官真正想看到的是一个完整的、能落地的排查链路。这篇文章我就把自己带新人和面试别人时对这道题的所有心得一次讲透先讲清楚这题在考什么再一层层解开网络探测、认证鉴权、数据读写、代码超时这些真正的操作细节。准备面试的能直接把这套思路搬进回答里被线上连接坑过的人也能照着这东西把故障定位出来。1. 先搞清楚面试官到底在考什么测试连通性背后的四层心智模型1.1 “PING 返回 PONG” 只是及格线Redis 官方提供了一个 redis-cli里面有个 ping 命令正常情况下会返回 PONG。很多人觉得测试连通性就是跑这一条简单粗暴。但我得泼一盆冷水ping 通只代表 TCP 连接建立成功Redis 进程还在响应命令而已。它说明不了你的网络链路是否稳定说明不了你的密码有没有配对更说明不了高并发下连接池里的连接是否可靠。之前我遇到过一件特别典型的事。运维同事拿着 Redis Desktop Manager 点了下“测试连接”显示正常然后就上线了。结果业务跑起来之后后台疯狂刷 “read timeout” 和 “redis command timed out”。为什么因为可视化工具测试连接通常只做一次最基础的握手而业务侧走的是连接池、是高频读写两者的负载模型完全不同。所以面试里如果你只说 ping 一下面试官心里基本已经给你盖了个“模板化”的戳。对一个有经验的从业者来说“测试连通性”应该是一个分层的心理模型我一般把它拆成四层层一网络能不能通端口能不能通层二Redis 鉴权能否通过是否有权限执行命令层三数据面能不能跑SET/GET 这种真实读写是否正常层四代码环境的超时、连接池、协议版本等配置是否匹配。这四层全部走通才算真正具备“可对外服务”的条件。面试的时候你要做的是把这个模型表达出来而不是背一条 ping 命令。1.2 面试现场常见的三种答法以及分别能拿到的分数我在面试别人的时候很少只听结论我会追问很多边界条件。按照我的经验候选人回答这道题基本分三个档次。第一种只答“用 redis-cli ping”。这是最低档。面试官接着问你那 PONG 没返回怎么办你就傻了。第二种能说出 ping 之外的东西比如 telnet IP 端口、nc 探测端口、redis-cli -u 带密码连接、redis-benchmark 测负载。这说明候选人真实碰过 Redis 环境有登录服务器排查问题的经验能拿到不错的分数。第三种也是最少见的一种能讲出自己的排查顺序先看 netstat 和 telnet 确认网络通不通再看 redis.conf 里 bind 和 protected-mode 的影响然后检查 AUTH 和 ACL 权限接着做 SET/GET 验证最后在代码里聊连接超时、读取超时、连接池耗尽。这种回答给我的感觉是此人不仅会用 Redis而且能独立处理线上事故。第三种答案并不需要你用多么高级的工具本质就是把别人懒得做的细节老老实实说出来。这也是我写这篇文章的初衷让你知道那些“小到不起眼”的排查点才是面试官眼里最有价值的东西。2. 第一层探测网络通没通用最朴素的办法先摸清2.1 三步基础探测telnet、nc、redis-cli 的边界不管你的 Redis 装在 Linux、Windows还是 Docker 容器里只要遇到“连不上”我的建议永远是从最底层开始摸。第一步先确认 IP 和端口通不通不用想复杂工具就是老三样。本机回环地址测试你可以直接执行telnet 127.0.0.1 6379如果黑屏或者显示 Connected to 127.0.0.1说明 TCP 端口是开的。如果提示 Connection refused说明端口没监听或者服务没起来。如果卡住不动多半是防火墙或者安全组规则拦截了。在很多最小化安装的 Linux 环境里没有 telnet这时候用 nc 替代nc -vz 127.0.0.1 6379-v 是显示详细信息-z 表示只扫描端口不发送数据。如果返回 Connected那么网络层就通了。等端口确定没问题再上真正的 Redis 协议级探测也就是 redis-cli。这看起来像是理所当然的事但很多人忽略了一个关键点redis-cli 本身可以设置连接超时。你直接敲 redis-cli ping在某些网络异常下可能卡很久才报错。更严谨的做法是redis-cli -h 127.0.0.1 -p 6379 -t 3000 ping-t 3000 表示连接超时 3000 毫秒超过这个时间直接判定失败。这样你在脚本里就能快速拿到结果而不是看着终端干等。这里我特意强调超时参数因为线上排查最怕的就是“不知道它要卡多久”。2.2 端口通了却连不上 Redis先查绑定地址与 protected-modeTCP 端口通并不代表 redis-cli 能连进去。这是面试里特别容易翻车的一个点。Redis 默认配置文件里 bind 可能被设置成了 127.0.0.1意味着它只监听本机回环地址。这时候你从另一台服务器用内网 IP 去连端口探测看是通的实际上 Redis 根本不理会外部请求。另一个更坑的是 protected-mode。Redis 默认开启保护模式如果没设置密码而且没有显式配置 bindRedis 在收到外部 IP 的连接请求时会直接拒绝只打印一条警告日志。我见过不少人在阿里云、腾讯云上起 Redis安全组放行了 6379结果外部怎么都连不上最后查半天发现就是 protected-mode 在作怪。所以我的排查顺序通常是确认服务监听地址netstat -tlnp | grep 6379或者 ss -tlnp | grep 6379如果发现监听在 127.0.0.1:6379说明配置里 bind 写死了要么改成 0.0.0.0要么把需要访问的 IP 加进去再检查 redis.conf 里 protected-mode 是否为 yes如果改成 no一定要确认你已经设置了密码否则等于裸奔最后检查防火墙和云安全组。这一套下来大部分“端口明明是通的但 Redis 就是连不上”的问题都能解除。面试时提到这个细节会一下子和那些只会 ping 的人拉开距离。3. 第二层探测认证与权限过关才算真正“接入”Redis3.1 AUTH、ACL、连接串三种带凭证的姿势网络层面打通之后下一步就是鉴权。很多人踩过的经典报错是NOAUTH Authentication required.这说明你 TCP 已经连上 Redis 了但没通过密码验证。处理方式取决于你的 Redis 版本。5.x 及以前的版本很简单就一条redis-cli -h 127.0.0.1 -p 6379 -a yourpassword ping或者连上去之后执行 auth yourpassword。但是 -a 这种方式会在进程列表里面暴露密码生产环境不太安全。我一般建议用环境变量export REDISCLI_AUTHyourpassword redis-cli -h 127.0.0.1 -p 6379 ping这样不会直接在命令行里看到明文密码这是 Redis 官方支持的姿势。Redis 6.0 引入了完整的 ACL 体系情况就更细了。用户不再是只有一个密码而是可以由管理员创建多个用户。比如redis-cli -h 127.0.0.1 -p 6379 -u redis://default:password127.0.0.1:6379/0 ping这条命令用 URI 形式来带用户名、密码、库号和连接地址。默认用户叫 default如果你建了专用账号就把 default 换成你的用户名。注意Redis 6 以后可以给不同用户设不同权限有些用户只能读不能写甚至有些用户只能跑指定命令。所以测试连通性时不能只看能不能执行 ping还要看你分配的用户能不能干你接下来想干的事儿。3.2 常见认证报错速查NOAUTH、WRONGPASS、NOPERM我把认证环节最常见的三种报错和应对方式列成一张表这张表在面试里可以直接讲出来报错信息含义排查方向NOAUTH Authentication required未认证执行 auth 或连接串里补充密码WRONGPASS invalid username-password pair用户名或密码错误检查 ACL 用户、密码拼接格式注意特殊字符转义NOPERM this user has no permissions用户无权限执行该命令检查 ACL 规则确认用户是否在 allowed commands 里最常见的组合坑是密码里带特殊字符比如 、#、冒号在 URI 连接串里容易被解析错。之前有人把密码设成 “pass123”然后用 -u 连接一直提示 WRONGPASS后来才发现 符号让 Redis 误以为后面是端口号。这种问题其实特别蠢但踩的人特别多。另外一个面试加分点是如果 Redis 配置了 requirepass但没有配 ACL那你直接 auth 密码即可如果启用了 ACL就必须以 “用户名 密码” 的形式 auth。这条逻辑说起来简单线上有人项目里 Redis 从 5.x 升到 6.x旧代码里只传密码不传用户名直接失联。你在面试时提到这个升级场景面试官基本就知道你是有真实运维经验的。4. 第三层探测从 PONG 到业务读写连通性不能只看“握手成功”4.1 数据面验证SET/GET 与集群环境下的重定向很多人做完 ping 就觉得万事大吉但我始终认为测试连通性至少要包含一次真实的数据读写。原因很简单连接可用不等于读写可用。你连上了 Redis也可能因为内存满了、持久化阻塞、集群重定向等种种原因导致业务命令无法正常执行。我常做的数据面测试是三连redis-cli -h 127.0.0.1 -p 6379 set conn_test_key value_test redis-cli -h 127.0.0.1 -p 6379 get conn_test_key redis-cli -h 127.0.0.1 -p 6379 del conn_test_key先写一个临时 key再读出来最后删掉。这三条命令能跑通说明这个 Redis 节点至少能正常处理数据操作。如果 set 成功但 get 返回 nil那你要怀疑是否连到了不同节点或者使用了不同库号。集群场景下要更加小心。你在 Redis Cluster 环境里随便找一个节点执行 set如果 key 的哈希槽不在当前节点Redis 会返回 MOVED 错误并告诉你应该去哪个 IP:port 访问。这是正常机制不代表节点故障。专业的做法是使用 redis-cli -c 开启集群模式让客户端自动跟随重定向redis-cli -c -h 127.0.0.1 -p 7001 set cluster_test_key value_test对应的哨兵模式Sentinel下直接测主节点或者从节点也可以但你要知道从节点默认不处理写请求你在从节点上执行 set会收到 READONLY 错误。面试被追问到这里能把这些边界情况说出来整个回答的信息量会完全不同。4.2 代码侧连通性测试Jedis/Lettuce/Python 的超时与连接池配置命令行测完了再谈代码侧。你工作中不可能永远在服务器上敲命令业务代码里对 Redis 的连通性测试通常是拿一个客户端连接池去执行命令。这里最常见的翻车点是命令行能通代码里却超时。因为代码里有连接池配置有连接超时有读取超时还有最小/最大空闲连接数等等。用 Java 举个例子。老牌客户端是 Jedis配置如下JedisPoolConfig config new JedisPoolConfig(); config.setMaxTotal(100); config.setMaxIdle(20); config.setMinIdle(5); config.setMaxWaitMillis(3000); JedisPool pool new JedisPool(config, 127.0.0.1, 6379, 2000, password); try (Jedis jedis pool.getResource()) { String pong jedis.ping(); jedis.set(java_test, ok); System.out.println(jedis.get(java_test)); }这里有个关键参数2000 是连接超时表示建立 TCP 连接最多等 2 秒maxWaitMillis 是连接池获取连接的最大等待时间而 ping 和读写时的超时在 Jedis 里默认走的是 socket 的 soTimeout这个值在 Jedis 构造函数里是第 5 个参数之后通过 socketTimeout 传的如果只传了 4 个参数默认读取超时可能是两秒。这些参数配置不合理就会导致你所谓“连通性测试”没事但是一旦压测或者业务量上来就疯狂抛 “JedisConnectionException”。另外一个常用客户端是 LettuceSpring Boot 2.x 默认集成。很多人遇到过的报错是redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException这条信息非常典型。它不是说 TCP 连不上而是说命令发出去之后在指定时间内没有等到响应。通常由三个原因造成Redis 服务端阻塞比如执行了 keys *或者 AOF 重写占用大量 CPU网络分区或者抖动严重Lettuce 的 commandTimeout 配置过短。在 Spring Boot 配置里你可以通过spring.redis.timeout3s来调整读取超时但真正要从根上解决建议先看服务端慢查询日志和 CPU 情况而不是一味调大超时。我见过有人把超时调到 30 秒还继续报错其实 Redis 早就卡在持久化上了。Python 侧用 redis-py 也很直观import redis r redis.Redis( host127.0.0.1, port6379, passwordpassword, socket_connect_timeout3, socket_timeout3, retry_on_timeoutTrue, ) print(r.ping()) r.set(python_test, ok) print(r.get(python_test))socket_connect_timeout 管连接socket_timeout 管每个命令的读写。retry_on_timeout 打开之后遇到超时会自动重试一次对网络抖动有那么点缓解作用但如果你 Redis 本身就慢重试只会加重压力。面试时能把“连接超时”和“读超时”这两个概念分清楚就已经赢了一半。5. 高频故障复盘连接超时、认证失败、命令阻塞的现场还原5.1 三种典型故障的表现与定位顺序我每次带人排查 Redis 连接问题都会用几个经典案例来启发思路。这里举三个最典型的故障现场每个都源自真实场景场景一业务服务器无法连接 Redis。现象是应用日志里频繁输出 “connect timed out”。我第一步不是看代码而是在业务服务器上 telnet Redis 的端口结果发现不通。接着在 Redis 服务器上看 netstat发现根本没有来自业务服务器 IP 的握手记录。最后一查安全组没放行内网 IP。这种纯网络层问题定位最快但如果你直接去调客户端超时方向就偏了。场景二外部工具连接失败提示 NOAUTH。现象是桌面客户端输入密码后报 NOAUTH。通常原因是版本文档不一致比如你用 Redis 6 的 ACL 模式但工具里只填了密码没填用户名。我处理过一次只需要把用户名 default 填进去就正常的案例。场景三连接正常但高并发下命令超时。现象是监控 Redis CPU 不高但应用里频繁报 RedisCommandTimeoutException。后面查到是某个业务用了 O(N) 命令一次扫描了几百万个 key导致单线程的 Redis 阻塞了几百毫秒其他请求全部排队超时。这种问题在命令行里测连通性根本测不出来必须结合 slowlog 和命令复杂度来分析。我把三类问题的定位顺序整理成一个通用流程确认 TCP 链路telnet 或 nc 探端口确认 Redis 进程状态ps -ef | grep redis观察 INFO 中的 connected_clients、blocked_clients、instantaneous_ops_per_sec确认鉴权是否通过auth 后执行 ping确认数据面是否可用set/get/delete看慢日志和错误日志slowlog get 100查看 server 日志里有没有 timeout 或拒绝连接记录看系统层资源内存、文件描述符数、TCP backlog 队列是否溢出。5.2 现代化“连接工具”为什么也会骗人还有一个特别多人忽略的问题图形化客户端测试连接和真实业务场景的差距。Redis Desktop Manager、Another Redis Desktop Manager、RedisInsight 这些工具点一下测试连接能返回 success 就给用户一个“一切正常”的直觉。但工具的连接测试通常只是客户端发起一个握手不一定做数据读写也不会模拟几百个并发连接。所以我在面试里经常问一个问题“如果桌面管理器显示连接正常但线上业务一直超时你下一步怎么做”这道题就是用来淘汰那些过度依赖图形化工具的人的。我的建议是图形化工具适合开发环境的可视化调试不适合作为线上连通性判定的唯一标准。真正要判断 Redis 有没有问题请直接上命令行至少也要在代码里做一个带超时控制的读写探活。探活本身最好是一个独立的脚本定时执行比如每分钟set health_check_key ok ex 10再用get health_check_key判断响应时间。这种做法之所以有效是因为它模拟了真实的业务命令。Redis 是单线程模型如果一个探活命令能在超时时间内返回至少说明当前没有灾难性的阻塞反之如果连简单读写都超时那就说明 Redis 内部出问题了。用一句大白话说就是别只问它“你还活着吗”要问它“你把活干得动吗”。6. 把这道题答成加分项的面试表达框架6.1 一套完整可复述的答题模板面试和实际排查还不完全一样。实际排查可以慢慢看日志面试则需要你在短时间内给出有条理的表达。我给你们一个可以直接照搬的表达结构这套结构我用下来效果不错第一步表明我分两种情况看待连通性。一种是基础连接一种是业务可用。第二步基础连接通常这样验证。先用 telnet 或者 nc 确认端口再用 redis-cli ping 确认协议层响应如果 Redis 配置了密码我会用 -a 或 REDISCLI_AUTH 先通过认证。整个过程注意连接超时参数一定要设置不能无限等待。第三步业务可用会再往前推一步。我会设置一个临时 key做一次 set/get/delete 的闭环。在集群环境下用 redis-cli -c 启动集群模式避免被 MOVED 误导在只读从节点上不会执行 set而是执行 get 来验证读取链路。第四步如果发现网络通但命令超时我会继续看 Redis 的 INFO、slowlog以及客户端连接池配置。重点排查是否用了慢命令、是否有持久化阻塞、连接池是否被打满。这句话术听起来不复杂但它把“测试连通性”从一个单点命令扩展成了多层排查体系面试官听到的基本就是你处理问题的真实状态。6.2 后续追问与扩展话题一旦你按上面的结构答完面试官大概率会接着往下问。我见过的高频追问包括如果 ping 超时你如何区分是网络问题还是 Redis 负载高Redis 6 的 ACL 和原来的 requirepass 有什么区别什么是连接池耗尽怎么看连接池有没有满Redis 为什么是单线程还这么快怎么监控 Redis 的慢查询其中第一个追问最容易暴露水平。正确的回答是如果在 Redis 本机执行 redis-cli ping 都超时那大概率是 Redis 自身问题比如 CPU 占用过高、持久化卡住、内存 swap 严重如果本机正常但业务服务器远程 ping 超时则优先怀疑防火墙、安全组、网络延迟或带宽。核心思想是“先本机后远程、先内网后外网”把变量逐个排除。聊到这里顺便给个额外提醒测试连通性别只盯着 ping 命令的 PONG。PONG 只是 Redis 告诉你“我听得到你说话”但不等于“我能帮你干活”。所以我会建议在你的监控体系里加入一个带数据读写的探活任务并记录每次操作耗时一旦连续几次超过阈值就告警。这条经验是我自己踩了很多坑才沉淀下来的。以前我也以为连通性就是“通了就行”直到被线上慢请求折磨过几次才明白真正的连通性是命令能稳定地在预期时间内拿到结果。希望这篇文章能帮你把这道送分题真正答成送分题。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进