深色模式
端口冲突排查
摘要:服务起不来报
Address already in use时,关键是先确认"是谁占了、占的是哪个协议族、哪个地址"。本文给出ss、lsof、fuser三种定位方式,并说明 IPv6 通配与容器映射这两类容易漏掉的情况。
适用环境
bash
ip -V
ss -V
which lsof fuser netstat
docker --version 2>/dev/null; kubectl version --client 2>/dev/null1
2
3
4
2
3
4
排障步骤
第 1 步:用 ss 精确过滤端口(推荐)
bash
ss -lntp 'sport = :8080'
ss -lntup 'sport = :8080' # 同时看 TCP/UDP1
2
2
输出的 Process 列直接给出 PID 与进程名,这是最快的方式。
第 2 步:用 lsof / fuser 交叉确认
bash
lsof -nP -iTCP:8080 -sTCP:LISTEN
fuser -v 8080/tcp1
2
2
不要盲目 kill 占用进程
先确认该进程是否为正在提供服务的实例。生产环境误杀会导致业务中断,应先摘流再操作。
第 3 步:检查 IPv4 与 IPv6 是否分别被占
bash
ss -lntp -4 'sport = :8080'
ss -lntp -6 'sport = :8080'1
2
2
[::]:8080 会同时抢占 IPv4
监听 IPv6 通配地址(::)时,Linux 默认同时接受 IPv4 映射连接(v6only=0)。此时再启动一个监听 0.0.0.0:8080 的进程会冲突,即使 ss -4 看起来没人占用。
第 4 步:确认是否绑定了具体 IP 而非通配
bash
ss -lntp | grep 80801
进程绑定 192.168.1.10:8080,而新服务要绑 0.0.0.0:8080,同样会冲突。反之亦然。
第 5 步:容器与端口映射冲突
bash
docker ps --format '{{.Names}}\t{{.Ports}}' | grep 8080
ss -lntp 'sport = :8080' # 宿主机上看到的是 docker-proxy 或进程自身1
2
2
容器场景下,冲突可能发生在:宿主机端口被占、hostNetwork 容器直接占用、多个容器映射到同一宿主机端口。
第 6 步:判断是 TIME_WAIT 还是真占用
bash
ss -ant 'sport = :8080' | head -20
ss -ant state time-wait 'sport = :8080' | wc -l1
2
2
服务端重启时,处于 TIME_WAIT 的旧连接一般不阻止重新 bind(内核有 SO_REUSEADDR 保护),若仍失败需检查应用是否未设置 SO_REUSEADDR。
验证
bash
ss -lntp 'sport = :8080'
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/1
2
2
常见坑
netstat 输出不含进程时需加 sudo
netstat -lntp 看不到进程名常是权限不足,ss -lntp 同理,用 sudo 重试。
SO_REUSEPORT 允许多进程同端口
若应用启用了 SO_REUSEPORT,多个进程监听同一端口是正常设计,ss 会列出多行,不要误判为冲突。
短连接压测后 bind 失败
大量 TIME_WAIT 占用临时端口导致无法建立新连接,应查 ip_local_port_range 而不是监听端口。
直接改服务端口绕过冲突
随意改端口会导致依赖方配置、健康检查、监控全部失配。应确认冲突方后决定谁让路。