简介:面向具备一定Linux与中间件基础、正在备战中高级运维岗位的IT技术人员,这份面试宝典围绕Nginx、Docker、Kubernetes及常见中间件展开,系统梳理Web服务优化、负载均衡、TCP/IP协议、K8s核心组件与调度原理、Prometheus监控、MySQL主从与GTID、Redis同步、Kafka/RabbitMQ对比等高频考点,并穿插shell脚本参数、iptables规则、Zabbix自定义监控等实用技能,既能查漏补缺,也可作为面试答题思路速查手册。资源为单个PDF文档,大小2.78MB,便于离线查阅。目前已有78位学习者下载。文档中包含大量Nginx配置示例、K8s工作流程说明与组件原理图解,建议结合实践环境动手验证,从而真正理解配置背后的原理与设计取舍。
1. 一份《Linux高级运维面试宝典》,为什么值得逐行拆
一份号称《Linux高级运维面试宝典》的PDF,被很多候选人当成题库背,结果面试官把“gzip压缩”追问一句“gzip_buffers 4 64k 到底分配了几块内存”,就卡住了。真正能发挥作用的宝典,不是题目清单,而是把Nginx优化、负载均衡、TCP/IP、Docker、K8s这些点连成一张网,让你能解释配置背后的取舍。这篇拆解围绕这份PDF里的高频考点展开,重点落在可以直接复现的配置、参数验证和常见坑上,适合准备中高级运维岗位,或者正在做架构选型的人。
2. Nginx性能调优的四个高频考点:从gzip到limit_req
Nginx在面试中的占比最高,但很多人只背结论,比如“开gzip”“加expires”,却解释不了参数之间的权衡。这一章把PDF中的Nginx优化题整理成几个可以动手验证的小节,每节都给出配置和验证方法,避免只会说“优化”不会调参。
2.1 隐藏版本号和进程身份:安全面第一问
隐藏版本号通常放在nginx.conf的http块里,配合修改worker进程的用户和组一起说。先看基础配置:
# nginx.conf 核心片段 user nginx; # worker进程使用 nginx 用户运行 worker_processes auto; # 自动匹配CPU核数 server_tokens off; # 隐藏版本号user指令控制worker进程的属主和属组,权限过大是生产环境最常见的安全隐患。server_tokens off 会让错误页和Server响应头不再携带Nginx版本号,修改后执行nginx -t && nginx -s reload验证配置,再用curl -I http://127.0.0.1/查看Server头。如果看到“Server: nginx”而不是“Server: nginx/1.24.0”,说明生效。源码安装时server_tokens的默认行为会和发行版包安装不同,所以线上环境以实际版本为准。
2.2 expires缓存与日志切割:静态资源的常规操作
静态资源优化是Nginx面试的基础题,expires和access_log配合是常见做法。
# 图片类静态资源缓存30天 location ~* \.(jpg|jpeg|gif|png|swf)$ { expires 30d; access_log off; }expires 30d 给这些文件加上Cache-Control: max-age=2592000和Expires头,让浏览器在30天内直接读本地缓存。access_log off 避免图片类请求刷爆访问日志,因为图片量通常远大于HTML页面。日志切割方面,Nginx本身没有内置轮转机制,生产环境一般交给logrotate:
/usr/local/nginx/logs/access.log { daily rotate 30 compress delaycompress missingok notifempty sharedscripts postrotate [ -f /usr/local/nginx/logs/nginx.pid ] && kill -USR1 `cat /usr/local/nginx/logs/nginx.pid` endscript }logrotate按天切割,保留30份,旧的压缩存储。postrotate里的kill -USR1信号让nginx重新打开日志文件,不需要重启进程。如果只mv日志文件不通知nginx,nginx会继续往已删除的inode里写数据,磁盘空间不会被释放。
2.3 Gzip压缩参数:先看配置再看原理
gzip压缩是Nginx优化里必问的题目,但关键在参数含义。
gzip on; # 开启gzip gzip_buffers 4 64k; # 压缩结果流缓存,4块64k gzip_http_version 1.1; # 仅对HTTP/1.1及以上生效 gzip_min_length 1k; # 小于1k不压缩 gzip_vary on; # 输出 Vary: Accept-Encoding gzip_comp_level 5; # 压缩级别 gzip_types text/plain text/css application/json application/javascript;各参数的作用如下表:
| 参数 | 作用 | 注意点 |
|---|---|---|
| gzip on | 开启压缩输出 | 默认off |
| gzip_buffers 4 64k | 申请4个64k的内存作为压缩结果流缓存 | 按需分配,不是一次性占满256k |
| gzip_min_length | 字节数低于该值不压缩 | 太小的响应压缩收益低,反而浪费CPU |
| gzip_http_version | 指定HTTP协议版本 | 默认1.1,老客户端为1.0时可能不压缩 |
| gzip_vary on | 让缓存服务器区分压缩版本 | 配合CDN时建议开启 |
| gzip_comp_level | 1-9压缩级别 | 5是速度和体积的折中 |
“gzip_buffers 4 64k”容易误解成总缓冲48k?实际是压缩结果流缓存最多使用4个64k的buffer,Nginx在压缩过程中按段写入,超过64k时申请下一个64k。面试官如果问哪些内容不要压缩,可以回答jpeg、png、mp4等本身已经压缩过的格式,再压一遍收益很小还会增加CPU开销。
2.4 防盗链:valid_referers和rewrite的配合
防盗链的原理是检查Referer字段,来源域名不在白名单就重写或拒绝。
location ~* \.(jpg|gif|swf)$ { valid_referers none blocked *.benet.com benet.com; if ($invalid_referer) { rewrite ^/ http://www.benet.com/error.png; } }valid_referers各字段含义:
| 值 | 含义 |
|---|---|
| none | Referer为空,比如直接浏览器地址栏访问图片 |
| blocked | Referer存在但不以http://或https://开头 |
| *.benet.com | 匹配该域名及其子域名的来源 |
当来源不在白名单时,$invalid_referer为1,执行rewrite跳转到错误图片。这里要提醒,if + rewrite在Nginx里是“邪恶指令”,可以把请求重写走,但不要把业务逻辑写在if里。更稳妥的方式是把rewrite换成return 403,直接拒绝盗链请求,减少流量消耗。如果希望记录盗链来源,可以在if里加上access_log /var/log/nginx/hotlink.log;,方便后续封禁。
2.5 limit_req限流:rate、burst、nodelay的真实关系
限流是Nginx面试的进阶题。首先在http块定义区域:
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;然后在server或location下应用:
location ~* \.html$ { limit_req zone=one burst=5 nodelay; proxy_pass http://backend_tomcat; }$binary_remote_addr是客户端的二进制IP地址,zone=one:10m表示名为one的共享内存区域占10MB,用来记录每个IP的请求状态。rate=1r/s表示平均每秒只允许1个请求。burst=5表示允许瞬时多排5个请求,nodelay表示排队的请求不延迟、立即处理;如果没有nodelay,超出rate的请求会排队等待,超过burst则直接返回503。真正起限流作用的是rate和burst,nodelay只改变排队请求的处理时机。生产环境建议加limit_req_status 429;,让超限请求返回429,便于区分限流和服务错误。
3. 负载均衡面试:LVS调度算法与Nginx upstream选型
负载均衡是高级运维面试的分水岭。面试官通常会从四层和七层的区别开始问,然后深入到调度算法。这一章把PDF中的LVS十种算法和Nginx upstream策略整理成容易记忆的模型,不要求背全,但要知道每个算法解决什么问题。
3.1 四层和七层到底差在哪
四层负载均衡工作在OSI模型的传输层,只能根据IP和端口转发;七层负载均衡工作在应用层,可以基于URL、Header、Cookie等应用层信息做决策。四层只看到“有一个TCP连接从10.0.0.1:12345到10.0.0.100:80”,七层还能看到“这个请求是GET /api/user,User-Agent是Chrome”。
| 维度 | 四层负载均衡 | 七层负载均衡 |
|---|---|---|
| 工作层级 | 传输层 | 应用层 |
| 典型实现 | LVS | Nginx、HAProxy |
| 决策依据 | IP + 端口 | URL、Header、Cookie |
| 连接关系 | 客户端与后端一条连接 | 客户端与代理、代理与后端两条连接 |
| 优点 | 性能高、吞吐大 | 灵活,可以做路由和改写 |
| 缺点 | 无法按内容分发 | CPU开销更大,吞吐受应用层处理影响 |
注意连接关系:四层负载均衡转发的是同一个TCP连接,所以LVS的DR模式下,响应流量可以不经过调度器,直接回给客户端;七层负载均衡必须维护两层连接,Nginx作为反向代理时,客户端连接和后端连接是独立的,这也解释了为什么Nginx代理高流量时CPU消耗比LVS高。
3.2 LVS十种调度算法的面试回答方式
LVS的调度算法不需要全背,但最好能说出常用算法的取舍。下表覆盖了PDF中的十种算法:
| 算法 | 核心逻辑 | 适用场景 |
|---|---|---|
| RR | 按顺序循环分发 | 后端处理能力接近 |
| WRR | 按权重比例分发 | 后端性能差异明显 |
| LC | 新请求分配给当前连接数最少的服务器 | 长连接服务 |
| WLC | 连接数与权重做除法,选结果小的 | 最常用的默认算法 |
| LBLC | 按目标IP绑定最近使用的服务器 | Cache集群 |
| LBLCR | 目标IP映射到一组服务器,再按LC选择 | 动态Cache集群 |
| DH | 按目标IP做散列 | 会话保持 |
| SH | 按源IP做散列 | 会话保持 |
| SED | (当前连接数+1)/权重,取最小 | 避免性能好的服务器被忽略 |
| NQ | 有空闲连接直接分配,否则用SED | 需要快速响应的场景 |
SED算法的计算过程是面试中容易卡住的地方。假设A、B、C三台机器权重分别是1、2、3,新请求进来时,SED计算为A=(1+1)/1=2,B=(1+2)/2=1.5,C=(1+3)/3=1.33,于是优先给C。因为C权重高,期望延迟低。NQ则更简单:只要有一台机器当前连接数为0,就不做计算直接分配过去。
3.3 Nginx upstream六种调度方式
Nginx的upstream模块提供了负载均衡配置入口,调度方式写在upstream块内。
upstream web_cluster { least_conn; server 10.0.1.10:8080 weight=2 max_fails=2 fail_timeout=30s; server 10.0.1.11:8080 weight=1 max_fails=2 fail_timeout=30s; } server { listen 80; location / { proxy_pass http://web_cluster; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }默认不写调度方式就是RR轮询;weight控制权重,权重越高被分配到的概率越大;least_conn是当前连接数少的优先;ip_hash保证同一客户端IP固定访问一台后端;url_hash按请求的URL做哈希;hash关键字则支持自定义键,比如hash $arg_sessionid;。ip_hash用于会话保持,但因为同一IP总有固定后端,如果那台机器宕机,这部分用户会失败,不能完全替代服务端Session同步。url_hash常用于缓存类场景,让同一个资源定向到同一台后端,提升缓存命中率。注意:在upstream里写ip_hash;之后,weight设置会被忽略,两者不能同时生效。
3.4 健康检查的坑:端口检测和URL检测
Nginx原生的健康检查是“被动”的:通过max_fails和fail_timeout判断,只有请求转发失败才把后端标记为不可用。
upstream backend { server 192.168.1.10:8080 max_fails=2 fail_timeout=10s; server 192.168.1.11:8080 max_fails=2 fail_timeout=10s; }max_fails=2表示在fail_timeout时间内失败2次就暂时摘掉该节点,fail_timeout=10s表示10秒后重新试探。但这种方式的问题在于:如果出现上传大文件时后端故障,Nginx已经在上传过程中,无法把这次连接切到另一台服务器,只能断掉。要主动检测后端是否可用,需要借助nginx_upstream_check_module第三方模块,或者用Nginx Plus的商业功能。Nginx原版健康检查只能检测端口,不能像HAProxy那样指定URL来检测,这也是面试中Nginx和HAProxy对比的常见考点。LVS也有类似限制,它对网络稳定性依赖大,不能使用正则表达式处理请求内容,因此动静分离这类需求通常不会用LVS解决,而是交给Nginx或HAProxy。
4. Nginx进程模型、HTTP链接处理与location匹配规则
Nginx的进程模型和location匹配规则是区分“用过Nginx”和“理解Nginx”的试金石。这一章按“进程怎么跑、请求怎么进、配置怎么配”的顺序拆,每一步都可以在实际环境中验证。
4.1 Master和Worker各干什么
Master进程负责读取和评估配置、维持worker进程的状态;worker进程才是真正处理请求的人。这种分离设计让Nginx可以在不中断服务的情况下reload配置。执行kill -HUP $(cat /usr/local/nginx/logs/nginx.pid)后,Master重新加载配置并启动新的worker,旧worker处理完现有连接后退出。日常查看:
ps -ef | grep nginx # root 1234 1 0 ... nginx: master process # nginx 1235 1234 0 ... nginx: worker processworker_processes建议设置为auto或者CPU核心数,worker_connections决定单个worker能同时打开的最大连接数。常用配置:
worker_processes auto; events { worker_connections 10240; }在Linux 2.6以上内核中,Nginx的worker可以复用连接,不需要像Apache那样每个连接一个进程,这是Nginx支撑高并发的底层原因。
4.2 HTTP请求从三次握手到响应的完整链路
面试官问“Nginx如何处理HTTP请求”,要按阶段回答。首先客户端三次握手建立TCP连接,内核把建立的连接放入监听队列,Nginx的事件模型把连接分发给某个空闲worker。worker收到新连接后,分配一个512字节的连接内存池,然后初始化http模块。如果客户端在client_header_timeout指令设置的时间内没有发送完整请求头,连接会被判定超时并关闭;之后才进入请求头校验、URI解析、location匹配、转发或静态文件处理。最后写入响应,记录access log,并根据keepalive配置决定连接是关闭还是复用。对应配置:
keepalive_timeout 65; client_header_timeout 10s; client_body_timeout 10s; send_timeout 10s;keepalive_timeout是客户端和Nginx之间的长连接保持时间;client_header_timeout是读取请求头的超时时间;client_body_timeout是读取请求体时的超时时间,但只对两次读操作之间的间隔生效,不是整个请求体必须在这个时间内读完;send_timeout是发送响应到客户端时,两次写操作之间的超时时间。面试时能说出“哪个阶段用哪个”就能得分。
4.3 large_client_header_buffers 4 8k是什么意思
这是一个经典陷阱题,答案不是4乘8k等于48k,而是4个8k的buffer,最多32k。Nginx先分配一个8k来读请求头,如果请求头超过8k,就再分配一个8k,最多分配4个。如果请求头超过32k,返回414 Request-URI Too Large。相关配置:
client_header_buffer_size 4k; large_client_header_buffers 4 16k;client_header_buffer_size是单个请求头缓冲区的初始大小,默认1k;large_client_header_buffers是当请求头过大时进入的扩展缓冲。生产环境遇到“请求头太大”的报错,优先调大large_client_header_buffers,把单个扩展buffer调小反而可能导致频繁申请多个buffer。注意配置单位是k,不是kb,Nginx配置文件中k表示1024字节。
4.4 location优先级和rewrite规则
location的匹配顺序不按配置文件里的书写顺序,而是按类型决定优先级:
| 写法 | 含义 | 优先级 |
|---|---|---|
| = /path | 精准匹配 | 最高,命中后不再继续匹配 |
| ^~ /path | 普通前缀匹配,命中后不再检查正则 | 次高 |
| ~ /path | 正则匹配,区分大小写 | 中 |
| ~* /path | 正则匹配,不区分大小写 | 中 |
| /path | 普通前缀匹配,命中后继续检查正则 | 最低 |
普通字符串匹配按最长前缀优先,但即便命中了普通前缀,如果后面有正则可以匹配,正则覆盖前面的结果;只有^~能“短路”正则。示例:
location = /logo.png { access_log off; } location ^~ /static/ { expires 7d; } location ~* \.(js|css)$ { expires 1h; } location / { proxy_pass http://web_cluster; }访问/logo.png走精准匹配;访问/static/app.js命中^~,即使后面的js正则也匹配,也不会再查正则;访问/other.js则命中js正则。rewrite规则只能放在server、location、if中,而且只能改写URI中参数之外的部分。rewrite的标志位里,last停止当前重写,并重新执行location匹配;break停止当前重写但不再匹配,直接处理当前location;redirect返回302临时重定向;permanent返回301永久重定向。例如:
location ^~ /download/ { rewrite ^/download/(.*)$ /files/$1 break; }这个配置把/download/路径重写到/files/路径,break避免循环重写,同时保证当前location不被重新匹配。
5. 被问到Docker和K8s时,如何把Nginx经验迁移过去
容器化面试题往往让传统运维不适,但换个角度看:Docker网络对应Nginx监听地址和iptables转发,K8s Service对应upstream动态管理。这一章不讲空概念,只讲怎么用命令验证以及如何把已有知识迁移到容器集群。
5.1 Docker网络模式:先跑个命令看现状
Linux运维对网络命名空间不陌生,Docker网络的基础就是它。先看当前环境有哪些网络:
docker network ls docker network inspect bridge | head -n 30默认的bridge网络会让容器通过veth对桥接到docker0,然后通过iptables做NAT访问外网。host模式让容器直接使用宿主机网络栈,没有隔离;none模式没有网络;container模式共享另一个容器的网络命名空间;overlay模式是跨节点容器通信的基础。面试中常问“Nginx容器要在80端口提供服务,怎么办”,两个答案:
docker run -d --name nginx-web --network host nginx:alpine docker run -d --name nginx-web -p 8080:80 nginx:alpinehost模式性能好但端口冲突需要自己管理,-p映射依赖iptables的DNAT规则,每个映射都会多一条规则。如果宿主机本身跑了Nginx,再起一个host模式的Nginx容器就会抢80端口,这时候可以改用-p映射或提前分好端口。这个选择逻辑和Nginx的listen指令一样:同一套资源只能有一个占用者,容器只是换了一种隔离方式。
5.2 K8s核心概念:Pod、Service、Label和Controller
K8s的调度单位是Pod,不是一个容器。一个Pod里的容器共享同一个网络命名空间,所以localhost可以互通。Label是键值对,通过selector关联资源;Controller负责维持Pod副本数;Service提供稳定的虚拟IP和DNS入口,后端对应一组Pod的Endpoints。可以用命令直接验证:
kubectl get pods -l app=nginx -o wide kubectl describe pod nginx-xxxxx | grep -A 5 Events第一条命令用Label选择器过滤出app=nginx的Pod,看它们分布在哪些节点;第二条命令看Events,调度失败、镜像拉取失败、探针失败都会在这里体现。Pod调度的基本流程:Scheduler watch到未调度的Pod,根据节点资源、亲和性规则选择节点,kubelet拿到Pod定义后创建容器。这个流程对应Nginx upstream里“选哪台后端”的逻辑,只不过Nginx靠round-robin或hash,K8s靠Scheduler的调度策略。
Service背后靠kube-proxy维护转发规则,常见模式是iptables和ipvs。iptables模式随机选中后端,规则数量随着Endpoint增加会变多;ipvs模式支持加权轮询、最小连接等调度算法。如果已经理解LVS的算法,看到kube-proxy的ipvs模式不需要额外学,直接沿用那套算法模型。
5.3 滚动更新与网络插件:把reload换成实例替换
Nginx更新配置靠reload热加载,K8s更新服务则依赖Deployment的滚动更新机制。执行下面命令会创建新版本Pod,每个Pod就绪后才继续更新下一个:
kubectl set image deployment/nginx nginx=nginx:alpine kubectl rollout status deployment/nginx kubectl rollout undo deployment/nginxset image触发镜像更新,rollout status可以看到更新进度,如果新版本启动失败,rollout undo立即回滚到上一个版本。Nginx reload和K8s滚动更新不是同一层面的操作,reload是配置热更新,滚动更新是实例替换;实例替换涉及新的IP、新的网络命名空间,因此需要Service做动态关联。
跨节点网络方面,flannel是常见的CNI插件。VXLAN模式通过UDP封装跨节点流量,适合三层网络环境;host-gw模式直接利用路由表把数据包转发到目标节点,性能更高但要求所有节点二层互通。面试被问到“Pod的IP为什么能跨节点访问”,VXLAN和host-gw就是两个可讲的答案。对应到Nginx场景,前者类似通过隧道到达后端,后者类似把后端地址直接写进路由表。
6. 用top命令把Linux负载指标讲成排查动作
top是linux常用命令里最容易被低估的一个。面试宝典里对top的整理从load average到buffers和cached的区别都有,但很多人只会按P看CPU排序。下面把它拆成“先看哪几行,再按哪几个键”。
6.1 第一行和第二三行怎么看
top - 09:30:00 up 10 days, 2:45, 2 users, load average: 0.15, 0.20, 0.30 Tasks: 120 total, 1 running, 119 sleeping, 0 stopped, 0 zombie %Cpu(s): 5.0 us, 1.0 sy, 0.0 ni, 94.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 stload average三个值分别对应最近1分钟、5分钟、15分钟的平均负载。单核系统负载超过1.00表示有任务在排队,多核系统负载不应该长期超过CPU核心总数。第二行看Tasks里的zombie数量,僵尸进程多说明有父进程没有正确回收子进程。第三行重点看wa,wa高表示CPU在等I/O,对应磁盘或网络瓶颈;us高说明用户态计算密集;si高说明软中断处理占用了大量CPU。
内存方面,top第四行的buffers和cached经常被混为一谈。buffers是块设备的读写缓冲区,cached是文件系统的页面缓存,两者都是Linux底层为了加速磁盘访问做的机制。判断内存是否够用,不能只看free列,还要看buffers和cached可以被回收的部分。
6.2 用top交互命令定位问题
top运行中可以按单个字母键完成大部分操作:
| 交互键 | 作用 |
|---|---|
| k | 按PID终止进程,可指定信号,默认15 |
| r | 调整进程优先级(nice),正值降低优先级 |
| M | 按内存占用排序 |
| P | 按CPU占用排序 |
| s | 调整刷新间隔,默认5秒 |
| f | 管理显示字段 |
k和r在生产环境要谨慎使用,优先用P和M找到异常进程,再决定是否介入。如果想把top结果写入监控脚本,用批处理模式:
top -b -n 1 | head -n 20-b表示非交互批处理,-n 1表示只输出一次,head截取前20行。持续观察某个进程可以组合参数:
top -b -d 2 -n 30 -p $(pgrep -f nginx | head -n 1)-d 2表示每2秒刷新,-n 30表示采样30次,-p指定进程PID。这个命令可以直接跑在Zabbix自定义监控里,把输出重定向到文件再解析,就得到一个完整的CPU采样脚本。面试时能这样用top,比只背参数表更能体现Linux排查能力。
本文还有配套的精品资源,点击获取