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

Shell / ELK / K8s网络 / Ansible / 故障处理 · 点击展开答案

已展开 0 / 10 题
Q11
Shell 脚本:如何写一个监控磁盘使用率并告警的脚本?
Shell监控
+
#!/bin/bash
# 磁盘使用率超阈值告警脚本
THRESHOLD=80                          # 告警阈值(%)
LOG="/var/log/disk_alert.log"

# df 解析:跳过首行,提取使用率和挂载点
df -h | awk 'NR>1 {print $5, $6}' | while read usage mount; do
    # 去掉百分号,转为数字
    usage_num=${usage%%%}
    if [ "$usage_num" -ge "$THRESHOLD" ]; then
        msg="[$(date '+%F %T')] WARN: $mount 使用率 ${usage} 超过 ${THRESHOLD}%"
        echo "$msg" | tee -a "$LOG"
        # 发钉钉告警(替换 webhook)
        curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
          -H 'Content-Type: application/json' \
          -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$msg\"}}"
    fi
done
# 每10分钟执行一次
*/10 * * * * /bin/bash /opt/scripts/disk_check.sh
面试考点:awk NR>1 跳标题行、${usage%%%} 去百分号、-ge 数值比较。这三个细节要能解释清楚。
Q12
ELK 日志收集流程是怎样的?Filebeat 和 Logstash 的区别?
ELK日志
+
  • 轻量版:Filebeat → Elasticsearch → Kibana(资源少时用)
  • 完整版:Filebeat → Logstash → Elasticsearch → Kibana(需要复杂处理时用)
  • Filebeat:Go 写的,轻量,仅负责采集和转发,内存占用低(<50MB)。部署在每台业务机器上。
  • Logstash:JVM,功能强大,支持 grok 解析、字段处理、多输出路由。但吃内存(512MB+)。
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log   # 采集 Nginx 访问日志
  fields:
    service: nginx                 # 自定义字段,便于 Kibana 过滤

output.elasticsearch:
  hosts: ["http://es01:9200"]
  index: "nginx-logs-%{+yyyy.MM.dd}"  # 按天建索引
实际建议:大多数场景 Filebeat 直接打 ES 就够用。只有需要多行合并、格式转换时才加 Logstash。
Q13
Kubernetes Service 的几种类型和使用场景?ClusterIP 原理是什么?
Kubernetes网络
+
  • ClusterIP(默认):集群内部访问,分配虚拟 IP,适合服务间调用
  • NodePort:宿主机端口映射,范围 30000-32767,适合临时外部测试
  • LoadBalancer:对接云厂商 LB(阿里云 SLB),生产对外暴露服务
  • ExternalName:CNAME 映射外部域名,适合对接外部数据库
  • kube-proxy 在每个节点维护 iptables/IPVS 规则
  • 访问 ClusterIP:Port → iptables DNAT → 随机选一个 Pod IP:Port
  • ClusterIP 本身不是真实网卡,是虚拟地址,只存在于 iptables 规则里
# 查看 Service 对应的 Endpoints(实际 Pod IP)
kubectl get endpoints <svc-name>

# 查看 iptables 转发规则(验证 ClusterIP 原理)
iptables -t nat -L KUBE-SERVICES | grep <clusterIP>
Q14
Ansible 的执行原理是什么?Playbook 幂等性如何保证?
Ansible自动化
+
  • Ansible 控制机通过 SSH 免密连接目标机
  • 将 Python 模块文件临时传输到目标机 /tmp 目录
  • 远程执行模块,收集返回结果,删除临时文件
  • 无需在目标机安装 Agent(只需有 Python)
  • 内置模块天然幂等:copy(MD5 对比不变不传)、yum(已装跳过)、service(已运行不重启)
  • shell/command 不幂等,需用 creates / when 条件控制
# 非幂等写法(每次都执行)
- shell: echo "hello" > /tmp/test.txt

# 幂等写法(文件存在就跳过)
- shell: echo "hello" > /tmp/test.txt
  args:
    creates: /tmp/test.txt   # 文件存在则跳过

# 或用 when 判断
- name: 初始化数据库
  shell: mysql -u root < /tmp/init.sql
  when: not db_initialized.stat.exists
记住:能用 module 就不用 shell/command,module 幂等,shell 不幂等。
Q15
MySQL 慢查询如何排查和优化?EXPLAIN 怎么看?
MySQL性能
+
# my.cnf 配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2          # 超过2秒记录

# 实时分析(找出最慢的SQL)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
  • type:访问类型,性能从差到好:ALL(全表)→ index → range → ref → eq_ref → const。有 ALL 就要优化
  • key:实际用到的索引,NULL 说明没走索引
  • rows:预估扫描行数,越小越好
  • Extra:出现 Using filesortUsing temporary 要警惕
-- 查看执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 1;

-- type=ALL 且无索引 → 创建联合索引
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
优化口诀:看 type 是否 ALL,看 key 是否 NULL,看 Extra 有无 filesort。三步定位,然后加索引。
Q16
Redis 持久化 RDB 和 AOF 的区别,生产如何选择?
Redis持久化
+
  • RDB(快照):定时 fork 子进程将内存全量写入二进制文件。文件小、恢复快,但可能丢失最后一次快照后的数据。
  • AOF(追加日志):记录每条写命令,重启时重放。数据更完整(最多丢1秒),但文件大、恢复慢。
# redis.conf
# RDB:900秒内有1次写则触发快照
save 900 1
save 300 10
save 60 10000

# AOF:每秒刷盘(推荐,兼顾性能和安全)
appendonly yes
appendfsync everysec    # no=最快丢数据多 | always=最安全但慢
  • 缓存场景(允许丢数据):只开 RDB,或都不开
  • 数据不能丢(如 Session、计数):开 AOF,everysec
  • 最高安全:RDB + AOF 混合持久化(Redis 4.0+,重启用 RDB 快速加载,AOF 补全增量)
Q17
Kubernetes 滚动更新和回滚的原理?如何控制更新节奏?
Kubernetes部署
+

Deployment 维护两个 ReplicaSet(旧版本 RS 缩减,新版本 RS 扩增),交替进行,保证服务不中断。

# deployment.yaml
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1    # 最多允许1个Pod不可用(保证服务)
      maxSurge: 1          # 最多允许超出期望副本数1个(加速更新)
# 触发滚动更新(改镜像)
kubectl set image deployment/myapp app=harbor.xx.com/app:v2

# 查看更新进度
kubectl rollout status deployment/myapp

# 查看历史版本
kubectl rollout history deployment/myapp

# 回滚到上一版本
kubectl rollout undo deployment/myapp

# 回滚到指定版本
kubectl rollout undo deployment/myapp --to-revision=2
注意:回滚本质是把旧 ReplicaSet 重新扩容,不是重新部署。所以回滚速度很快。
Q18
Nginx 负载均衡的几种算法?如何做会话保持?
Nginx负载均衡
+
  • round-robin(默认):轮询,适合后端性能相近
  • weight:加权轮询,性能强的机器配更高权重
  • least_conn:最少连接数,适合长连接场景
  • ip_hash:同一 IP 固定打到同一后端(会话保持方式之一)
  • hash $request_uri:按 URI 哈希,适合缓存服务
upstream backend {
    # ip_hash;                   # 开启 IP 会话保持
    least_conn;                  # 最少连接算法
    server 192.168.1.10:8080 weight=3;  # 权重3
    server 192.168.1.11:8080 weight=1;
    server 192.168.1.12:8080 backup;    # 备用节点
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  • ip_hash:简单但 NAT 场景失效(多人共享同一公网IP)
  • Session 共享(推荐):Session 存 Redis,所有后端共享,不依赖 Nginx 策略
Q19
线上某服务突然无法访问,你的完整排查思路?
故障排查综合
+
# 第一层:网络是否可达
ping <服务IP>               # 基础连通性
traceroute <服务IP>         # 路由追踪
curl -Iv http://<服务IP>:<port>  # 端口层测试

# 第二层:端口是否监听
ss -tlnp | grep <port>      # 服务是否在监听
telnet <IP> <port>          # 端口通不通

# 第三层:进程是否存活
systemctl status <service>
ps aux | grep <process>

# 第四层:看服务日志
journalctl -u <service> --since "10 min ago"
tail -f /var/log/nginx/error.log

# 第五层:资源是否耗尽
free -h          # 内存
df -h            # 磁盘(日志写满也会导致服务挂)
ulimit -n        # 文件描述符是否耗尽
kubectl get pod -n <ns>                  # Pod 是否 Running
kubectl logs <pod> --previous           # 上次崩溃的日志
kubectl describe svc <svc>             # Service Endpoints 是否有 IP
面试答法:按"网络→端口→进程→日志→资源"五层答,体现系统性思维。最后说"同时通知相关人员,同步处理进度"体现协作意识。
Q20
Linux 文件系统 inode 是什么?inode 耗尽如何解决?
Linux文件系统
+

inode(索引节点)存储文件的元数据:权限、所有者、大小、时间戳、数据块指针。文件名不在 inode 里,文件名存在目录项里,目录项指向 inode 编号。

# 磁盘空间还有,但无法创建新文件
df -h         # 显示磁盘有剩余
df -i         # inode 使用率 100% ← 根因

# 查看哪个目录 inode 最多
for dir in /var /tmp /home; do
  echo "$dir: $(find $dir | wc -l)"
done
  • 原因1:大量小文件(如 PHP session 文件堆积、日志碎片)
  • 原因2:某个目录疯狂生成临时文件
# 找出文件数最多的目录
find / -xdev -type f | cut -d/ -f2 | sort | uniq -c | sort -rn | head

# 批量删除(谨慎确认路径后执行)
find /var/lib/php/sessions/ -type f -mtime +7 -delete

# 根本解法:调整 mkfs 时的 inode 密度(只能重新格式化)
mkfs.ext4 -T largefile /dev/sdX   # 适合大文件场景,inode 更少但文件更大
记住:df -h 看空间,df -i 看 inode。磁盘没满但写不进文件,先查 inode。