场景与处置思路
启动服务报 Address already in use,说明目标端口已被占用。处置分两步:先用 ss -tlnp 或 lsof -i 找到占用进程的 PID,再用 ps 与 /proc 下的信息确认它的身份、启动时间、父进程与工作目录,判断是上一次没退干净的残留进程、另一个正常服务,还是配置错误导致的重复启动。决策要谨慎:托管在 systemd 或面板下的服务应通过其管理命令停止,直接 kill 会被自动拉起,问题看起来会反复出现。
基本信息
| 场景 | 服务启动失败,日志报端口已被占用 |
|---|---|
| 目标 | 定位占用进程并选择正确的处置方式 |
| 命令组合 | ss -tlnp、lsof -i、ps、/proc/PID 下的 cwd 与 exe |
| 判断依据 | 进程身份、启动时间、父进程、工作目录、是否由服务管理器托管 |
| 风险提示 | 直接 kill 被托管进程会触发自动重启,问题反复出现 |
典型使用场景
- 新版本启动报端口占用,怀疑旧进程没退干净
- 端口被完全无关的服务占用,需要改端口
- 重复启动造成冲突,需要确认是否有多个实例
- 容器端口映射占用宿主机端口
- 清理失控的测试进程
定位与决策
定位与决策
ss -tlnp | grep ':8080' # 拿到 pid=
lsof -i :8080 # 交叉验证
ps -p 4321 -o pid,ppid,user,lstart,cmd # 身份与启动时间
readlink /proc/4321/exe; cat /proc/4321/cwd 2>/dev/null
systemctl status <服务> | head # 是否由 systemd 托管
kill 4321 # 优雅停止,kill -9 是最后手段
docker ps --format '{{.Names}} {{.Ports}}' | grep 8080 # 是否为容器映射占用进程的来源判断
| 来源 | 识别线索 | 处置方式 |
|---|---|---|
| 残留的上一次进程 | 启动时间较早,属主与业务账号一致 | 确认后优雅停止并清理相关锁文件 |
| 其他正常服务 | 命令行与工作目录指向别的应用 | 调整端口或迁移服务,不要直接杀 |
| systemd 或面板托管 | systemctl status 能查到对应单元 | 用管理命令停止,避免被自动拉起 |
| 容器端口映射 | 宿主机上没有直接对应的进程 | 用 docker 命令处理容器,而不是杀宿主机进程 |
| 系统组件占用 | 命令行指向内核或系统服务 | 先确认影响范围,不要贸然终止 |
改动前先记录 PID、父进程、启动时间、工作目录与命令行,避免出现「杀掉之后才发现是核心依赖」的情况。
TCP 与 UDP 是两套独立的端口空间。服务使用 UDP 却只查 TCP 会一直找不到占用者,排查时要两边都看。