面试追问地图
| 主问题 | 必讲关键点 | 下一层追问 |
|---|---|---|
| top/vmstat | CPU、load、运行队列、上下文切换 | CPU 空闲但 load 高的原因 |
| free | available、cache、swap | 容器内存和宿主机内存差异 |
| iostat | await、util、队列 | 高 util 是否一定代表磁盘瓶颈 |
| ss/lsof | 监听、连接状态、进程 | CLOSE_WAIT/TIME_WAIT 排查 |
| jstack/jmap/jstat | 线程、堆、GC | 在线导出堆的风险 |
| Arthas | thread、trace、watch | 高开销命令如何控制影响 |
| Docker | 镜像层、容器、namespace/cgroup | 容器退出后数据、镜像优化 |
| JVM 容器化 | Xmx、非堆、RSS、限制 | OOMKilled 与 Java OOM 区别 |
| K8s 探针 | readiness/liveness/startup | 错误探针为何引发重启风暴 |
| 发布策略 | 滚动、蓝绿、金丝雀 | 数据库兼容、自动回滚指标 |
| 可观测性 | 日志、指标、Trace | Trace 采样、敏感信息、告警降噪 |
命令题不仅要说命令名,还要说明关键列、异常特征,以及看到结果后的下一步。
一、Linux 常用排查命令
常用系统资源命令有哪些?
| 命令 | 主要用途 |
|---|---|
top / htop | CPU、内存、负载、进程 |
vmstat | CPU、内存、运行队列、上下文切换 |
free -h | 内存和 Swap |
iostat -x | 磁盘吞吐、延迟和利用率 |
df -h / du -sh | 文件系统和目录占用 |
ss -lntp | 监听端口和 TCP 连接 |
lsof | 文件、端口和进程关联 |
pidstat | 进程或线程级 CPU、IO、上下文切换 |
Linux load average 是什么?
Load Average 表示一段时间内:
- 正在使用 CPU 的任务。
- 等待 CPU 的可运行任务。
- Linux 中不可中断睡眠的任务,常见于 IO 等待。
不能简单认为 load 大于 CPU 核数就一定有问题,还要结合 CPU 利用率、IO wait 和运行队列判断。
Buffers/Cache 占用高是否代表内存不足?
不一定。Linux 会利用空闲内存做文件缓存,并在应用需要时回收。
判断内存是否紧张主要看:
available内存。- Swap 是否持续增长。
- 是否频繁发生 major page fault。
- 是否出现 OOM Killer。
服务端口不通怎么排查?
进程是否启动
↓
端口是否监听、监听在哪个地址
↓
本机 curl/telnet 是否成功
↓
防火墙、安全组、容器端口映射
↓
DNS、路由、负载均衡和上游代理常用命令:
ss -lntp
curl -v http://127.0.0.1:8080/health
nslookup example.com
traceroute example.com二、JVM 诊断工具
jps、jstack、jmap、jstat 分别做什么?
| 工具 | 用途 |
|---|---|
jps | 查看 Java 进程 |
jstack | 导出线程栈,分析死锁和阻塞 |
jmap | 查看堆信息或导出堆快照 |
jstat | 查看 GC、堆各区域和类加载统计 |
jcmd | 向 JVM 发送诊断命令,能力较综合 |
线上使用导出堆等重操作前,要评估停顿时间、磁盘空间和敏感数据风险。
Arthas 常用能力?
dashboard:查看线程、内存和 GC 概况。thread:定位高 CPU 线程和阻塞线程。watch:观察方法入参、返回值和异常。trace:分析方法调用耗时。tt:记录并重放方法调用现场。jad:反编译运行中的类。
诊断工具用于快速建立证据,不应长期在生产环境执行高开销命令。
三、Docker
镜像和容器的区别?
- 镜像:只读模板,包含程序、依赖和运行环境。
- 容器:镜像的运行实例,增加可写层和运行时状态。
镜像应保持可重复构建,容器应尽量无状态,持久数据放在外部存储或卷中。
Dockerfile 如何优化?
- 使用合适且固定版本的基础镜像。
- 使用多阶段构建,减少最终镜像体积。
- 合并相关
RUN,清理包管理缓存。 - 先复制依赖描述文件,充分利用构建缓存。
- 使用非 root 用户运行。
- 不把密钥和环境配置打进镜像。
容器内存与 JVM 堆如何设置?
容器内存不仅包含 Java 堆,还包括:
- 元空间。
- 线程栈。
- 直接内存。
- Code Cache。
- JVM 和 native 库。
因此不能把 -Xmx 设置为容器内存上限,应为非堆和系统开销预留空间,并监控容器 RSS。超限后被 cgroup OOM kill(退出码 137、JVM 无异常日志)的机制与排查见操作系统”page cache 与 OOM killer”一节。
四、Kubernetes
Pod、Deployment、Service 分别是什么?
- Pod:Kubernetes 最小调度单元,包含一个或多个容器。
- Deployment:管理无状态 Pod 的副本、滚动更新和回滚。
- Service:为一组 Pod 提供稳定访问地址和负载均衡。
readiness 和 liveness probe 的区别?
| 探针 | 失败后的含义 | 常见动作 |
|---|---|---|
| readiness | 当前不能接收流量 | 从 Service Endpoints 移除 |
| liveness | 进程可能无法自愈 | 重启容器 |
| startup | 应用仍在启动 | 启动完成前保护其他探针 |
不要把短暂的下游故障直接作为 liveness 失败条件,否则可能引发批量重启。
Kubernetes 中服务发布的基本过程?
- 构建并推送不可变版本镜像。
- 更新 Deployment 镜像版本。
- 创建新 Pod,通过 readiness 后接收流量。
- 逐步下线旧 Pod。
- 观察错误率、延迟和资源指标。
- 异常时暂停或回滚。
五、CI/CD 与发布
Maven 生命周期、依赖冲突、BOM 和可重复构建见 构建与依赖管理;测试分层和质量门禁见 测试与代码质量。
一条典型 CI/CD 流水线包含什么?
代码检查 → 单元测试 → 构建制品 → 安全扫描
→ 部署测试环境 → 集成测试 → 灰度发布 → 全量发布构建产物应具备版本号和可追溯信息,同一制品在不同环境间晋级,不要每个环境重新构建。
蓝绿发布、滚动发布、金丝雀发布的区别?
| 方式 | 特点 | 适用场景 |
|---|---|---|
| 蓝绿发布 | 新旧环境并存,一次切流 | 回滚要求快,但资源成本高 |
| 滚动发布 | 分批替换实例 | 常规无状态服务 |
| 金丝雀发布 | 少量用户或流量先验证 | 高风险变更和核心服务 |
数据库变更如何兼容灰度发布?
遵循扩展再收缩:
- 先新增字段或表,保持旧代码兼容。
- 发布同时兼容新旧结构的代码。
- 完成数据回填和验证。
- 切换读写逻辑。
- 确认无旧版本后再删除旧结构。
不要在同一次发布中直接重命名或删除仍被旧版本使用的字段。
如何设计可回滚的发布?
- 应用版本和配置都可追溯。
- 数据库变更向前向后兼容。
- 消息格式和缓存结构支持版本演进。
- 明确自动回滚指标和人工决策人。
- 发布前验证回滚步骤,而不是故障时临时研究。
六、可观测性
日志、指标、Trace 如何分工?
- 日志:记录离散事件和上下文。
- 指标:反映趋势、容量和异常。
- Trace:展示跨服务调用链和各节点耗时。
关键请求应贯穿统一的 Trace ID,日志避免打印密码、令牌和完整个人信息。
服务至少应该监控哪些指标?
可以按四类整理:
- 流量:QPS、并发数、消息生产速度。
- 错误:错误率、异常类型、消费失败。
- 延迟:平均、P95、P99。
- 饱和度:CPU、内存、线程池、连接池、队列长度。
同时监控业务指标,技术指标正常不代表业务一定正常。
七、Git 版本控制
Git 分支策略
频次 ★★★ · 难度 🟢 · 高频:阿里/字节/腾讯/美团/百度/京东
| 策略 | 分支结构 | 适用场景 | 特点 |
|---|---|---|---|
| Git Flow | master + develop + feature/* + release/* + hotfix/* | 版本化产品发布(客户端 App、大型企业产品) | 流程严谨,但对快速迭代太重 |
| GitHub Flow | 只有 main + 短生命周期 feature 分支,合入 PR | 持续部署的 Web 应用 | 简单灵活,维护分支少 |
| Trunk-Based | 所有人直接在 main 开发 + feature flag 控制功能 | 高频率 CI/CD 团队(Google/Facebook 等) | 分支寿命 < 1 天,需强 CI/CD 和 feature flag 体系 |
面试追问:
- Git Flow 现在过时了吗?→ 对快速迭代的 Web 后端来说确实太重——release 分支冻结期间没人能合入新 feature,降低交付速度。现代团队多用 GitHub Flow(简单)或 Trunk-Based(高频),Git Flow 更适合客户端 SDK/系统软件等有严格发布窗口的项目。
- merge 和 rebase 的区别?→
git merge创建合并提交保留分支拓扑,能看到”谁从谁分支”的历史;git rebase把当前分支的提交在目标分支顶部重放,历史变线性。原则:公共分支用 merge,个人分支用 rebase——已推送到远程的公共分支 rebase 会改写历史,其他人 pull 时冲突。
Git 常用操作
| 操作 | 场景 | 命令 |
|---|---|---|
| 撤回 commit | commit 后发现忘了加文件或注释错了 | git reset --soft HEAD^(保留暂存区改动,只撤回提交) |
| 撤回 push | 推送到远程后发现有问题 | git reset HEAD^ + git push origin xxx --force-with-lease |
| 临时切换 | 正在开发 A,紧急修复 B | git stash 暂存当前改动;git stash pop 恢复 |
| 挑特定提交 | 只把某几个 commit 搬到当前分支 | git cherry-pick <commit-hash> |
| 交互式 rebase | 合并、修改、重排多个 commit | git rebase -i HEAD~3(合并最近 3 个 commit 为 1 个) |
| 查看文件谁改过 | 定位某行代码的最后修改者 | git blame <file> |
| 二分查找 bug | 找到引入 bug 的第一个 commit | git bisect start + git bisect bad + git bisect good |
常见追问:
--force-with-lease和--force的区别?→--force直接覆盖远程分支;--force-with-lease检查远程分支是否被其他人推过新提交(基于你最后一次 fetch 时的 remote ref),更安全。永远不要用裸--force,至少用--force-with-lease。.gitignore生效了但文件还在?→.gitignore只对未跟踪文件生效,已经被 Git 跟踪的文件需要git rm --cached <file>先移除索引再重新提交。