Nginx性能优化

Nginx性能优化
[TOC]
背景
1、首先我们需要了解性能优化要考虑哪些方面2、然后我们需要了解性能优化必要用到的压力测试工具ab3、最后我们需要了解系统上有哪些注意和优化的点,以及nginx配置文件
我们再做性能优化工作前,我们重点需要考虑哪些方面,和了解哪些方面1、首先需要了解我们当前系统的结构和瓶颈,了解当前使用的是什么,运行的是什么业务,都有哪些服务,了解每个服务最大能支撑多少并发。比如nginx作为静态资源服务并发是多少,最高瓶颈在哪里,能支持多少QPS(每秒查询率)的访问请求,那我们怎么得出这组系统结构瓶颈呢,比如top查看系统的CPU负载、内存使用率、总得运行进程等,也可以通过日志去分析请求的情况,当然也可以通过我们前面介绍到的stub_statius模块查看当前的连接情况,也可以对线上的业务进行压力测试(低峰期),去了解当前这套系统能承担多少的请求和并发,已做好相应的评估。这个是我们做性能优化最先考虑的地方
2、其次我们需要了解业务模式,虽然我们是做性能优化,但每一个性能的优化都是为业务所提供的服务的,我们需要了解每个业务接口的类型,比如:电商网站中的抢购模式,这种情况下面,平时没什么流量,但到了抢购时间流量会突增。我们还需要了解系统层次化的结构,比如:我们使用nginx做的是代理、还是动静分离、还是后端直接服务用户,那么这个就需要我们对每一层做好相应的梳理。以便更好的服务业务。
3、最后我们需要考虑性能与安全,往往注重了性能,但是忽略了安全。往往过于注重安全,对性能又会产生影响。比如:我们在设计防火墙功能时,检测过于严密,这样就会给性能带来影响。那么如果对于性能完全追求,却不顾服务的安全,这个也会造成很大的隐患,所以需要评估好两者的关系,把握好两者的孰重孰轻。以及整体的相关性,权衡好对应的点。压力测试
在系统业务量没有增长之前,我们就要做好相应的准备工作,以防患业务量突增带来的接口压力,所以对于接口压力测试就显得非常重要了,我们首先要评估好系统压力,然后使用工具检测当前系统情况,是否能满足对应压力的需求[root@web01 ~]# abab: wrong number of argumentsUsage: ab [options] [http[s]://]hostname[:port]/path# ab命令属于httpd-tools=======================ab -n 200 -c 2 http://127.0.0.1/#-n 要执行的请求数#-c 请求的并发数#-k 是否开启长连接#后面接我们测试的链接(网址http://)
[root@web01 ~]# cd /etc/nginx/conf.d/[root@web01 conf.d]# lltotal 28-rw-r--r-- 1 root root 315 Mar 13 13:21 admin.conf....# 第一个子配置文件[root@web01 conf.d]# mv test.conf 1.test.conf# 我们把test放前面[root@web01 conf.d]# lltotal 28-rw-r--r-- 1 root root 129 Mar 11 09:24 1.test.conf...[root@web01 conf.d]# systemctl restart nginx# 重启一下[root@web01 conf.d]# curl 127.0.0.1web01_index# 再次拉取本地[root@web01 conf.d]# curl http://127.0.0.1web01_index'上面两个是一样的'[root@web01 conf.d]# ab -n20000 -c200 http://127.0.0.1'报错了!后面应该跟具体的html页面才行!'[root@web01 conf.d]# ab -n20000 -c200 http://127.0.0.1/index.htmlThis is ApacheBench, Version 2.3 <$Revision: 1874286 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/===============================这些页面都是静态的,所以Nginx处理起来比较快!如果是动态的,就会Nginx比较鸡肋!===============================
Benchmarking 127.0.0.1 (be patient)Completed 2000 requestsCompleted 4000 requestsCompleted 6000 requestsCompleted 8000 requestsCompleted 10000 requestsCompleted 12000 requestsCompleted 14000 requestsCompleted 16000 requestsCompleted 18000 requestsCompleted 20000 requestsFinished 20000 requests# 上面是发的请求数
Server Software: nginx/1.26.1# 服务器软件:Nginx,版本 1.26.1Server Hostname: 127.0.0.1# 测试的目标主机名(域名)Server Port: 80# 测试使用的端口(HTTP 默认端口 80)
Document Path: /index.html# 请求的路径Document Length: 12 bytes# 服务器返回的内容长度
'测试参数与统计'Concurrency Level: 200# 并发请求数:200(模拟 200 个用户同时访问)Time taken for tests: 0.739 seconds# 完成所有测试请求的总耗时Complete requests: 20000# 成功的请求总数:2 万次Failed requests: 0✅# 失败的请求数:0(无失败)Total transferred: 4840000 bytes# 测试期间传输的总数据量HTML transferred: 240000 bytes# 仅 HTML 内容的总传输量
'性能指标'Requests per second: 27050.24 [#/sec] (mean)✅# 每秒处理的请求数(QPS),反映服务器吞吐量Time per request: 7.394 [ms] (mean)# 单个请求的平均耗时(并发模式下)Time per request: 0.037 [ms] (mean, across all concurrent requests)# 单个请求的实际平均耗时(不考虑并发)Transfer rate: 6392.73 [Kbytes/sec] received# 数据传输速率
'连接时间分布(单位:毫秒)'Connection Times (ms) min mean[+/-sd] median maxConnect: 0 1 0.6 1 4Processing: 1 4 0.6 4 7Waiting: 0 3 0.6 3 6Total: 2 5 0.9 5 10# 各项请求时间的统计(连接、处理、等待、总耗时):
'请求耗时百分比'Percentage of the requests served within a certain time (ms) 50% 5 66% 5 75% 5 80% 5 90% 6 95% 6 98% 7 99% 8# 99%的请求在8ms内完成 100% 10 (longest request)'xx%的请求在xx毫秒内完成'系统性能优化
📌文件句柄,Linux一切皆文件'也可以叫为 文件描述符 '# 详细可以参考架构开篇,有介绍!!文件句柄可以理解为就是一个索引,文件句柄会随着我们进程的调用-->频繁增加系统为了安全和稳定,默认会限制每个用户/进程能打开的文件句柄数量但在高并发场景(比如 Nginx、数据库、Java 应用),这个默认值远远不够!所以我们要调大这个限制,但又不能无限大——要合理分配====================================🔄 举个生活化的例子:想象你在餐厅打工:文件句柄 = 你能同时端的盘子数量。系统默认限制 = 老板说:“你最多只能端 10 个盘子!”(怕你摔了)高并发服务 = 高峰期来了 100 个客人,你得端 50 个盘子!修改 limits.conf = 你跟老板申请:“给我配个推车,我能端 65535 个!”[root@web02 ~]# tail -1 /etc/security/limits.conf* - nofile 65535Nginx 的 rlimit = 你自己偷偷练了杂技,哪怕老板没同意,你也先尝试多端几个(但最多不能超过老板允许的上限)# 针对nginx进程,nginx自带配置worker_rlimit_nofile====================================# 其他了解1、全局修改(对所有用户生效)* soft nofile 25535* hard nofile 25535==========================* 表示所有用户soft 是“软限制”:超过时只是警告,程序还能继续用(但可能失败)hard 是“硬限制”:绝对不能超过nofile = 最大打开文件数
2.针对特定用户(比如 root)root soft nofile 65535root hard nofile 65535✅ 实际生产中,很多服务会用专用用户(如 nginx、mysql),也可以单独为它们设限
3.调整内核参数:# (端口重用)[root@web01 ROOT]# vim /etc/sysctl.confnet.ipv4.tcp_tw_reuse = 1# 开启端口复用net.ipv4.tcp_timestamps = 0# 禁用时间戳'刚开始进公司,内核的东西先不要着急动!'===================net.ipv4.ip_forward=0# 这个是内核转发[root@web01 ROOT]# sysctl -p# 可以查看我们添加的内核参数# 配置文件里面有的东西[root@web01 ROOT]# sysctl -a# 可以查看所有内核参数====================================场景还原:客户端每秒发起几千甚至上万个 HTTP 请求(短连接)服务器处理很快,比如 10ms 就返回结果,然后主动关闭连接每次关闭都会让服务器本地的一个端口进入 TIME_WAIT 状态,持续 60 秒# 什么是 TIME_WAIT?'服务器处理完请求后主动close,TCP协议会进入一个叫TIME_WAIT的状态'
问题来了:服务器作为主动关闭方,会占用大量本地端口结果:新的连接无法分配本地端口,客户端连不上或连接超时# “服务器干正经事 1 秒,端口却要‘躺尸’60 秒”'资源利用率极低,端口成了瓶颈'
怎么解决?(简单提一下)1.启用 SO_REUSEADDR 和 net.ipv4.tcp_tw_reuse→ 允许内核在安全前提下重用 TIME_WAIT 的 socket(需配合时间戳)# 上面的端口复用2.让客户端主动关闭连接→ 把 TIME_WAIT 转移到客户端3.使用连接池 or 改成长连接→ 从根本上减少连接 创建/关闭 次数
长连接:一次连接建立后,反复用来传多个请求连接不会频繁 创建/关闭,所以几乎不会产生大量TIME_WAIT代理服务优化
通常nginx作为代理服务,负责转发用户的请求,那么在转发的过程中建议开启HTTP长连接# 用于减少握手次数,降低服务器损耗
'负载均衡lb01的优化:'upstream webs { server 172.16.1.7; server 172.16.1.8; keepalive 16; # 负载均衡服务器(lb01)和后台web长连接}
server { ... location / { proxy_next_upstream error timeout http_500 http_502 http_503 http_504; # 如果web01崩了,不返回它 include proxy_set; # 文件位置:/etc/nginx/proxy_set }}[root@lb01 nginx]# ll /etc/nginx/proxy_set-rw-r--r-- 1 root root 258 Feb 22 10:18 /etc/nginx/proxy_set[root@lb01 nginx]# cat /etc/nginx/proxy_setproxy_set_header Host $http_host;# 保留用户请求的Host主机proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;# 记录客户真实的IP地址proxy_http_version 1.1;# 固定HTTP版本为1.1,长连接
# 下面的超时控制参数,请参考Nginx04的文档!proxy_connect_timeout 30;proxy_send_timeout 60;proxy_read_timeout 60;
proxy_buffering on;proxy_buffer_size 32k;proxy_buffers 4 128k;静态资源优化

静态资源优化Nginx善于处理静态资源# 要么从本地磁盘去拿,要么去NFS去拿=========================浏览器渲染:HTML、CSS、JS图片文件:JPG、GIF、PNG视频文件:Mp4、AVI其他文件:TXT、DOC、PDF

我们也可以通过
access.log访问日志中,看出来请求明显增加!如果浏览器没有缓存,web服务器也没有设置
那么每次用户访问页面或请求资源时,都会向后端Web服务器发起新的HTTP请求
-
浏览器怎么知道,要走
缓存还是源站 -
走缓存的时候,如果
后台web服务器有改动怎么办? -
通过看头部信息!来确认是否改变!
请求头和响应头


| 概念 | 谁发出? |
|---|---|
| Request(请求) | 客户端(浏览器等) |
| Response(响应) | 服务器 |
| 头部 | 作用 |
|---|---|
ETag | 服务器为资源生成的唯一标识,用于精确比对资源是否变化 |
Last-Modified | 资源最后修改的时间戳,用于时间比对 |
If-None-Match | 客户端在后续请求中携带,与服务器的 ETag 比较 |
If-Modified-Since | 客户端在后续请求中携带,与服务器的 Last-Modified 比较 |
⚠️ 注意:
ETag和Last-Modified是 服务器设置的响应头
如果浏览器访问过! 就会从 从上次响应中
把ETag、Last-Modified等都存入本地缓存
作为下次请求时使用的凭证
用于下次携带对比
If-None-Match和If-Modified-Since携带的就是它俩
缓存流程详解
①浏览器检查本地是否有缓存
- 浏览器先查看本地是否已有该资源的缓存
- 如果有,再看这个缓存是否“有效”(即是否过期)
-
缓存有效性判断依据:
-
是否设置了
Cache-Control: max-age=... -
或者
Expires头
-
❗ 如果缓存已过期 → 必须向服务器发起请求
②发送条件请求
如果缓存已过期,浏览器先发送一个 带条件头部的请求,让服务器判断资源有没有变
✅ 优先级: 先看 ETag,再看 Last-Modified
具体步骤如下:
- 如果之前响应中有
ETag,且浏览器缓存了它:
- 浏览器会在新请求中带上:
If-None-Match: "69b0b3c8-c"-
服务器收到后,比较当前资源的
ETag是否一致:-
相同 → 返回
304 Not Modified -
不同 → 返回
200 OK + 新内容
-
- 如果
ETag不存在或无效(比如服务器没返回):
- 浏览器检查是否有
Last-Modified时间戳 - 若有,则在请求中带上:
If-Modified-Since: Wed, 11 Mar 2026 00:14:00 GMT- 服务器比较当前文件的修改时间:
- 没变 → 返回
304 Not Modified - 改变了 → 返回
200 OK + 新内容
- 没变 → 返回
- 如果两者都没有:
- 浏览器只能发起普通请求(无条件请求),服务器返回完整内容(
200 OK)

✅ 总结:正确顺序
| 步骤 | 条件 | 行为 |
|---|---|---|
| 1 | 缓存未过期(max-age > 0) | 直接使用本地缓存,不发请求 |
| 2 | 缓存过期 | 发起条件请求 |
| 3 | 有 ETag → 发送 If-None-Match | 服务器比对 ETag |
| 4 | 无 ETag → 发送 If-Modified-Since | 服务器比对时间 |
| 5 | 都没有 → 发送普通请求 | 服务器返回完整资源 |
缓存设置
# 配置在浏览器的缓存时间为7天[root@web01 conf.d]# vim test.confserve listen 80; server_name test.kpyun.com; root /code/test;
location ~ .*\.(jpg|gif|png)$ { # 如果有人访问我们jpg...结尾的文件 # .*任意字符 /.撬棍 expires 7d; # 在浏览器缓存7天 } location / { index index.html; }}[root@web01 conf.d]# cp 史迪奇.png /code/test/sdq.png[root@web01 conf.d]# ll /code/test/total 576-rw-r--r-- 1 root root 12 Mar 11 08:16 index.html-rw-r--r-- 1 www www 582512 Mar 10 18:55 sdq.png[root@web02 conf.d]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web02 conf.d]# systemctl restart nginx
在企业中,一般我们会把那些,不经常变的东西缓存一两年!!
- 比如公司的
LOGO

比较
稳定的资源我们才会去,配置缓存!
- 经常
改动的我们不会去配的!
'开发代码没有正式上线'# 取消js、css、html等静态文件缓存
location ~ .*\.(js|css|html)$ { add_header Cache-Control no-store; add_header Pragma no-cache; }
location ~ .*\.(jpg|gif|png)$ { expires 7d; }'图片进行缓存,js,css不进行缓存!'[root@web01 conf.d]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web01 conf.d]# systemctl restart nginx
[root@web01 conf.d]# tail -f /var/log/nginx/access.log10.0.0.1 - - [20/Mar/2026:11:11:33 +0800] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36" "-"10.0.0.1 - - [20/Mar/2026:11:11:36 +0800] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36" "-"'每次都是请求的源站!'==========================10.0.0.1 - - [20/Mar/2026:08:59:23 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36" "-"# 这个是之前的访问日志,都是304,资源命中!
文件高效传输

- 传统读取文件方式 VS sendfile读取文件方式
🎯 目标:把一个文件从硬盘传给客户端(比如浏览器)
🔹 一、传统方式(没有 sendfile)
✅ 步骤分解
- 第一步:操作系统从硬盘读文件 → 放进「内核缓冲区」
- 第二步:程序把内核缓冲区的数据复制到「用户缓冲区」
- 第三步:程序再把用户缓冲区的数据复制回「内核缓冲区」(准备发送)
- 第四步:通过 Socket 发给客户端
💡 注意:数据在「用户空间」和「内核空间」之间来回拷贝了 两次!
❌ 问题:
- CPU 要参与搬运,浪费性能
- 对于大文件,特别慢
🔹 二、sendfile 方式(开启 sendfile)
📌 简单说:“直接让内核帮忙,不经过用户!”
✅ 步骤分解:
- 第一步:操作系统从硬盘读文件 → 放进「内核缓冲区」
- 第二步:直接告诉内核:“把这块内存发给 Socket”
- 第三步:内核直接把数据从「内核缓冲区」发到网络
💡 数据只在内核空间流动,没有进入用户空间!
✅ 好处:
-
节省 CPU
-
更快、更省资源,尤其适合大文件传输
🎯 所以, sendfile = 让内核代劳,你只管指挥,不费力气!
'sendfile'在主配置文件里面:[root@web01 nginx]# ll /etc/nginx/nginx.conf-rw-r--r-- 1 root root 699 Mar 10 17:44 /etc/nginx/nginx.conf... sendfile on; # Nginx默认是开启的====================================tcp_nopush VS tcp_nodelay'它俩默认都是off关闭状态!'⚠️ 不推荐混用!不要同时开启 tcp_nopush 和 tcp_nodelay它们是互斥的: tcp_nopush = “别急,等我攒够了再发” tcp_nodelay = “别等,有就发”🎯 总结口诀🟢 “一个请求 = 一个完整响应” → 用 nopush(吞吐优先)🔴 “一个连接 = 多次来回对话” → 用 nodelay(延迟优先)🎯 一句话定义吞吐优先:👉 “一次能运多少货?” —— 关注单位时间内传输的总数据量延迟优先:👉 “第一个字多久到?” —— 关注单次操作的响应速度====================================🎯 核心结论(你总结得非常到位):不能单纯以“文件大小”来决定用 tcp_nopush 还是 tcp_nodelay,在大多数高性能服务中(尤其是静态资源、API、CDN),tcp_nopush(吞吐优先)用得更多、更合理
核心真相:即使文件小,Nginx 也会“批量发送”场景还原:用户打开一个网页浏览器并发请求 10 个资源:index.html, style.css, app.js, logo.png, icon1.png, ...每个文件可能只有 2KB~50KB但 Nginx 在内核层面通过 sendfile + tcp_nopush,会把多个文件的数据“合并成一个大TCP包”发出去!🧠 在一次响应中,把整个文件内容一次性高效发出👉 可见:吞吐优先的场景远多于延迟优先,尤其在基础设施层====================================两者都是好工具,关键看业务需求:你是要“快”(响应快),还是要“多”(传得多)?| 场景 | 推荐配置 | 为什么? |
|---|---|---|
| 静态文件服务器(如 Nginx 传图片/JS/CSS) | tcp_nopush on; | 批量发包,最大化吞吐 |
| CDN 边缘节点 | tcp_nopush on; | 大量文件分发,追求效率 |
| 日志写入 | tcp_nopush on; | 日志是顺序批量写,适合攒包 |
| SSH / 远程桌面 / 在线游戏 | tcp_nodelay on; | 用户按键必须立刻响应,不能等 |
| 金融交易系统 | tcp_nodelay on; | 毫秒级延迟决定成败 |
| WebSocket / gRPC / HTTP/2 | tcp_nodelay on; | 实时双向通信,小消息频繁 |
| 日志收集(如 Fluentd → Kafka) | tcp_nopush on;(如果批量发送) tcp_nodelay on;(如果实时上报) | 取决于是否缓冲日志 |
| Telnet / 交互式 Shell | tcp_nodelay on; | 每敲一个键都要立刻传 |
📊 实测数据参考(来自 Nginx 官方和社区压测)
| 配置 | QPS(10KB 静态文件) | 平均延迟 | CPU 使用率 |
|---|---|---|---|
sendfile on; tcp_nopush on; | 28,000 | 8ms | 45% |
sendfile on; tcp_nodelay on; | 22,000 | 7ms | 60% |
👉 虽然 nodelay 延迟略低 1ms,但 吞吐下降 20%+,CPU 更高 ——在 CDN/静态站 这种高并发场景,得不偿失!
静态资源压缩

Nginx将
响应报文发送至客户端之前启用压缩功能,然后进行传输这能够有效地节约带宽,并提高
响应客户端的速度
| 级别 | CPU 消耗 | 适用场景 | 特点说明 |
|---|---|---|---|
| 1 | ★ (~20%) | 实时流媒体 | 速度优先,压缩较弱 |
| 3 | ★★ (~35%) | 动态内容 | 平衡速度与压缩 |
| 6 | ★★★ (~50%) | ==通用 Web 内容== | 默认推荐,综合性能较好 |
| 9 | ★★★★ (~55%) | 静态资源 | 压缩最强,适合预处理资源 |
'内容冗余度会影响压缩效果'高冗余内容(如重复文本、未压缩的日志、HTML/CSS/JSON):1.含大量重复模式或空白字符2.极易被压缩低冗余内容(如加密数据、随机字符串、图片/视频):1.几乎无重复模式2.难以进一步压缩✅ 建议:仅对文本类资源启用高压缩级别图片、视频等媒体文件通常无需再用 Gzip 算法进行二次压缩============================gzip传输压缩'传输前压缩,传输后解压'# 默认是关闭的状态
'压缩图片效率较低'# 别人的图片都是经过处理的!所占的空间的是kb在企业中,图片这些东西让前端自己调!除非万不得已,压缩会占用我们服务器的资源!=========================案例: 压缩txt文件[root@web01 nginx]# cat /etc/services /etc/services /etc/services > /code/test/hh.txt[root@web01 nginx]# ls -lh /code/test/hh.txt-rw-r--r-- 1 root root 2.0M Mar 20 14:07 /code/test/hh.txt# 准备2M的文件
'浏览器测试访问大小'
'配置压缩'[root@web01 conf.d]# cat 1.test.confserver { listen 80; server_name test.kpyun.com; root /code/test;
location / { index index.html; }
location ~ .*\.(js|css|html)$ { add_header Cache-Control no-store; add_header Pragma no-cache; }
location ~ .*\.(jpg|gif|png)$ { expires 7d; }
location ~ .*\.(txt|xml|html|json|js|css)$ { # 如果匹配到这些 gzip on; # 开启压缩 gzip_http_version 1.1; # 压缩http版本1.1 gzip_comp_level 6; # 压缩等级6(通用) gzip_types text/plain text/css text/javascript application/javascript application/json application/xml; # 压缩的类型:必须用空格隔开 gzip_min_length 1024; # 小于1KB的文件不压缩(避免小文件压缩后反而变大) }}[root@web01 conf.d]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web01 conf.d]# systemctl restart nginx
'再次打开浏览器测试访问大小'
防止资源盗链
防盗链:'指的是防止资源被其他网站恶意盗用'===============================# web02配置盗链、偷取WEB01的图片[root@web02 ~]# vim /etc/nginx/conf.d/test.confserver { listen 80; server_name daolian.com; root /code/test;
location / { index index.html; }}# 域名:daolian.com[root@web02 ~]# vim /code/test/index.html<html> <head> <meta charset="utf-8"> <title>FROM web01 picture</title> </head> <body style="background-color:pink;"> <center><img src="http://test.kpyun.com/sdq.png"/></center> </body></html>'背景颜色是pink色!'[root@web02 ~]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web02 ~]# systemctl restart nginx
# 最后 windows的hosts解析10.0.0.8 daolian.com10.0.0.7 test.kpyun.com
'web01配置防盗链'# 准备一张禁止盗图的图片[root@web01 conf.d]# cat 1.test.confserver { listen 80; server_name test.kpyun.com; root /code/test;
location / { index index.html; }
location ~ .*\.(js|css|html)$ { add_header Cache-Control no-store; add_header Pragma no-cache; }
location ~ .*\.(jpg|gif|png)$ { expires 7d; valid_referers none blocked test.kpyun.com *.baidu.com; # 有效的来源 它们使用空格分隔!!! # none:请求没有带Referer(比如用户直接在浏览器地址栏输入图片链接) # blocked:Referer存在,但不是以 http:// 或 https:// 开头(比如被防火墙/代理删掉了协议头) # 后面是你自己的域名和信任的域名,允许他们请求 if ( $invalid_referer ) { # 如果是无效的请求 # return 403;可以直接返回禁止 rewrite ^(.*)$ /d.png break; # 或者跳转到/code/test/d.png,并停止匹配下面的location } } location ~ .*\.(txt|xml|html|json|js|css)$ { gzip on; gzip_http_version 1.1; gzip_comp_level 6; gzip_types text/plain text/css text/javascript application/javascript application/json application/xml; gzip_min_length 1024; }}[root@web01 conf.d]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web01 conf.d]# systemctl restart nginx
# 照片的准备![root@web01 conf.d]# ls -lh /code/test/d.png-rw-r--r-- 1 root root 543K Mar 20 16:28 /code/test/d.png
'再次浏览器访问'daolian.com
跨域访问

🌐 什么是跨域访问?
想象一下,你(浏览器)在 A 餐厅(a.com)点了一份牛排 但你想加点 B 餐厅(b.com)特制的酱料
于是你对服务员说:“麻烦帮我从 B 餐厅拿点酱料过来”
但餐厅有个规定(同源策略):
“为了安全,A 餐厅不能随便帮你去别的餐厅拿东西,除非 B 餐厅明确同意”
所以,当你请求 B 餐厅的酱料时,B 餐厅必须在回信里写清楚:
“我允许 A 餐厅的客人来拿我的酱料”(也就是返回
Access-Control-Allow-Origin: https://a.com)
如果你没看到这句话,你的浏览器(作为守规矩的食客)就会拒绝使用这份酱料,并报错:“跨域请求被阻止了!”
✅ 总结一下(一句话版):
- 浏览器 出于安全,默认禁止网页向不同域名发请求(跨域)
- 服务端(比如通过 Nginx)可以通过在响应头中添加
Access-Control-Allow-Origin来“授权”哪些网站可以跨域访问
# WEB02准备跨域[root@web02 ~]# cat /etc/nginx/conf.d/test.confserver { listen 80; server_name kuayu.com; root /code/test;
location / { index index.html; }}[root@web02 ~]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web02 ~]# systemctl restart nginx[root@web02 conf.d]# cat /code/test/index.html<html lang="en"><head> <meta charset="UTF-8" /> <title>测试跨域访问</title> <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script></head><script type="text/javascript">$(document).ready(function(){ $.ajax({ type: "GET", url: "http://test.kpyun.com", success: function(data) { alert("sucess 成功了!!!"); }, error: function() { alert("fail!!,跨不过去啊,不让进去啊,只能...!"); } });});</script> <body> <h1>跨域访问测试</h1> </body></html>
=================================上面html页面代码里面不能够带#号!'浏览器测试访问'windows的hosts解析10.0.0.8 kuayu.com10.0.0.7 test.kpyun.com
# 配置WEB01允许跨域请求[root@web01 conf.d]# vim 1.test.confserver { listen 80; server_name test.kpyun.com; root /code/test;
location ~ .*\.(html|htm)$ { add_header Access-Control-Allow-Origin http://kuayu.com; # add_header Access-Control-Allow-Origin *; # 这个是允许所有跨域(不推荐生产环境用) add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; }}[root@web01 conf.d]# nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful[root@web01 conf.d]# systemctl restart nginx
'再次测试访问!'
CPU亲和

❌ 没有 CPU 亲和性时(默认情况):进程在不同CPU核心之间来回跳 ---> 频繁切换任务,效率低,还容易出错! 1.每次切换,CPU缓存(Cache)里的数据就失效了(cache miss) 2.CPU 得重新从内存加载数据,速度变慢,性能下降==============================✅ 启用 CPU 亲和性后:给每个 Nginx worker 固定分配一个CPU核心 1.减少上下文切换和缓存失效 2.提高 CPU 利用率和请求处理速度# 以web01举例# 分配4个核心[root@web01 conf.d]# lscpu | grep -i cpu\(s\) | sed -n '1p'CPU(s): 4[root@web01 conf.d]# systemctl restart nginx[root@web01 conf.d]# ps aux | grep nginxroot 4765 0.0 0.1 33796 1124 ? Ss 17:40 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf# 主进程管理着下面4个workerwww 4766 0.0 0.4 45104 4428 ? S 17:40 0:00 nginx: worker processwww 4767 0.0 0.4 45104 4068 ? S 17:40 0:00 nginx: worker processwww 4768 0.0 0.4 45104 4068 ? S 17:40 0:00 nginx: worker processwww 4769 0.0 0.4 45104 4068 ? S 17:40 0:00 nginx: worker process==================================='查看默认的Nginx进程的绑定核心!'[root@web01 conf.d]# ps -eo pid,args,psr|grep [n]ginx 4765 nginx: master process /usr/ 1 # 主进程 4766 nginx: worker process 2 4767 nginx: worker process 2 4768 nginx: worker process 0 4769 nginx: worker process 0# 有一个CPU核心完全偷懒 3# 完全是少一个核心的!
配置CPU亲和方式# 最佳绑定方式,修改nginx启动的work进程为自动[root@web01 ~]# grep -C 1 worker_cpu_affinity /etc/nginx/nginx.confworker_processes auto;# 配置在它的下面就行(主配置文件)worker_cpu_affinity auto;# 配置CPU自动亲和[root@web01 ~]# systemctl restart nginx'再次查看cpu亲和'[root@web01 ~]# ps -eo pid,args,psr|grep [n]ginx 4870 nginx: master process /usr/ 3 4871 nginx: worker process 0 4872 nginx: worker process 1 4873 nginx: worker process 2 4874 nginx: worker process 3# CPU核心被均匀分配!Nginx优化总结
总并发连接 = worker_processes × worker_connections
worker_rlimit_nofile (fd 上限,从内核申请) ==每个 worker 独立== ↓ worker_connections (连接数上限,nginx 自己限)
一个请求最少 2 个 fd
worker_rlimit_nofile = 65535 ← 内核允许这个 worker 打开的最大 fd 数 worker_connections = 32768 ← nginx 允许自己最多维持 32768 个连接 ← 32768 × 2 = 65536 ≈ 65535 ✅
✅ 现在 65535 对单个 worker 来说刚刚好
一个 TCP 连接 ──可以承载──→ 多个 HTTP 请求 (keep-alive)
客户端 ──── TCP 连接 ────→ nginx ──── TCP 连接 ────→ 后端
Nginx FD 占用与连接/请求关系
| 阶段 | fd 占用 |
|---|---|
| 客户端建立 TCP 连接 | fd × 1 |
| nginx 把请求代理到后端,建立上游连接 | fd × 1 |
| 之后该连接上的第 N 个请求 | fd 不增加(复用) |
| 客户端断开,上游连接回连接池 | fd 释放 |
核心结论:
- 2 个 fd 是按连接算,不是按请求算
- 10000 并发连接 ≈ 20000 fd,但这 10000 连接可能同时处理着 50000 个请求(keep-alive 管道)
worker_connections 32768的意思是同时存活 32768 个连接,而不是 32768 个请求——请求量一般远大于连接数
nginx优化总结,nginx通用优化配置文件[root@nginx ~]# cat nginx.confuser www; # nginx进程启动用户worker_processes auto; # 与cpu核心一致即可✅worker_cpu_affinity auto; # cpu亲和
error_log /var/log/nginx/error.log warn; # 错误日志pid /run/nginx.pid;✅worker_rlimit_nofile 65535; # 每个work能打开的文件描述符# 每个 worker 独立'可以参考上面的文件句柄!'
events { use epoll; # 使用epoll高效网络模型(默认的) # 可以不用配置 ✅worker_connections 32768; # 每个worker进程可以同时处理最大连接数 # 一个连接平均占用两个文件描述符}
http { include mime.types; default_type application/octet-stream; charset utf-8,gbk; # 统一使用utf-8字符集
# 定义日志格式 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
#定义json日志格式 log_format json_access '{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_time,' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"url":"$uri",' '"domain":"$host",' '"xff":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"status":"$status"}';
access_log /var/log/nginx/access.log main; # 访问日志
✅server_tokens off; # 禁止浏览器显示nginx版本号 ✅client_max_body_size 20m; # 文件上传大小限制调整 默认1M 'php也有上传限制' # 像论坛,博客...它们才需要进行修改!
# 文件高效传输,静态资源服务器建议打开 ✅sendfile on; ✅tcp_nopush on; # 文件实时传输,动态资源服务建议打开,需要打开keepalive 🔍tcp_nodelay on; 🔍keepalive_timeout 65; # 如果改为0,就是短连接,请求一次断开一次
include /etc/nginx/conf.d/*.conf;}面试题: NGINX优化过什么
1、CPU亲和
2、调整每个worker进程的最大连接数、默认1024
3、文件的高效传输sendfile
4、开启tcp长连接,以及长连接超时时间keepalived
5、开启文件传输压缩gzip
6、开启静态文件expires缓存
7、隐藏nginx版本号
8、配置防盗链、以及跨域访问
9、优雅显示nginx错误页面
10、nginx加密传输https优化
11、防DDOS、cc攻击,限制单IP并发连接,以及http请求
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



