运维工程师面试题精选:中间件(Nginx / Redis / 消息队列)

中间件是运维面试最容易拉开差距的一块:配置谁都会抄,但 502 与 504 怎么区分、缓存雪崩怎么防、消息积压先动哪里,答得好不好直接反映候选人有没有真正排过障。本文精选 12 道高频题,覆盖 Nginx、Redis 与消息队列,每题先给结论,再列要点。

本文题目一览

  • Nginx 负载均衡策略有哪些?分别适合什么场景
  • Nginx 返回 502 和 504 有什么区别?怎么排查
  • 动静分离怎么做?静态资源缓存如何配置
  • Nginx 配置 HTTPS 有哪些要点
  • Redis 五种基本数据结构分别适合什么场景
  • RDB 和 AOF 怎么取舍?宕机后如何恢复
  • 缓存穿透、击穿、雪崩有什么区别?怎么解决
  • Redis 主从、哨兵和 Cluster 有什么区别
  • Kafka 怎么保证消息不丢
  • Kafka 重复消费怎么保证幂等
  • RabbitMQ 和 Kafka 怎么选型
  • 消息大量积压时线上如何应急处置

一、Nginx

1. Nginx 的负载均衡策略有哪些?分别适合什么场景?

结论:通过 upstream 定义后端组,默认轮询;其余策略按后端是否同构、是否需要会话保持、后端是否为缓存来选。

  • 轮询与 weight:轮询适合后端同构、无状态;weight 按权重分配,适合机器配置不一致或灰度引流。
  • ip_hash:同一 IP 固定打到同一后端做简易会话保持;缺点是负载易倾斜、后端摘除时哈希重排,能无状态化就别用。
  • least_conn:优先发给连接数最少的后端,适合请求耗时差异大的长连接场景。
  • 一致性哈希:按 URI 等变量哈希(hash $request_uri consistent),后端增减只影响少量请求,典型用于后端是缓存的场景以保住命中率。
  • 补充:开源版只有被动健康检查(max_fails、fail_timeout);后端长连接要配 keepalive 且 proxy_http_version 设为 1.1。
upstream backend {
    least_conn;
    server 10.0.0.11:8080 weight=3 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 weight=2 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

2. Nginx 返回 502 和 504 有什么区别?各自怎么排查?

结论:502 是后端给了无效响应——已经连上但后端异常;504 是等后端超时——规定时间内没等到响应。先看 error.log 一句话就能定性。

  • 502 成因:后端进程挂了或在重启、连接被拒或被重置、响应头过大撑爆 proxy buffer。日志典型字样:connect() failed、connection reset by peer。
  • 504 成因:后端处理太慢(慢 SQL、大计算)、线程池或连接池打满在排队、proxy_read_timeout 设得过短。日志典型字样:upstream timed out。
  • 排查顺序:tail error.log 定性;绕过 Nginx 用 curl 直连后端测耗时;查后端进程、端口与连接数;最后才考虑调超时参数。
  • 提醒:盲目调大超时只会把故障拖得更久,先分清后端是"死了"还是"慢了"。

3. 动静分离怎么做?静态资源缓存如何配置?

结论:用 location 按路径或扩展名分流:静态资源由 Nginx 本地直接出或走 CDN,动态请求才 proxy_pass 到后端,静态侧可单独设长缓存。

  • 静态资源设 expires 长缓存并输出 Cache-Control,文件名带版本号指纹(如 app.a1b2c3.js)解决更新问题。
  • 动态内容默认不缓存;用 proxy_cache 时要避开带 Cookie、带用户态的接口,防止用户间串号。
  • 文本类资源开 gzip 压缩,图片视频不要重复压缩;大文件下载可用 sendfile 优化传输。
location ~* \.(jpg|jpeg|png|gif|css|js|woff2)$ {
    root /data/www/static;
    expires 30d;
    add_header Cache-Control "public";
    access_log off;
}

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=api_cache:100m
                 max_size=10g inactive=60m;
location /api/ {
    proxy_cache api_cache;
    proxy_cache_valid 200 10s;
    proxy_pass http://backend;
}

4. Nginx 上配置 HTTPS 有哪些要点?证书出问题怎么快速定位?

结论:要点是证书链完整、协议套件收敛、私钥安全和到期自动续期;线上证书故障十有八九是链不完整或已过期。

  • 证书链:ssl_certificate 必须配全链(fullchain,含中间证书),只配站点证书时部分客户端会报不信任,这是最高频的坑。
  • 协议与套件:只开 TLS 1.2 与 1.3,禁用 SSLv3、TLS 1.0/1.1 和弱套件;可加 HSTS 强制 HTTPS。
  • 续期与权限:Let's Encrypt 证书仅 90 天,须用 certbot/acme.sh 自动续期并在续期后 reload Nginx,同时对到期时间做告警;私钥权限收紧到 600。
  • 定位:用 openssl s_client 查证书链、有效期与协商结果。
openssl s_client -connect www.example.com:443 -servername www.example.com
# 重点看 Certificate chain 是否完整、Verify return code 是否为 0、NotAfter 是否过期

二、Redis

5. Redis 五种基本数据结构分别适合什么场景?

结论:按访问方式选结构:整体读写用 String/Hash,顺序处理用 List,去重与集合运算用 Set,排序与范围查询用 ZSet。

  • String:对象缓存、计数器(INCR 做限流与阅读数)、分布式锁(SET NX PX)、验证码与会话。
  • Hash:存对象多字段,如用户、商品信息,可单字段更新,比整对象序列化成 String 更省内存。
  • List:简单消息队列(LPUSH 加 BRPOP)、最新动态列表(LPUSH 加 LTRIM 固定长度)。
  • Set:去重、标签、抽奖名单;用 SINTER 求共同关注、共同好友。
  • ZSet:排行榜(按 score 排序)、延时队列(score 存执行时间戳,轮询取到期任务)。底层是跳表加哈希表。

6. RDB 和 AOF 两种持久化怎么取舍?宕机后如何恢复?

结论:RDB 是定时快照,文件小、恢复快但丢数据多;AOF 是操作日志,数据更全但文件大、恢复慢。生产通常两者都开,或用 4.0 后的混合持久化。

  • RDB:bgsave 子进程 fork 导出二进制快照,紧凑、适合做备份与灾备;缺点是两次快照间数据会丢,fork 有内存与写时复制开销。
  • AOF:追加记录写命令,appendfsync 设 everysec 时最多丢 1 秒数据,会定期重写瘦身。
  • 混合持久化:开启 aof-use-rdb-preamble 后,重写文件前半是 RDB 快照、后半是增量 AOF,兼顾速度与完整性,推荐使用。
  • 恢复与运维:重启时优先加载 AOF;要定期把 RDB 拷到异机并监控快照是否成功。即使只当缓存也要开持久化,否则重启缓存全冷、流量直压数据库易引发雪崩。

7. 缓存穿透、击穿、雪崩有什么区别?分别怎么解决?

结论:穿透是查根本不存在的数据;击穿是单个热点 key 过期瞬间被打爆;雪崩是大量 key 同时失效或 Redis 整体不可用。

  • 穿透:请求的数据在缓存和库里都不存在(如拿不存在的 ID 刷接口),次次穿到数据库。对策:布隆过滤器拦截、空结果也缓存并设短过期、入口做校验与限流。
  • 击穿:热点 key 刚过期、大量并发同时重建。对策:重建加互斥锁,只放一个线程查库回填;或逻辑过期,异步重建期间先返回旧值。
  • 雪崩:对策是过期时间加随机抖动、多级缓存(本地加 Redis)、Redis 做高可用、数据库前加熔断与限流降级。
  • 加分项:能主动提监控缓存命中率和数据库 QPS,三种问题在监控上的表现各不相同。

8. Redis 主从、哨兵和 Cluster 三种模式有什么区别?

结论:主从解决数据冗余,哨兵在此之上解决自动故障转移,Cluster 再加分片扩容;数据量不大用哨兵足够,要水平扩展才上 Cluster。

  • 主从:一主多从、异步复制,从节点分担读;主宕机需人工切换,复制延迟下从节点会读到旧数据。
  • 哨兵:哨兵进程组监控主从,主宕机自动选新主并通知客户端,一般 3 个起步;要注意脑裂,可用 min-replicas 类配置缓解。
  • Cluster:16384 个哈希槽分片到多个主节点、每主带从,支持水平扩容;代价是多 key 操作受限(需 hash tag)、运维复杂。
  • 巡检关注:复制延迟、内存碎片率、大 key、慢日志(SLOWLOG),都应纳入告警。
redis-cli INFO replication   # 主从角色与复制偏移量
redis-cli INFO memory        # 内存使用与碎片率
redis-cli --bigkeys          # 扫描大 key,须低峰期执行
redis-cli SLOWLOG GET 10     # 慢日志

三、消息队列

9. Kafka 怎么保证消息不丢?

结论:要同时守住三段:生产端确认、Broker 端副本、消费端提交时机,任何一段图省事都会丢。

  • 生产端:acks 设为 all(等全部同步副本确认),retries 大于 0 并开启幂等生产者(enable.idempotence),防重试造成重复与乱序。
  • Broker 端:副本数(replication.factor)至少 3、min.insync.replicas 至少 2,关闭不干净的 Leader 选举(unclean.leader.election.enable=false),防落后副本当选丢数据。
  • 消费端:关自动提交,先处理业务、成功后再手动提交 offset;处理失败不提交,让消息可被重新消费。
  • 总结:Kafka 是"至少一次"语义,宁可重复也不能丢,重复靠业务幂等兜底(见下题)。

10. Kafka 重复消费不可避免时,怎么保证消费幂等?

结论:重复源于 offset 提交与业务处理不在同一事务(如处理完还没提交就宕机),要在业务侧用幂等设计接住,而不是指望消息队列不重发。

  • 唯一键去重:消息带全局唯一 ID,消费前先查去重表或 Redis,已处理直接跳过。
  • 数据库约束兜底:业务唯一键建唯一索引,重复插入直接冲突失败,把幂等落在存储层最可靠。
  • 状态机与乐观锁:订单只允许合法状态流转,非法流转直接拒绝;更新带版本号,旧消息重复到达时更新行数为 0,自然丢弃。
  • 注意:去重记录的保留时长要大于消息的最大重投时长,并与"处理成功再提交 offset"配合。

11. RabbitMQ 和 Kafka 怎么选型?

结论:按业务形态选:要高吞吐、流式处理和消息回溯选 Kafka;要灵活路由、低延迟的业务消息选 RabbitMQ。

  • 吞吐与定位:Kafka 是分布式日志,顺序写盘加零拷贝,吞吐可达几十万 TPS,定位日志、埋点与流处理;RabbitMQ 基于 AMQP,吞吐在万级,定位传统业务消息。
  • 路由与留存:RabbitMQ 有 Exchange 加绑定键的灵活路由、死信队列等现成语义,但消费确认后即删除;Kafka 只有 Topic 分区,但按时间留存、可按 offset 回溯重消费。
  • 顺序与延迟:Kafka 只保证分区内有序;RabbitMQ 在小流量业务消息上延迟更低、更可控。
  • 答题落点:先分清业务是"数据管道"还是"业务通知",再谈吞吐数字,不要只背参数。

12. 消息队列出现大量积压,线上如何应急处置?

结论:先判断是生产突增还是消费变慢,再止血扩容,最后复盘补容量与告警;切忌一上来就删消息。

  • 判断成因:看生产速率是否突增(活动、重试风暴),再看消费是否变慢(下游变慢、单条耗时上升、报错重试、消费者假死)。
  • 扩消费:增加消费者实例,但 Kafka 并发上限是分区数,消费者再多也没用;不够时先扩分区再扩消费者。
  • 临时止血:可把消费降级为只落库不处理、临时转发到新 Topic 慢慢消化、跳过可丢弃的非核心消息(先评估影响并留记录)。
  • 防毒丸:单条坏消息反复重试会堵住整个分区,要有死信队列与跳过策略。
  • 事后:补齐积压条数与最久等待时长双维度告警,复盘容量与限流。

面试官视角

中间件题主要分辨候选人是"背过八股"还是"真排过障",可从三点判断:

  • 看证据意识:讲 502/504 能说出 error.log 的关键句、讲缓存问题会提命中率与数据库 QPS 的,是有实战经验的信号。
  • 看取舍意识:ip_hash 影响均衡、调大超时掩盖故障、扩消费者受分区数限制——能主动说出方案代价的更成熟。
  • 看可靠性意识:答 Kafka 时能区分生产、存储、消费三段,并给出"至少一次加业务幂等"的,是可托付核心链路的信号。
  • 反之,只罗列名词、结合不了业务场景(如排行榜为何用 ZSet、延时任务为何用 score 存时间戳)的,建议换到其简历上的具体系统继续验证深度。

发表回复

后才能评论