当我们负责的线上应用突然变慢或者报错,而直觉又告诉你“代码明明没问题”的时候,很多人的第一反应就是翻日志、查监控,忙得团团转。但如果你用了 Linkerd,这时候最该做的是先稳住心态,顺着服务网格的“路线图”一步步排查。今天就用大白话加上实际能跑的命令,聊聊怎么快速定位服务异常问题。
一、遇到服务慢或者报错,先别慌
1.1 先看现象,别急着关进程
服务异常一般分两种:一种是“能通但慢”,比如接口要等好几秒;另一种是“根本不通”,比如连接被拒、超时、5xx 满天飞。现象不同,排查的方向也不同。如果你一上来就重启应用,很可能会把现场破坏掉,尤其是链路里复杂的调用关系,重启后就很难复现了。
正确的做法是先记录现象:是哪个接口?哪个客户端?报错内容是什么?延迟大概多少?有没有伴随 CPU 或内存飙高?这些信息能帮你判断问题是在入口、中间链路还是服务本身。
1.2 链路里到底谁在拖后腿
Linkerd 作为服务网格,会在每个 Pod 里自动塞一个轻量级的 sidecar proxy(就是那个叫 linkerd-proxy 的小容器)。所有进出服务的流量都会经过它,所以它就像一条“隐形的高速公路”。当服务出问题时,可能是应用自己的问题,也可能是高速公路堵了。排查的核心就是分清“应用的问题”和“代理/网格的问题”。
一个实用的经验:如果链路里只有某个服务报错,而其它服务都正常,那多半是这个服务自身或者它的 proxy 出问题了;如果所有通过 Linkerd 的服务都异常,那要先看控制平面是不是还健康。
二、Linkerd 的基本排查命令
这里我们用到的技术栈是 Kubernetes 命令行工具 + Linkerd CLI,也就是在 bash 里跑 kubectl 和 linkerd 命令。下面所有命令都可以直接复制到终端里执行。
2.1 看看 Linkerd 自己活着没有
任何排查之前,先确认 Linkerd 系统本身是健康的。linkerd check 这个命令会做一整套体检,包括控制平面组件、数据平面代理、网络策略等等。它输出的内容很直白,有 √ 就是正常,有 × 就是有问题。
# 执行 Linkerd 体检,输出结果会逐项告诉我们哪里有问题
# 这个命令会自动读取当前 kubeconfig 指向的集群,所以要先配好 kubectl
linkerd check
如果检查结果里有红叉,比如 linkerd-destination 这个组件不健康,那后面所有排查都可能跑偏,因为 linkerd-destination 负责告诉代理“流量该往哪里发”。
2.2 看看数据面代理状态
控制面正常后,还需要确认业务 Pod 里的代理是不是真的注入了,并且处于运行状态。怎么快速看呢?用 kubectl get pod 就行了。
# 查看指定命名空间下所有 Pod,注意看 READY 列
# 正常情况下每个 Pod 的 READY 应该是 2/2(应用容器 + linkerd-proxy 容器)
kubectl -n your-namespace get pod
2/2 的意思是两个容器都起来了。如果你看到 1/2,那说明 linkerd-proxy 没有起来,需要进一步查看它的日志或者事件。
# 查看某个具体 Pod 的详细事件,重点看 Events 部分
# 如果容器启动失败,这里通常会给出原因,比如镜像拉取失败或端口冲突
kubectl -n your-namespace describe pod your-pod-name
三、常见的故障类型和定位方法
3.1 服务突然超时
超时是服务网格场景下最常见的异常,可能的原因有:业务处理慢、依赖的下游服务超时、代理线程池耗尽、网络拥塞等。
第一步,用 linkerd stat 观察当前服务的延迟和成功率指标。它会把服务间的流量情况汇总成表格,非常直观。
# 查看某个命名空间下所有 Deployment 的流量指标
# 输出会包含 请求率(RPS)、成功率、P50/P95/P99 延迟等
linkerd -n your-namespace stat deploy
如果 P99 明显升高,但成功率还是 100%,说明有少量请求非常慢。这时候可以用 linkerd top 实时盯着流量,看看是哪个来源、哪个路由在拖时间。
# 实时显示前10条最慢的请求
# 这个命令会持续输出,按 q 退出
linkerd -n your-namespace top --max 10
接下来看应用日志和代理日志。应用日志直接看业务容器,代理日志则要看 -c linkerd-proxy。
# 查看应用容器的最近100行日志
kubectl -n your-namespace logs deploy/your-service --tail=100
# 查看 linkerd-proxy 容器的最近100行日志
# 代理日志会记录每个出站/入站连接的状态,如果看到 connect timeout 之类字眼,就是网络层问题
kubectl -n your-namespace logs deploy/your-service -c linkerd-proxy --tail=100
3.2 连接被拒绝
如果出现 Connection refused 或者 No route to host,说明目标端口没有监听或者 Pod 不存在了。在 Linkerd 体系里,一个常见原因是服务端口没有正确纳入网格,导致代理无法转发。
先用 kubectl get svc 确认 Service 存在,并且它的端口和 Pod 里的实际监听端口对得上。
# 查看服务列表,确认端口映射
kubectl -n your-namespace get svc
然后用 kubectl get endpoints 看有没有可用的后端 Pod。
# 查看某个 Service 的 Endpoints
# 如果 ENDPOINTS 列是空,说明 Service 没有选中任何 Pod,流量自然无路可走
kubectl -n your-namespace get endpoints your-service
还有一种情况是 Pod 存在,但 Linkerd 禁止了访问某些端口。Linkerd 默认会忽略某些管理端口,如果你把业务端口配到了管理端口段里,也会连不上。这时可以看看 Pod 的注入注解,了解一下端口配置。
# 查看 Pod 的注解,其中 linkerd.io/inject: enabled 表示已注入
# 如果有 linkerd.io/port 这类注解,要确认它是否指向了正确的业务端口
kubectl -n your-namespace get pod your-pod-name -o jsonpath='{.metadata.annotations}'
3.3 内存和 CPU 飙高
服务卡顿也可能是资源问题。先用 kubectl top 看看 Pod 和节点的资源占用。
# 查看节点资源使用情况
kubectl top nodes
# 查看命名空间下所有 Pod 的资源使用情况
kubectl -n your-namespace top pod
如果发现某个 Pod 的 linkerd-proxy 容器 CPU 特别高,很可能是网络流量异常,比如有大量重试或者反复握手。这时可以看 linkerd top 里的“请求来源”,如果某个客户端在疯狂重试,那就是它的问题。
如果业务容器 CPU 高,那就进到容器里用常规手段排查,比如看线程堆栈。
# 进入业务容器执行 top 命令,看看是哪个进程或者线程在消耗 CPU
# 注意 -c 后面换成实际容器名,默认如果只有一个容器就不用加
kubectl -n your-namespace exec -it your-pod-name -c your-container-name -- top
四、一个完整的排查案例
下面我们模拟一个实际场景:订单服务 order-service 突然有大量 500 错误,同时调用它的 user-service 也变慢。我们从头到尾走一遍流程。
技术栈还是 Kubernetes CLI + Linkerd CLI,所有命令都在 bash 中执行。
首先确认 Linkerd 是否健康。
# 1. 体检控制面
linkerd check
# 假设输出都正常,继续下一步
然后看看 order-service 的流量指标。
# 2. 查看该服务所有相关 workload 的成功率和 P99
linkerd -n production stat deploy/order-service
# 假设输出了类似:
# NAME MESHED SUCCESS RPS LATENCY_P50 LATENCY_P99
# order-service 1/1 99.50% 12.3rps 5ms 800ms
这里能看到成功率接近 100%,但 P99 高达 800ms,说明有少量请求非常慢。我们再用 linkerd top 看看慢请求来自哪个客户端。
# 3. 实时抓取 top 请求,按延迟排序
linkerd -n production top --max 5
# 输出里可以看到 source 是 user-service,destination 是 order-service
# 有这个信息,我们就知道问题出在 user-service 调用 order-service 的链路上
接着查看两个服务各自的日志。先看 order-service 的应用日志。
# 4. 查看 order-service 应用的最近日志
kubectl -n production logs deploy/order-service --tail=200
# 日志里可能看到很多 "context deadline exceeded" 或者 "database timeout"
再看它调用了什么外部依赖。假设日志里发现慢是因为调用了数据库超时,那可以顺便用 kubectl exec 进入容器测一下数据库连通性。
# 5. 进入 order-service 容器,测试数据库端口是否可达
# socat 可能不存在,这里用 bash 的 /dev/tcp 模拟端口探测
kubectl -n production exec -it deploy/order-service -- bash -c "
timeout 3 bash -c 'echo > /dev/tcp/10.0.0.5/3306' && echo 'db ok' || echo 'db unreachable'
"
# 假设输出 db unreachable,说明数据库网络有问题
既然容器网络能通,为什么还是 timeout?这时候要考虑 Linkerd 是否在转发时出现了问题。查看 linkerd-proxy 日志。
# 6. 查看 order-service 的代理日志,过滤出 error 或者 timeout 关键字
kubectl -n production logs deploy/order-service -c linkerd-proxy --tail=500 | grep -E 'error|timeout|refused' | head -50
# 如果看到 "connection timed out after 10s" 这样的记录,说明代理层确实发生了出站连接超时
# 结合数据库 IP,可以定位到是数据库网络策略或防火墙的问题
最后,我们查看一下命名空间里是否存在网络策略限制了流量。
# 7. 查看 network policy,看是否允许 order-service 访问数据库 IP
kubectl -n production get networkpolicy
# 如果发现默认拒绝策略,需要调整 policy 允许端口 3306 的出站流量
到这里我们就定位到了根因:数据库网络策略把出站流量拦住了,导致 order-service 连接数据库超时。解决方式是修改网络策略,而不是调整业务代码。
五、Linkerd 的优缺点和适用场景
通过上面的例子,大家应该能感受到 Linkerd 的排查思路其实很清晰。它最大的优点就是“无侵入”。你不需要改代码,只要在 Kubernetes 里加上注入注解,Linkerd 会自动帮你做好 mTLS、流量保护和指标采集。因为它用 Rust 写的数据面,内存占用通常比很多同类产品小很多,在小内存的集群里特别友好。
但 Linkerd 也有明显的缺点:它支持的功能相对克制,比如没有复杂的流量镜像或分布式链路追踪(需要额外插件)。它面向的是“连接控制和可观测性”,而不是“API 网关”或者“大规模灰度发布”。所以如果你的场景是极端复杂的流量治理,Linkerd 可能不是最合适的。
适用场景非常清晰:中小型微服务集群,主要是需要 TLS 加密、错误率指标、慢请求追踪,以及不想给应用代码增加负担的团队。这些恰恰是日常排查故障时最需要的东西。
六、注意事项
排查 Linkerd 问题时,有几个容易踩的坑:
第一,不要忽略 linkerd check。很多人一上来就翻日志,但控制面本身如果是坏的,业务侧看到的报错会千奇百怪,浪费大量时间。
第二,要分清楚“应用日志”和“代理日志”。业务日志告诉你业务逻辑有没有异常,代理日志告诉你网络连接有没有异常。两个都要看,但不要混在一起。
第三,注意看 linkerd stat 里的 MESHED 列。如果有些 Pod 没有注入代理,那它就不会被网格管到,流量行为和其它服务会不一样。这时候要先解决注入问题,否则排查方向很容易偏。
第四,不要只盯着 P99。虽然 P99 能暴露慢请求,但有时候偶发错误会稀释到成功率里,看起来只是 0.5% 的失败,实际却影响了所有用户。最好同时看 SUCCESS 和 LATENCY_P99 两个维度。
第五,临时重启应用要慎重。如果是在排查现场,先抓取 linkerd top 或者 kubectl logs 把现场留证再操作,不然问题没了,就什么也追不到了。
第六,注意 Linkerd 默认的最大连接池和超时时间。如果你的服务对延迟特别敏感,可能需要手动调整代理的配置。通过环境变量或服务定义可以改,比如 LINKERD2_PROXY_INBOUND_ACCEPT_KEEPALIVE 这类参数。
七、总结
服务网格并没有让故障消失,但它把故障变成了一条条清晰的“数据流”。排查 Linkerd 问题时,记好这四步:先看控制面,再看指标,然后看日志,最后看网络策略。每一步都有对应的命令,并且都不需要改代码。
实际工作中,大部分服务异常问题都集中在“依赖慢”和“网络不通”这两类。你只要会用 linkerd check 确认系统健康,用 linkerd stat 看延迟和成功率,用 linkerd top 找慢请求源头,再用 kubectl logs 和 kubectl describe 深入到容器和网络层,基本都能快速定位到根因。而且这套思路不只适用于 Linkerd,很多云原生工具也都遵循“先看组件状态,再看业务指标,最后看日志”的排查路径,学会了对其它技术栈也有帮助。
下次再遇到服务异常,别慌,先打开终端跑一条 linkerd check,你会感谢自己留下了如此清晰的诊断路径。
评论
围绕“Linkerd故障排查思路:快速定位服务异常问题”参与讨论