服务器运维面试题库
生成时间:2026-05-24 22:23
【面试题】1. Nginx的location匹配规则优先级是怎样的?请详细说明并举例。
【标准答案】Nginx的location匹配有四种类型,优先级从高到低依次是:
精确匹配
= /path:URI完全一致才命中,优先级最高,一旦匹配直接返回,不再继续。适合做精确路由,比如= /health做健康检查,一次匹配就结束,性能最优。前缀匹配(最高优先)
^~ /path:匹配前缀后,如果后面没有更长的前缀匹配,就直接使用它,不会再去检查正则。适合已知不需要正则的静态路径,比如^~ /static/,避免正则匹配的性能开销。正则匹配
~区分大小写 /~*不区分大小写:按照配置文件中出现的顺序依次匹配,第一个命中的就使用。正则之间是"先到先得",所以正则的顺序很重要。普通前缀匹配
/path:优先级最低。Nginx会记住最长前缀匹配,但还会继续检查是否有正则匹配。如果有正则命中,正则优先;如果没有,才用最长前缀。
记忆口诀:精确 > 前缀优先 > 正则 > 普通前缀。面试中重点强调两点:一是正则按书写顺序匹配,写在前面的优先;二是普通前缀虽然优先级低,但Nginx会选择最长的那个前缀。
【面试题】2. Linux系统中load average三个数值分别代表什么?什么情况下需要告警?
【标准答案】load average三个数分别是1分钟、5分钟、15分钟的系统平均负载,表示单位时间内处于可运行状态(R状态)和不可中断睡眠状态(D状态,通常是IO等待)的进程数。
理解关键点:
- 这个值不是CPU使用率,而是排队等待运行的进程数量
- 判断标准是和CPU核数对比。单核系统load=1表示刚好满载,4核系统load=4表示满载
- 三个数的趋势反映系统状态:1分钟>5分钟>15分钟说明负载在上升,反过来说明负载在下降
告警阈值设定:
- 一般经验:load超过核数的70%关注,超过核数告警,超过核数2倍严重告警
- 比如4核机器:load>2.8关注,>4告警,>8严重
- 还要看趋势:如果1分钟值远高于15分钟值,说明是突发负载,可能自行恢复;如果三者接近且持续高,说明是持续压力,需要介入
面试加分点:要区分CPU密集型高load和IO密集型高load。CPU密集型top看%us高,IO密集型top看%wa高,处理方式完全不同——CPU密集型要优化代码或扩核,IO密集型要优化磁盘或加缓存。
【面试题】3. 如何排查Nginx 502 Bad Gateway错误?请给出完整的排查思路。
【标准答案】502说明Nginx作为反向代理时,无法从上游服务拿到有效响应。排查步骤:
第一步:确认上游服务是否存活
systemctl status php-fpm/systemctl status tomcat看服务状态netstat -tlnp | grep 端口看端口是否在监听- 如果服务挂了,先看服务日志找崩溃原因再重启
第二步:检查Nginx到上游的连通性
curl http://127.0.0.1:上游端口/在Nginx机器上直接请求上游- 检查upstream配置的地址和端口是否正确
- 如果上游在另一台机器,检查防火墙和网络连通性
第三步:检查上游服务是否过载
- 上游进程数是否打满:php-fpm的
pm.max_children、tomcat的线程池 - 看上游日志是否有超时或拒绝连接的记录
ss -s看连接数是否异常
第四步:检查Nginx配置
proxy_read_timeout、proxy_connect_timeout是否设置过小- upstream的
max_fails和fail_timeout是否把上游标记为down了 proxy_buffer_size是否不够导致响应头过大
第五步:查Nginx error.log
tail -f /var/log/nginx/error.log看502对应的具体错误信息connect() failed (111: Connection refused)→ 上游没启动connect() failed (110: Connection timed out)→ 上游无响应upstream sent too big header→ buffer太小
面试重点:不要一上来就重启,要先定位根因。502的本质是Nginx连不上上游或上游返回了无效响应,沿着这条线排查就不会走偏。
【面试题】4. Keepalived+Nginx高可用方案的工作原理是什么?脑裂问题如何解决?
【标准答案】工作原理: Keepalived基于VRRP协议实现VIP(虚拟IP)漂移。两台Nginx服务器分别作为MASTER和BACKUP,Keepalived会持续发送VRRP广播包(组播224.0.0.18)。MASTER优先级高的持有VIP,BACKUP监听广播。当MASTER宕机,BACKUP收不到广播,在约定时间后接管VIP,实现自动故障转移。
关键配置点:
vrrp_instance中state MASTER/BACKUP、priority值决定角色virtual_ipaddress配置VIPtrack_script可以配置健康检查脚本,检测Nginx进程是否存活,如果Nginx挂了就主动降低优先级让VIP漂走
脑裂问题: 脑裂是指MASTER和BACKUP都认为自己持有VIP,同时写入流量。原因是两者之间网络不通但各自都还活着。
解决方案:
- 冗余心跳线:除了主用VRRP组播通道,增加一条独立的交叉网线做备用心跳
- 仲裁机制:引入第三方节点或网关做仲裁,两节点抢VIP时由仲裁决定归属
- 检测脚本:在
notify_master回调中检查对方是否真的挂了,如果对方还活着就放弃接管 - 防火墙规则:确保VRRP协议(协议号112)不被防火墙拦截,这是最常见的脑裂原因
- 日志监控:监控Keepalived状态切换日志,脑裂发生时及时告警人工介入
面试加分:实际生产中,最简单有效的防脑裂手段是确保VRRP组播包不被阻断,同时用track_script检测Nginx进程状态。如果条件允许,用双VIP互为主备(A是VIP1的MASTER、VIP2的BACKUP,B反过来),既防脑裂又充分利用资源。
【面试题】5. iptables和firewalld有什么区别?生产环境推荐用哪个?
【标准答案】核心区别:
- iptables是传统的Linux防火墙工具,直接操作内核netfilter规则链,规则按顺序匹配,规则多时性能线性下降
- firewalld是CentOS7+的默认防火墙管理工具,底层仍然可以调用iptables/nftables,但引入了"zone"和"service"的抽象层,规则管理更灵活
关键差异:
- 规则组织方式:iptables是扁平的规则列表;firewalld用zone(trusted/public/dmz等)分组,不同网络接口可以绑不同zone
- 规则生效方式:iptables每条规则立即生效;firewalld修改后需要reload才生效(也可以--permanent即时生效),支持运行时规则和永久规则分离
- 性能:iptables规则多时遍历慢;firewalld底层用nftables时性能更好(批量处理)
- 易用性:firewalld用service和zone封装,开HTTP就是
firewall-cmd --add-service=http,不用记端口号
生产建议:
- CentOS7+推荐firewalld,管理方便,zone隔离更安全
- 如果规则量非常大(上千条)或需要精细控制包处理流程,用iptables/nftables更合适
- 两者不要混用,会冲突。选一个用到底
- 不管用哪个,核心原则:默认拒绝,只开必要端口,限制来源IP
面试强调:不要陷入"哪个更好"的争论,重点是理解底层都是netfilter/nftables,选型看团队习惯和运维复杂度。能用firewalld解决的就别手写iptables规则。
【面试题】6. Tomcat的Connector三种线程模型(BIO/NIO/APR)有什么区别?生产环境怎么选?
【标准答案】三种模型对比:
BIO(Blocking IO):Tomcat 8.5之前默认。每个请求占用一个线程,线程在读写时阻塞。并发一高线程数暴增,上下文切换开销大。已淘汰,不推荐。
NIO(Non-blocking IO):Tomcat 8.5+默认。使用Java NIO,一个线程通过Selector管理多个连接,读写不阻塞。用少量线程处理大量连接,适合高并发长连接场景。配置
protocol="org.apache.coyote.http11.Http11NioProtocol"。APR(Apache Portable Runtime):通过JNI调用本地C库实现,本质是使用操作系统的epoll。性能最好,但需要安装APR库和tomcat-native。配置
protocol="org.apache.coyote.http11.Http11AprProtocol"。
生产选型:
- 绝大多数场景用NIO就够了,开箱即用,性能已经很好
- 对性能极致要求(单机万级并发以上)且运维能力强时用APR,但要承担额外依赖的运维成本
- BIO绝对不要用
NIO模式调优关键参数:
maxThreads="500":最大工作线程数,不是越大越好,一般200-800,CPU密集型少设,IO密集型多设minSpareThreads="50":最小空闲线程,避免突发流量时现创建线程acceptCount="200":连接队列长度,线程满时连接排队等待connectionTimeout="20000":连接超时,防止慢连接占资源
面试要点:选NIO默认即可,重点会调参数。APR性能虽好但增加了部署复杂度,除非有明确的性能瓶颈证据,否则不值得引入。
【面试题】7. Linux系统中如何排查内存泄漏?请给出完整的排查步骤。
【标准答案】第一步:确认是否存在内存泄漏
free -h看内存使用趋势,关注available值是否持续下降top按M排序,看哪个进程内存持续增长vmstat 1看si/so是否有持续swap,内存不足时系统会swap
第二步:定位泄漏进程
ps aux --sort=-%mem | head -20找内存占用最高的进程top -p PID持续观察特定进程的RES(物理内存)和VIRT(虚拟内存)- 如果是Java应用:
jstat -gcutil PID 1000看各代内存变化,Old区持续增长回收不掉就是泄漏
第三步:分析泄漏原因
- Java应用:
jmap -dump:format=b,file=heap.hprof PID导出堆dump,用MAT或VisualVM分析,找占用最大的对象和GC Roots引用链 - C/C++应用:用valgrind
valgrind --leak-check=full ./program直接检测泄漏点 - Go应用:
pprof工具,go tool pprof http://localhost:6060/debug/pprof/heap - 通用方法:
pmap -x PID看进程内存映射,/proc/PID/smaps看详细内存段
第四步:临时止损
- 如果内存快打满了,先
systemctl restart 服务名重启恢复 - 设置cron定期检查内存,超阈值自动重启(应急方案)
- 调大swap作为缓冲(治标不治本)
第五步:根因修复
- 代码层面:未关闭的资源(连接/流)、集合对象只增不删、ThreadLocal未清理、缓存无过期策略
- 配置层面:JVM堆是否太小、GC策略是否合适
面试关键:排查内存泄漏的核心是"持续监控+对比趋势",不是看一个时间点的快照。要先确认趋势,再定位进程,再分析代码,不要一上来就重启了事。
【面试题】8. Nginx限流配置怎么做?limit_req和limit_conn的区别和使用场景是什么?
【标准答案】limit_req——限制请求速率(限频) 基于令牌桶算法,控制单位时间内的请求数。
# http块中定义限流规则
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# server或location中应用
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429;
}rate=10r/s:每个IP每秒最多10个请求burst=20:允许突发20个请求排队nodelay:突发请求不延迟处理,超出的直接拒绝- 不加nodelay:突发请求会排队延迟处理,不会直接拒绝
limit_conn——限制并发连接数 控制同一时刻的并发连接数。
# http块中定义
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# location中应用
location /download/ {
limit_conn zone=conn_limit 5;
limit_conn_status 503;
}表示每个IP最多5个并发连接。$binary_remote_addr比$remote_addr更省内存(IPv4只占4字节)。
区别和使用场景:
- limit_req:防高频刷接口、防爬虫、API速率限制。关注的是"多快"
- limit_conn:防并发下载、防连接耗尽。关注的是"多少个"
- 两者可以同时用,互不冲突
面试加分点:
- 限流维度可以换:
$binary_remote_addr按IP限,$server_name按站点限,自定义变量按API Key限 - 限流后的处理:返回429/503,或配置
error_page 429 /429.html给友好提示 - 分布式环境下单机限流不够,需要Redis+Lua或网关层统一限流
【面试题】9. Prometheus+Grafana监控体系中,如何设计一个完整的监控告警方案?
【标准答案】监控指标设计——USE方法(Utilization/Saturation/Errors):
- 主机层:CPU使用率、load average、内存使用率、磁盘使用率、磁盘IO使用率和等待、网络带宽、文件描述符使用数
- 应用层:QPS、响应时间P50/P95/P99、错误率、活跃连接数、线程池使用率、JVM堆内存和GC
- 中间件层:MySQL连接数/慢查询/QPS、Redis命中率和内存、MQ消息堆积量、Nginx请求量和状态码分布
- 业务层:订单量、支付成功率、核心接口耗时(根据业务定制)
告警分级:
- P0致命:服务不可用、核心功能故障 → 电话+短信,5分钟响应
- P1严重:性能严重下降、资源即将耗尽 → 短信+IM,15分钟响应
- P2警告:指标异常但未影响服务 → IM通知,工作时间处理
- P3提示:常规信息,仅记录
告警规则设计原则:
- 告警要有价值,宁缺毋滥。一条告警必须对应一个明确的处理动作
- 用
for持续时间避免毛刺误报:for: 5m表示持续5分钟才告警 - 多条件组合减少误报:CPU>80% AND load>核数*2 才告警,比单条件更准
- 告警聚合:同一服务的相关告警合并,避免风暴
Prometheus关键配置:
# alertmanager配置告警路由和抑制
route:
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'ops-team'Grafana看板设计:
- 总览大屏:全红绿状态,一眼看系统健康度
- 主机详情:单机所有指标
- 应用详情:单个服务的调用链和性能
- 告警历史:过去24h告警趋势
面试要点:监控不是堆指标,是设计一套"发现问题-定位问题-解决问题"的闭环。告警太多=没有告警,控制告警质量比覆盖面更重要。
【面试题】10. Docker容器资源限制怎么做?一个容器把宿主机资源吃光了怎么处理?
【标准答案】Docker资源限制参数:
- CPU限制:
--cpus=2:限制最多使用2个CPU核心--cpuset-cpus=0,2:绑定到第0和第2个CPU核心--cpu-shares=512:CPU权重(相对值,只在争抢时生效)
- 内存限制:
-m 4g或--memory=4g:限制最大内存4G--memory-swap=8g:限制内存+swap总共8G--memory-reservation=2g:软限制,内存紧张时才生效
- IO限制:
--device-read-bps /dev/sda:10mb:读速度限制10MB/s--device-write-iops /dev/sda:100:写IOPS限制100
容器吃光宿主机资源的处理:
紧急处理:
docker stats找到异常容器docker update --memory=2g --cpus=1 容器ID在线调整资源限制(不用重启)- 如果容器已经卡死:
docker kill 容器ID强制停止
根因分析:
docker logs 容器ID看日志,是否应用异常导致资源暴涨docker exec 容器ID top进入容器看进程,定位具体哪个进程- 如果是Java应用,检查是否JVM堆设置过大(
-Xmx超过了容器内存限制)
预防措施:
- 所有容器必须设置资源限制:这是铁律。没有资源限制的容器就是定时炸弹
- K8s中用requests和limits:yaml
resources: requests: # 保底资源 memory: "512Mi" cpu: "500m" limits: # 上限资源 memory: "2Gi" cpu: "2000m" - 设置OOM优先级:
--oom-score-adj值越高越先被杀,核心服务设低值 - 监控告警:容器CPU/内存使用率超过80%就告警
面试关键:强调"预防>处理"。每个容器上线时就必须配好资源限制,这是运维底线。出问题后再加限制是被动的,而且docker update虽然能在线调整,但部分参数(如swap限制)修改后需要重建容器。