服务器运维面试题库
生成时间:2026-05-24 20:40 | 题目数:10
【面试题】1. Nginx的proxy_pass转发时,URI末尾带不带斜杠有什么区别?生产中踩过坑吗?
【标准答案】区别很大。proxy_pass带URI(含斜杠)时,Nginx会把location匹配的部分替换掉再转发;不带URI时,原样透传整个请求路径给后端。
举例:location /api/ { proxy_pass http://backend/; },请求 /api/user 会变成 /user 转发。如果 proxy_pass http://backend;(末尾没斜杠),则转发 /api/user,路径不变。
生产常见坑:后端接口期望收到 /user,但配置没加斜杠导致后端收到 /api/user,直接404。建议:明确后端期望的路径格式,统一规范,配置完一定用curl验证转发路径是否正确。
【面试题】2. Tomcat的NIO、APR、NIO2三种Connector线程模型怎么选?各适用什么场景?
【标准答案】三种模型核心区别在IO处理方式:
- NIO:基于Java NIO,用少量线程通过Selector管理大量连接,适合一般Web应用,Tomcat 8.5+默认就是NIO,大多数场景够用。
- APR:调用Apache Portable Runtime本地库,用操作系统级别的epoll/sendfile,性能最高,尤其静态资源和SSL场景优势明显,但需要安装APR native库,运维成本高。
- NIO2:基于Java 7的AsynchronousFileChannel,异步IO模型,理论性能好但实际和NIO差距不大,主要在Windows上有优势。
生产建议:Linux环境首选NIO(开箱即用,性能够用);对性能极致追求且能装APR的选APR;Windows部署考虑NIO2。别盲目追APR,NIO配合合理的线程池参数已经能扛住绝大多数业务。
【面试题】3. Linux系统load average三个数字分别代表什么?什么情况下load高但CPU使用率低?怎么排查?
【标准答案】load average三个数字分别是1分钟、5分钟、15分钟内的系统平均负载,含义是处于R状态(运行中或等待CPU)和D状态(不可中断IO等待)的进程数之和。
load高但CPU使用率低,典型原因是大量进程卡在D状态,即磁盘IO瓶颈。排查步骤:1)vmstat 1看wa列(IO等待CPU占比),wa高说明磁盘慢;2)iostat -x 1看%util和await,哪块盘高一目了然;3)ps aux | awk '$8 ~ /D/' 找D状态进程;4)iotop定位具体哪个进程IO消耗最大。
常见场景:NFS挂载卡死、磁盘坏道、数据库大查询刷盘、日志狂写。临时应急:能停的进程先停,不能停的考虑限速(ionice)或切换IO路径。
【面试题】4. Nginx的limit_req和limit_conn两个限流模块有什么区别?怎么配合使用防刷接口?
【标准答案】两者限流维度不同:
- limit_req:按请求速率限流,基于令牌桶算法,控制的是"每秒允许多少请求"。比如 limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; 限制单IP每秒10个请求。
- limit_conn:按并发连接数限流,控制的是"同时允许多少连接"。比如 limit_conn_zone $binary_remote_addr zone=addr:10m; 配合 limit_conn addr 20; 限制单IP最多20个并发连接。
配合使用:limit_req挡住短时间突发(刷接口),limit_conn挡住慢速连接攻击(慢速DDoS,一个连接占着不放)。生产建议:limit_req加burst参数允许合理突发(burst=20 nodelay),避免正常用户被误杀;limit_conn的值根据业务QPS和响应时间计算,一般50-100起步。两个都要配好自定义错误页,被限流时返回429而不是默认的503。
【面试题】5. Keepalived+Nginx高可用方案中,主节点Nginx进程挂了但机器还活着,VIP不会漂移怎么办?
【标准答案】这是经典问题。Keepalived默认只检测自己进程是否存活,不关心Nginx状态。如果Nginx挂了但Keepalived还在,VIP不会漂移,流量打到死Nginx上,服务就挂了。
解决方案:写一个检测脚本,用vrrp_script配置:
# 检测脚本
#!/bin/bash
if ! pidof nginx > /dev/null; then
systemctl start nginx # 先尝试重启
sleep 2
if ! pidof nginx > /dev/null; then
exit 1 # 重启失败,标记失败
fi
fi
exit 0Keepalived配置中:
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -20
fall 3
rise 2
}weight -20是关键:检测失败时优先级减20,低于备节点优先级就自动漂移。fall 3连续3次失败才判定,避免网络抖动误切换。同时要配好nopreempt或不配,按业务决定切回策略——一般建议不自动切回,避免脑裂反复切换。
【面试题】6. 如何用tcpdump抓包排查Nginx 502问题?说出具体抓包命令和分析思路。
【标准答案】502是Nginx无法从上游获取有效响应,常见原因:后端挂了、后端拒绝连接、后端响应超时、Nginx和后端之间的网络问题。
抓包步骤: 1)先确认后端存活:curl直接访问后端IP:端口。 2)抓Nginx到后端的包:tcpdump -i eth0 -nn host <后端IP> and port <后端端口> -w 502.pcap,同时复现问题。 3)分析重点看什么:SYN包发出去了有没有SYN+ACK回来——没有就是后端没收到或防火墙拦截;有SYN+ACK但紧接着RST——后端拒绝连接(进程没起来或端口不对);TCP连接建立但后端迟迟不回数据——后端处理卡住;回的数据带RST或FIN——后端异常断开。
常见结论:大量SYN没响应→后端挂了或防火墙问题;连接建立后RST→后端进程异常;正常请求但响应慢→后端性能问题,调proxy_read_timeout。
【面试题】7. Linux的sysctl内核参数中,net.ipv4.tcp_tw_reuse能解决TIME_WAIT过多的问题吗?生产环境敢开吗?
【标准答案】能缓解,但不是万能药,而且生产环境要谨慎。
tcp_tw_reuse=1允许将TIME_WAIT状态的连接重新用于新的TCP连接,只对客户端(主动发起连接方)生效。服务端被动收到SYN时不受这个参数影响。
生产能不能开?看场景:Nginx作为反向代理去连后端,Nginx是客户端角色,开了可以复用TIME_WAIT连接,缓解端口耗尽,这个场景可以开。但如果你的服务器是被动接收连接方(比如数据库),开了也没用。
真正该做的:1)先搞清楚谁是主动关闭方——主动close的一方才产生TIME_WAIT;2)如果是Nginx主动关,考虑让后端主动关(后端设keepalive,Nginx用upstream keepalive复用连接);3)tcp_tw_reuse配合tcp_timestamps(必须开启)才生效;4)net.ipv4.tcp_max_tw_buckets适当调大给缓冲空间。
绝对不要开tcp_tw_recycle(已在Linux 4.12后移除),会导致NAT环境下连接异常。
【面试题】8. Prometheus的pull模型和Zabbix的push模型各有什么优劣?什么场景选哪个?
【标准答案】两种模型核心区别:
Prometheus pull模式:服务端主动去拉取目标指标。优势:服务端掌控采集节奏,目标只需暴露/metrics接口,新实例自动发现(SD机制),不用逐个配agent;劣势:不适合短生命周期任务(进程结束指标就没了),大规模部署时服务端压力大,跨网络需打通访问。
Zabbix push模式(agent主动上报):Agent主动向Server发送数据。优势:适合NAT后或防火墙内的机器,短任务也能上报完就退出,服务端压力分散;劣势:每台机器要装agent并配置,扩展性差,新增监控要手动加item。
选型建议:云原生/K8s环境选Prometheus,天然支持服务发现,生态丰富(Grafana+Alertmanager);传统IDC物理机/虚拟机选Zabbix,agent成熟稳定,模板丰富,运维人员上手快。也有混合方案:核心基础设施用Zabbix,应用层用Prometheus,两者通过remote_write打通。
【面试题】9. Docker容器内进程PID 1的问题是什么?为什么Docker容器里不能只用systemd?怎么正确处理优雅退出?
【标准答案】Docker容器中,ENTRYPOINT启动的进程就是PID 1。Linux的PID 1有两个特殊职责:回收孤儿进程、处理信号转发。
问题在哪:如果你用shell脚本启动应用(ENTRYPOINT ["sh", "-c", "..."]),PID 1是sh而不是你的应用,sh不会转发SIGTERM给子进程,导致docker stop时应用收不到信号,10秒后被SIGKILL强杀,数据可能丢失。
为什么不用systemd?容器理念是一个进程一个容器,systemd需要特权运行(--privileged)、需要cgroup访问、会启动一堆服务,违背容器轻量原则,而且复杂到容易出问题。
正确做法:1)用exec形式:ENTRYPOINT ["java", "-jar", "app.jar"],让应用直接成为PID 1;2)如果需要启动脚本,最后一行用exec java -jar app.jar把PID 1让给应用;3)更优雅的方案:用tini或dumb-init作为PID 1,它们负责信号转发和僵尸进程回收,应用作为子进程运行。K8s环境用pod的preStop hook + SIGTERM处理优雅关闭。
【面试题】10. 如何设计一个百万级并发的服务器架构?说出关键分层和每层的技术选型思路。
【标准答案】百万级并发架构核心是分层+水平扩展,不存在单机扛住的方案。
第一层:接入层。DNS轮询 + CDN静态资源分发,动静分离。动态请求到LVS(DR模式,单机可抗百万并发)做四层负载,再转Nginx集群做七层路由和限流。
第二层:网关层。Nginx/OpenResty或API网关(Kong/APISIX),负责鉴权、限流、熔断、路由。这层必须无状态,随时水平扩容。
第三层:服务层。微服务拆分,每服务独立扩缩容。连接池(数据库用Druid/HikariCP,Redis用Lettuce)控制住连接数。服务间通信用gRPC或消息队列解耦。
第四层:缓存层。本地缓存(Caffeine)挡热点 + Redis集群挡常规查询 + 穿透/击穿/雪崩的防护(布隆过滤器、互斥锁、随机过期)。缓存命中率要达到95%以上,否则数据库扛不住。
第五层:数据层。读写分离(主写从读),分库分表(ShardingSphere),冷热分离(热数据MySQL + 冷数据归档到ES或对象存储)。
横切关注点:监控(Prometheus+Grafana全链路)、日志(ELK集中采集)、链路追踪(SkyWalking)、配置中心(Nacos)、熔断降级(Sentinel)。关键数字:LVS单机百万、Nginx单机5万并发、Redis单机10万QPS、MySQL单机5000 QPS是基线,超出就扩。