运维面试 高频10题 · 第五组

etcd / OOM / 数据库备份 / CI深入 / 自动化运维 · Q41–Q50

etcd OOM排查 MySQL备份 Jenkins深入 K8s探针 Redis集群 容器OOM Zabbix LVM 故障演练
已展开 0 / 10 题
Q41
etcd 在 K8s 中的作用是什么?etcd 集群如何保证数据一致性?
K8setcd分布式
+
  • K8s 的唯一数据存储,所有集群状态都在 etcd 里:Node 信息、Pod 定义、ConfigMap、Secret、Service、RBAC 规则等
  • API Server 是唯一直接读写 etcd 的组件,其他组件通过 API Server 间接访问
  • etcd 挂了 = 集群无法创建/修改任何资源(已运行的 Pod 不受影响)
  • etcd 使用 Raft 算法保证强一致性
  • 集群必须有 奇数个节点(3 或 5),超过半数节点存活才能提供服务
  • 写入流程:Client → Leader → Leader 复制日志到多数 Follower → 多数确认 → 提交 → 返回成功
  • 3 节点容忍 1 个挂;5 节点容忍 2 个挂
# 查看 etcd 集群健康状态
ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint health

# 查看集群成员
etcdctl member list

# 备份快照(生产必做)
etcdctl snapshot save /backup/etcd-$(date +%F).db

# 查看快照状态
etcdctl snapshot status /backup/etcd-2025-01-01.db
生产建议:etcd 备份是 K8s 灾难恢复的核心。定时备份 etcd 快照到对象存储,保留最近 7 天。etcd 数据目录挂独立 SSD,避免 IO 竞争影响 Leader 心跳。
Q42
容器 OOMKilled 如何排查?limits 和 requests 怎么合理设置?
K8sOOM资源管理
+
# 第一步:确认是 OOMKilled
kubectl describe pod <pod-name>
# 看 Last State → Reason: OOMKilled
# 看 Exit Code: 137(128 + 9,被 SIGKILL)

# 第二步:看历史日志(容器重启前)
kubectl logs <pod-name> --previous

# 第三步:看内存使用趋势(Grafana / kubectl top)
kubectl top pod <pod-name> --containers

# 第四步:宿主机层面确认
dmesg | grep -i "oom\|killed"
journalctl -k | grep -i oom
  • requests:调度保证值,scheduler 用它决定把 Pod 调到哪个节点(节点可用资源 ≥ requests 才调过去)
  • limits:硬上限,容器内存超过 limit → 立即 OOMKill;CPU 超过 limit → 被限速(不会 Kill)
resources:
  requests:
    memory: "256Mi"   # 正常运行所需,通过监控 P90 用量确定
    cpu: "250m"       # 0.25 核,1000m = 1核
  limits:
    memory: "512Mi"   # requests 的 1.5~2 倍,留弹性空间
    cpu: "500m"       # CPU limit 可以设高,反正只限速不 Kill
  • Guaranteed:requests == limits,OOM 时最后被杀,生产核心服务用这个
  • Burstable:requests < limits,正常,大多数服务
  • BestEffort:没设 requests/limits,OOM 时第一个被杀,禁止生产使用
实战口诀:先跑一周收集 Grafana 内存 P90 数据,以此设 requests;limits 设为 requests 的 2 倍。核心服务设成 Guaranteed,稳定不被驱逐。
Q43
MySQL 数据库备份方案有哪些?如何实现增量备份和时间点恢复?
MySQL备份恢复
+
方式工具优点缺点
逻辑备份mysqldump跨版本兼容,可读大库慢,恢复慢
物理备份xtrabackup快速,支持热备和增量需相同 MySQL 版本
binlog 备份mysqlbinlog实现增量 + 时间点恢复需配合全量使用
#!/bin/bash
# 全量热备,不锁表,生产推荐
DATE=$(date +%F)
BACKUP_DIR="/backup/mysql/$DATE"

xtrabackup --backup \
  --user=backup_user \
  --password=<pwd> \
  --target-dir=$BACKUP_DIR

# prepare 阶段(使备份可用)
xtrabackup --prepare --target-dir=$BACKUP_DIR

# 上传到对象存储
ossutil cp -r $BACKUP_DIR oss://your-bucket/mysql/
# 场景:误删数据,需要恢复到 10:30 之前
# 1. 恢复最近的全量备份
xtrabackup --copy-back --target-dir=/backup/mysql/2025-01-01
chown -R mysql:mysql /var/lib/mysql

# 2. 用 binlog 回放到指定时间点(不包含误操作)
mysqlbinlog \
  --start-datetime="2025-01-01 00:00:00" \
  --stop-datetime="2025-01-01 10:29:59" \
  /var/lib/mysql/mysql-bin.* | mysql -u root -p

# 关键:binlog 必须提前开启
# my.cnf: log_bin = /var/lib/mysql/mysql-bin
面试加分:说出"3-2-1 备份原则"——3 份数据、2 种介质、1 份异地存储。以及定期做恢复演练,没验证过的备份不可信。
Q44
K8s 的三种健康探针是什么?配置不当会导致什么问题?
K8s探针稳定性
+
  • livenessProbe(存活探针):失败 → 杀死容器并重启。用于检测进程死锁、僵死等无法自恢复的状态
  • readinessProbe(就绪探针):失败 → 从 Service Endpoints 摘除(不接收流量),但不重启。用于服务预热、依赖未就绪等
  • startupProbe(启动探针):慢启动应用专用,启动期间 liveness/readiness 暂停检查,防止启动中被误杀
livenessProbe:
  httpGet:
    path: /healthz     # 接口返回 2xx 即存活
    port: 8080
  initialDelaySeconds: 30   # 容器启动后等30秒再开始探测
  periodSeconds: 10         # 每10秒探测一次
  failureThreshold: 3       # 连续失败3次才重启

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 2       # 失败2次就摘流量

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30      # 允许最多 30*10=300秒 启动时间
  periodSeconds: 10
  • initialDelaySeconds 太短:应用还没起来就被 liveness 判定失败 → 无限重启循环(CrashLoopBackOff)
  • liveness 探测接口依赖 DB:DB 抖动 → 大量 Pod 被重启 → 雪崩。liveness 只查进程自身状态,readiness 才查依赖
  • 没有 readiness:Pod 刚启动还没 warm up,流量就打进来 → 大量 502
设计原则:liveness 只检查"进程是否卡死"(轻量);readiness 检查"能否正常处理请求"(含依赖);Java 慢启动必须加 startupProbe。
Q45
Redis Cluster 集群模式原理?和哨兵模式的区别?
Redis集群高可用
+
维度Sentinel 哨兵Cluster 集群
数据分布全量复制,每节点全量数据分片,数据分散在各节点
容量扩展不能水平扩容支持在线扩缩容
故障转移哨兵投票选主集群内部 Gossip 协议
最小节点数1主+1从+3哨兵3主+3从(最少6个)
适用场景数据量不大,需高可用数据量大,需水平扩展
  • 数据按 Hash Slot(哈希槽) 分片,共 16384 个槽,均分给各主节点
  • 写入 key 时:CRC16(key) % 16384 计算归属槽,路由到对应节点
  • 客户端请求错误节点时,收到 MOVED 重定向,客户端再去正确节点请求
# 查看集群状态
redis-cli -c -h 127.0.0.1 -p 7001 cluster info
redis-cli -c cluster nodes   # 查看各节点槽分布

# 模拟客户端(-c 开启自动重定向)
redis-cli -c -h 127.0.0.1 -p 7001
> set foo bar     # 自动 MOVED 到正确节点

# 在线迁移槽(扩容时用)
redis-cli --cluster reshard 127.0.0.1:7001
注意坑:Cluster 不支持多 key 跨槽操作(如 mset 多个 key、lua 脚本跨 key)。解决方案是用 {} 哈希标签强制同槽:key:{user:1}:namekey:{user:1}:age 在同一槽。
Q46
Jenkins 共享库(Shared Library)是什么?如何复用 Pipeline 代码?
JenkinsCI/CD工程化
+

多个项目 Jenkinsfile 有大量重复代码(构建镜像、推 Harbor、kubectl 部署逻辑相同),修改一处要改所有项目。共享库把公共逻辑提取为函数库,各项目直接调用。

# Git 仓库结构(jenkins-shared-library)
├── vars/
│   ├── buildImage.groovy     # 全局函数:构建推送镜像
│   ├── deployK8s.groovy      # 全局函数:部署到 K8s
│   └── notify.groovy         # 全局函数:钉钉通知
└── src/                      # 类库(复杂逻辑)
// vars/buildImage.groovy
def call(String imageName, String tag) {
    sh """
        docker build -t harbor.xx.com/${imageName}:${tag} .
        docker push harbor.xx.com/${imageName}:${tag}
        docker rmi harbor.xx.com/${imageName}:${tag}
    """
}

// vars/deployK8s.groovy
def call(String namespace, String deployment, String image) {
    sh "kubectl set image deployment/${deployment} \
        app=${image} -n ${namespace} --record"
    sh "kubectl rollout status deployment/${deployment} -n ${namespace}"
}
// 引用共享库(在 Jenkins 全局配置里注册 Git 地址)
@Library('jenkins-shared-library') _

pipeline {
    agent any
    stages {
        stage('构建镜像') {
            steps { buildImage('myapp', env.BUILD_NUMBER) }
        }
        stage('部署') {
            steps {
                deployK8s('production', 'myapp',
                  "harbor.xx.com/myapp:${env.BUILD_NUMBER}")
            }
        }
    }
    post { failure { notify('构建失败') } }
}
面试加分:说出"用共享库统一了全公司 CI/CD 规范,新项目接入只需3行调用",体现工程化思维。
Q47
Zabbix 和 Prometheus 的区别?各自适合什么场景?
ZabbixPrometheus监控
+
维度ZabbixPrometheus
架构Push(Agent 主动上报)Pull(主动拉取 exporter)
数据存储MySQL / PostgreSQL本地 TSDB(时序数据库)
查询语言无,GUI 操作为主PromQL,表达力强
K8s 支持差,需额外配置原生支持,ServiceMonitor
告警内置告警,GUI 配置AlertManager,YAML 配置
适合场景传统物理机/VM 监控云原生/K8s/微服务监控
# Zabbix Agent 配置(被监控端)
# /etc/zabbix/zabbix_agentd.conf
Server=192.168.1.100         # Zabbix Server IP
ServerActive=192.168.1.100   # 主动模式
Hostname=web-server-01       # 在 Zabbix UI 里对应的主机名

# 自定义监控项(UserParameter)
UserParameter=nginx.conn,ss -ant | grep ESTABLISHED | wc -l
实际选型:传统架构(物理机 + VM)用 Zabbix,告警配置 GUI 化更适合团队;K8s 云原生环境用 Prometheus + Grafana,和 K8s 生态无缝集成。你的项目两者都有,面试时结合实际场景说明选型理由。
Q48
LVM 逻辑卷是什么?如何在线扩容磁盘?
LinuxLVM存储
+
  • PV(Physical Volume):物理磁盘或分区,最底层
  • VG(Volume Group):多个 PV 组成资源池
  • LV(Logical Volume):从 VG 中分配,格式化后挂载使用
# 场景:/data 目录满了,新增一块磁盘 /dev/sdb 扩容

# 第1步:初始化新磁盘为 PV
pvcreate /dev/sdb
pvdisplay                     # 查看 PV 列表

# 第2步:将 PV 加入 VG(假设 VG 名为 datavg)
vgextend datavg /dev/sdb
vgdisplay datavg              # 确认 VG 空间增加

# 第3步:扩展 LV(+100G 或扩到最大)
lvextend -L +100G /dev/datavg/datalv
# 或扩到 VG 全部剩余空间
lvextend -l +100%FREE /dev/datavg/datalv

# 第4步:在线扩容文件系统(不卸载)
# ext4 文件系统
resize2fs /dev/datavg/datalv
# xfs 文件系统(CentOS 7+ 默认)
xfs_growfs /data

# 验证
df -h /data
关键点:lvextend 只扩了 LV,文件系统还没扩。最后必须执行 resize2fs(ext4)或 xfs_growfs(xfs),两者缺一不可。漏掉这步是最常见的操作失误。
Q49
什么是混沌工程?生产环境如何做故障演练?
稳定性故障演练SRE
+

主动在系统中注入故障(网络延迟、Pod 宕机、磁盘满、CPU 满),验证系统的容错能力和告警响应是否符合预期,在可控条件下暴露隐患,而不是等线上真实故障时才发现。

# 1. 随机删除 Pod(验证 Deployment 自愈能力)
kubectl delete pod -l app=myapp -n production --grace-period=0

# 2. 模拟节点 NotReady(验证 Pod 漂移)
# 在某个 worker 上停止 kubelet
systemctl stop kubelet
# 观察:Pod 是否在 5分钟后漂移到其他节点

# 3. 模拟 OOMKill(验证 limits 和告警)
kubectl exec -it <pod> -- stress --vm 1 --vm-bytes 600M

# 4. 网络注入(用 tc 模拟延迟)
tc qdisc add dev eth0 root netem delay 200ms 50ms
# 恢复
tc qdisc del dev eth0 root

# 5. 使用 Chaos Mesh(K8s 原生混沌工具)
kubectl apply -f - <<EOF
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
  name: pod-kill-test
spec:
  action: pod-kill
  selector:
    namespaces: [staging]        # 只在预发环境测!
    labelSelectors:
      app: myapp
  scheduler:
    cron: "@every 5m"
EOF
演练原则:① 先在测试/预发环境,再到生产低峰期;② 提前通知相关人员;③ 准备回滚方案;④ 记录 MTTR(平均恢复时间),逐步优化。
Q50
运维工程师如何做好变更管理?上线前需要检查哪些内容?
运维规范变更管理综合
+
  • 变更计划:明确变更内容、影响范围、执行步骤、预计时长
  • 回滚方案:每个变更必须有明确的回滚步骤,且能在 5 分钟内完成
  • 验证标准:变更后如何判断成功(接口返回 200、监控无告警、日志无报错)
# === 代码/配置 ===
□ 代码已 Code Review,通过 SonarQube 静态扫描
□ 镜像已构建并在测试环境验证通过
□ ConfigMap / 环境变量变更已确认
□ 数据库变更脚本已准备(DDL 变更需提前评估锁表风险)

# === 资源 ===
□ 节点资源充足(kubectl top nodes,预留 20% 余量)
□ PVC 空间充足(df -h,磁盘使用率 < 80%)
□ 镜像已推送到 Harbor 并扫描无高危漏洞

# === 流量 ===
□ 选低峰时段(凌晨或周末)
□ 分批灰度上线(先 1 个 Pod,观察5分钟再全量)
□ Nginx / Ingress 限流规则已确认

# === 应急 ===
□ 回滚命令已准备(kubectl rollout undo)
□ 告警通道畅通(钉钉/企微 webhook 已测试)
□ 相关人员已通知并在线待命
  • 故障发生后 24 小时内完成 RCA(根因分析)
  • 记录:时间线、根因、影响范围、临时措施、永久修复方案
  • 不追责个人,关注系统性问题,建立长效机制
面试结语:这道题考察软实力。答出"变更必有回滚方案"、"低峰分批上线"、"事后 Post-mortem 不追责",体现成熟的运维工程师思维,和只会敲命令的区别就在这里。