--- id: devops.linux.interview title: Linux 面试题 type: interview domain: devops stack: [linux] tags: [Linux, 命令, 排查, 面试] level: basic related: [devops.linux.commands, devops.linux.troubleshooting] week: [14, 16] --- # Linux 面试题 ## 基础 ### 【基础】怎么查看某个端口被哪个进程占用? **参考答案**:`ss -lntp | grep 8080`(或旧命令 `netstat -lntp`、`lsof -i :8080`),输出里有进程名和 PID。没有 root 权限时可能看不到其他用户进程的信息。 **追问**:`ss` 和 `netstat` 的区别?→ `ss` 更新、更快,直接从内核获取信息;`netstat` 在很多新系统上默认不再安装。 ### 【基础】怎么实时查看日志?怎么查找包含某个关键字的行? **参考答案**:`tail -f app.log` 实时跟踪;`grep -n "ERROR" app.log` 查找并显示行号,`grep -C 5` 显示上下文,`grep -r` 递归目录;systemd 服务用 `journalctl -u 服务名 -f`。 **追问**:日志文件很大,怎么只看某个时间段?→ 用 `sed -n '/开始时间/,/结束时间/p'` 或 `awk` 按时间字段过滤;systemd 服务用 `journalctl --since --until`。 ### 【基础】`kill`、`kill -9`、`kill -15` 有什么区别? **参考答案**:`kill` 默认发送 SIGTERM(15),进程可以捕获它做清理后退出;`kill -9` 发送 SIGKILL,不能被捕获,进程立即被杀死,来不及释放资源。应该先 SIGTERM,等待超时后再 SIGKILL。 **追问**:为什么不建议直接使用 `kill -9`?→ 程序无法清理资源(关闭连接、刷新缓冲、删除临时文件),可能导致数据不完整;先发 SIGTERM,等待超时后再用 -9。 ### 【基础】软链接和硬链接的区别? **参考答案**:硬链接是同一个 inode 的另一个文件名,删除原文件后硬链接仍能访问,不能跨文件系统、不能链接目录;软链接是一个单独的文件,内容是目标路径,原文件删除后软链接失效,可以跨文件系统、可以链接目录。部署中常用软链接切换版本(`current -> releases/v2`)。 **追问**:删除源文件后,软链接和硬链接会怎样?→ 软链接失效(指向的路径不存在);硬链接仍然可以访问数据,因为数据要等到所有硬链接都删除后才释放。 ## 进阶 ### 【进阶】服务器负载很高,你怎么排查? **参考答案**:`uptime` 看 load 和核数对比;`top` 看 CPU 的 `us`(用户态计算)、`sy`(内核态)、`wa`(IO 等待);`wa` 高查磁盘(`iostat -x`、`iotop`),`us` 高找占用最高的进程和线程(`top -H -p`),再用语言工具(Go pprof、py-spy)定位到函数;同时看内存是否在用 swap。 **追问**:负载高但 CPU 使用率低是什么情况?→ 负载包含等待 I/O(D 状态)的进程,可能是磁盘 I/O 瓶颈或 NFS 等存储问题,用 `iostat`、`vmstat` 查看 `wa`。 ### 【进阶】TIME_WAIT 和 CLOSE_WAIT 过多分别说明什么? **参考答案**:TIME_WAIT 出现在主动关闭连接的一方,大量出现通常是频繁创建短连接,应该复用连接(keep-alive、连接池)。CLOSE_WAIT 表示对方已关闭、本方还没关闭,大量出现基本是程序没有关闭连接(例如 Go 没有 `resp.Body.Close()`),属于代码 bug。 **追问**:CLOSE_WAIT 一般是谁的问题?→ 通常是自己程序的问题:对方已经关闭连接,自己没有调用 close(例如 HTTP 响应体没有关闭)。 ### 【进阶】磁盘满了怎么处理? **参考答案**:`df -h` 确认哪个分区满,`df -i` 检查 inode 是否用尽(大量小文件);`du -sh /* | sort -h` 逐层找大目录;常见是日志、临时文件、Docker 镜像和容器日志。删除正在被进程写的文件不会释放空间,用 `lsof +L1` 查找,清空文件内容或重启进程。长期方案:logrotate、Docker 日志大小限制、磁盘使用率告警。 **追问**:删除了大文件但磁盘空间没有释放,为什么?→ 文件还被进程打开着,用 `lsof +L1` 或 `lsof | grep deleted` 找到进程,重启进程或清空文件。 ## 场景题 ### 【场景题】Go 服务内存持续上涨,最后被系统杀掉,怎么定位? **参考答案**:先在内核日志确认是 OOM(`journalctl -k | grep -i oom`);服务开启 pprof,在内存上涨过程中多次采集 heap,对比哪些对象在增长(`go tool pprof -inuse_space`、`-base` 对比);同时看 goroutine 数量是否持续增长(goroutine 泄漏也会占内存)。常见原因:无上限的缓存或 map、goroutine 阻塞泄漏、读取大文件 / 大响应到内存。修复后加内存告警和 `MemoryMax` 限制。 **追问**:怎么确认是被 OOM Killer 杀掉的?→ `dmesg -T | grep -i oom` 或 `journalctl -k` 查看内核日志;容器中看退出码 137 和 OOMKilled 状态。 ### 【场景题】用户反馈接口偶尔很慢,但你登录服务器时一切正常,怎么办? **参考答案**:需要事后可查的数据:Nginx 日志记录 `$request_time` 和 `$upstream_response_time`,用 awk 找出慢请求的时间点和接口;应用日志带请求 ID 和每一步耗时;数据库开慢查询日志;看云监控在对应时间点的 CPU、IO、网络曲线。根据时间点关联定时任务、备份、其他服务的批处理。长期方案是接入指标监控和链路追踪。 **追问**:怎么让偶发问题留下证据?→ 增加带请求 ID 的结构化日志和慢请求日志;监控历史指标(CPU、GC、连接数);在问题出现时自动保存现场(如 pprof 数据)。 ### 【场景题】怎么把一个 Go 程序部署成开机自启、崩溃自动重启的服务? **参考答案**:编写 systemd 单元文件:指定运行用户、工作目录、环境变量文件、`ExecStart`、`Restart=on-failure`、`RestartSec`、停止超时;`systemctl daemon-reload`、`enable --now`;日志用 `journalctl -u` 查看。程序本身要处理 SIGTERM 优雅退出。也可以用 Docker 的 `restart: unless-stopped` 实现类似效果。 **追问**:日志写到哪里?→ systemd 服务输出到标准输出,由 journald 收集,用 `journalctl -u 服务名` 查看;需要长期保存时配置日志轮转或采集到日志平台。