Nginx 优化
一、性能优化概述
1.我们需要了解的
1、首先需要了解我们当前系统的结构和瓶颈,了解当前使用的是什么,运行的是什么业务,都有哪些服务,了解每个服务最大能支撑多少并发。
比如nginx作为静态资源服务并发是多少,最高瓶颈在哪里,能支持多少qps(每秒查询率)的访问请求,那我们怎么得出这组系统结构瓶颈呢,
比如top查看系统的CPU负载、内存使用率、总得运行进程等,也可以通过日志去分析请求的情况,当然也可以通过我们前面介绍到的stub_status模块查看
当前的连接情况,也可以对线上的业务进行压力测试(低峰期),去了解当前这套系统能承担多少的请求和并发,已做好响应的评估。
这个是我们做性能优化最先考虑的地方。
2、其次我们需要了解业务模式,虽然我们是做性能优化,但每一个性能的优化都是为业务所提供的服务的,我们需要了解每个业务接口的类型,
比如:电商网站中的抢购模式,这种情况下面,平时没什么流量,但到了抢购时间流量会突增。
我们还需要了解系统层次化的结构,比如:我们使用nginx做的是代理、还是动静分离、还是后端直接服务用户,
那么这个就需要我们对每一层做好相应的梳理。以便更好的服务业务。
3、最后我们需要考虑性能与安全,往往注重了性能,但是忽略了安全。往往过于注重安全,对性能又会产生影响。
比如:我们在设计防火墙功能时,检测过于严密,这样就会给性能带来影响。那么如果对于性能完全追求,却不顾服务的安全,
这个也会造成很大的隐患,所以需要评估好两者的关系,把握好两者的孰重孰轻。以及整体的相关性,权衡好对应的点。
1.首先需要了解我们当前系统的结构和瓶颈
2.分析服务的限制和使用情况
3.了解业务模式
4.了解系统层次化的结构
5.考虑性能与安全
2.从哪些方面入手进行优化
OSI 七层模型:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
1.硬件 如果nginx做代理(CPU),静态资源(磁盘读写性能,磁盘大小),动态资源(CPU,内存)
2.网络 带宽,丢包,延迟
3.系统 文件描述符(文件句柄数)
4.应用 服务与服务保持长连接
5.服务 静态资源服务优化
二、压力测试工具(ab)
1.安装ab压力测试工具
[root@web01 ~]# yum install -y httpd-tools
2.测试工具参数
[root@web01 ~]# ab -n 200 -c 2 http://blog.linux.com/
-n 指定请求次数
-c 指定并发数
-k 开启长连接
[root@web01 ~]# ab
Usage: ab [options] [http[s]://]hostname[:port]/path
3.配置nginx静态网站
#配置nginx
[root@web01 conf.d]# vim ab.linux.com.conf
server {
listen 80;
server_name ab.linux.com;
location / {
root /code/ab;
try_files $uri $uri/ @java;
}
location @java {
proxy_pass http://127.0.0.1:8080;
}
}
#配置nginx站点目录文件
[root@web01 conf.d]# echo linux_nginx > /code/ab/index.html
[root@web01 conf.d]# systemctl restart nginx
4.压力测试静态网站
[root@web01 conf.d]# ab -n 10000 -c 200 http://ab.linux.com/index.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking ab.linux.com (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: nginx/1.16.1
Server Hostname: ab.linux.com
Server Port: 80
Document Path: /index.html
Document Length: 12 bytes
Concurrency Level: 200
Time taken for tests: 4.195 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 2420000 bytes
HTML transferred: 120000 bytes
Requests per second: 2383.81 [#/sec] (mean)
Time per request: 83.899 [ms] (mean)
Time per request: 0.419 [ms] (mean, across all concurrent requests)
Transfer rate: 563.36 [Kbytes/sec] received
[root@web01 conf.d]#
5.配置tomcat静态网站
#1.下载或上传tomcat包
[root@web01 ~]# mkdir /service
[root@web01 ~]# cd /service
[root@web01 service]# rz apache-tomcat-8.5.51.tar.gz
#2.解压代码包
[root@web01 service]# tar xf apache-tomcat-8.5.51.tar.gz
#3.配置java环境
1.上传并解压至指定文件夹
[root@web01 service]# tar xf jdk-8u40-linux-x64.gz -C /service/
[root@web01 service]# mv jdk1.8.0_40 java1.8
2.修改添加环境变量
[root@web01 service]# vim /etc/profile.d/java.sh
export JAVA_HOME=/service/java1.8
export JRE_HOME=/service/java1.8/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$PATH:$JAVA_HOME/bin
[root@web01 service]# source /etc/profile
#4.配置tomcat页面
[root@web01 service]# echo "linux_tomcat" > apache-tomcat-8.5.51/webapps/ROOT/index.html
#5.启动tomcat,启动的时候最好看着日志
[root@web01 service]# /service/apache-tomcat-8.5.51/bin/startup.sh && tail -f /service/apache-tomcat-8.5.51/logs/catalina.out
6.压力测试tomcat处理静态网站
[root@web01 service]# ab -n 10000 -c 200 http://ab.linux.com/index.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking ab.linux.com (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: nginx/1.16.1
Server Hostname: ab.linux.com
Server Port: 80
Document Path: /index.html
Document Length: 13 bytes
Concurrency Level: 200
Time taken for tests: 19.267 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 2490000 bytes
HTML transferred: 130000 bytes
Requests per second: 519.01 [#/sec] (mean)
Time per request: 385.349 [ms] (mean)
Time per request: 1.927 [ms] (mean, across all concurrent requests)
Transfer rate: 126.20 [Kbytes/sec] received
7.结论
nginx处理静态资源速度比tomcat快很多
8.影响性能的指标
1、网络
(1)网络的流量
(2)网络是否丢包
(3)这些会影响http的请求与调用
2、系统
(1)硬件有没有磁盘损坏,磁盘速率
(2)系统的负载、内存、系统稳定性
3、服务
(1)连接优化。请求优化
(2)根据业务形态做对应的服务设置
4、程序
(1)接口性能
(2)处理速度
(3)程序执行效率
5、数据库
三、系统性能优化
文件句柄,Linux一切皆文件,文件句柄可以理解为就是一个索引,文件句柄会随着我们进程的调用频繁增加,
系统默认文件句柄是有限制的,不能让一个进程无限的调用,所以我们需要限制每个 进程和每个服务使用多大的文件句柄,文件句柄也是必须要调整的优化参数。
#查看文件句柄数 ulimit -n
#查看一个服务打开多少文件句柄 lsof -p pid
#查看一共打开多少文件句柄数 lsof -i | awk '{print $2}' |wc -l
1.设置文件句柄数
[root@web01 ~]# vim /etc/security/limits.conf
1.系统全局修改文件句柄
# * 代表所有用户,soft代表提醒,hard直接限制,nofile指定打开最大文件数量
* - nofile 65535
* soft nofile 65535
* hard nofile 65535
2.用户局部修改
root - nofile 65535
root soft nofile 65535
root hard nofile 65535
3.进程指定修改
#针对nginx进程,nginx自带配置,nginx.conf
worker_rlimit_nofile 65535;
2.系统层面优化
#调整内核参数:让time_wait状态端口可以重新使用
[root@web01 ~]# sysctl -a #查看所有内核参数
[root@web01 ~]# sysctl -p #查看我们手动配置的内核参数
[root@web01 ~]# vim /etc/sysctl.conf
#重用time_wait状态端口
[root@web01 ~]# sysctl -p
net.ipv4.tcp_tw_reuse = 1
四、代理服务优化
通常nginx作为代理服务,负责转发用户的请求,那么在转发的过程中建议开启HTTP长连接,用于减少握手次数,降低服务器损耗。
1.配置nginx代理开启长连接
upstream tomcat {
server 127.0.0.1:8080;
keepalive 16; #开启长连接
}
server {
listen 80;
server_name daili.linux.com;
location /tomcat/ {
proxy_pass http://tomcat;
proxy_http_version 1.1; #指定http协议为1.1版本
proxy_set_header Connection ""; #清除“connection”头字段
include proxy_params; #调用优化配置
proxy_next_upstream error timeout http_500 http_502 http_503 http_504; #平滑过渡到另一台机器
}
}
2.代理到php服务保持长连接
upstream php_conn {
server 127.0.0.1:9000;
keepalive 16;
}
server {
listen 80;
server_name php.linux.com;
location /php/ {
root /code;
fastcgi_pass php_conn;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#开启长连接
fastcgi_keep_conn on;
#长连接超时时间
fastcgi_connect_timeout 60s;
include fastcgi_params;
}
}
五、静态资源优化
Nginx作为静态资源Web服务器,用于静态资源处理,传输非常的高效
静态资源指的是非WEB服务器端运行处理而生成的文件
静态资源类型 |
种类 |
浏览器渲染 |
HTML、CSS、JS |
图片文件 |
JPEG、GIF、PNG |
视频文件 |
FLV、Mp4、AVI |
其他文件 |
TXT、DOC、PDF、... |
1.静态资源缓存
浏览器缓存设置用于提高网站性能,尤其是新闻网站,图片一旦发布,改动的可能是非常小的,
所以我们希望能否用户访问一次后,图片缓存在用户的浏览器长时间缓存。 浏览器是有自己的缓存机制,
他是基于HTTP协议缓存机制来实现的,在HTTP协议中有很多头信息,那么实现浏览器的缓存就需要依赖特殊的头信息
来与服务器进行特殊的验证,如Expires(http/1.0);Cache-control(http/1.1)。
ETag: "5e6864a0-c"
Last-Modified: Wed, 11 Mar 2020 04:10:08 GMT
Cache-Control: max-age=315360000
Expires: Wed, 02 Jan 2030 12:14:50 GMT
If-Modified-Since: Wed, 11 Mar 2020 04:10:08 GMT
If-None-Match: "5e6864a0-c"
1)浏览器读取缓存流程
1.浏览器请求服务器会先进行Expires、Cache-Control的检查,检查缓存是否过期,如果没有过期则直接从缓存文件中读取。
2.如果缓存过期首先检查是否存在etag,如果存在那么客户端会带着If-None-Match向web服务器请求,
与etag值进行比对,如果值一致则走缓存,如果不一致则不走缓存。
3.如果etag不存在,则进行last-Modified检查,客户端会带着if-Modified-Since向web服务器请求,
与last-Modified进行比对,如果值一致则走缓存,如果不一致则不走缓存。
Last-Modified:服务器上文件的最后修改时间
Etag:服务器上的文件标识
If-None-Match:浏览器上的文件标识
if-Modified-Since:浏览器保存的文件最后修改时间
Expires:本地缓存目录中,文件过期的时间
Cache-control:本地缓存目录中,文件过期的时间
2)缓存时间配置
#语法
#作用:添加Cache-Control Expires头
Syntax: expires [modified] time;
epoch | max | off;
Default: expires off;
Context: http, server, location, if in location
#配置静态资源缓存
[root@web01 static]# vim /etc/nginx/conf.d/huancun.conf
server {
listen 80;
server_name static.linux.com;
root /code/static;
location ~* \.(jpg|png|gif)$ {
expires 7d;
}
}
3)如果不想缓存
#1.开启无痕模式
#2.勾上disable_cache
#3.配置nginx
location ~* \.(css|js|html) {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}
2.静态资源读取
1)文件高效读取配置语法
Syntax: sendfile on | off;
Default: sendfile off;
Context: http, server, location, if in location
2)高效传输(传输效率高)
#将多个数据带个包,一次推送,大文件适合打开此配置,必须要打开sendfile
Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http, server, location
3)长连接传输(传输实时性高)
#来一个数据就推一个数据,需要开启keepalive
Syntax: tcp_nodelay on | off;
Default: tcpnodelay off;
Context: http, server, location
3.静态资源压缩
1)静态资源压缩语法
#gzip传输压缩,传输前压缩,传输后解压
Syntax: gzip on | off;
Default: gzip off;
Context: http, server, location, if in location
#gzip压缩哪些文件
Syntax: gzip_types mime-type ...;
Default: gzip_types text/html;
Context: http, server, location
#gzip压缩比率,加快传输,但压缩本身比较耗费服务器性能
Syntax: gzip_comp_level level;
Default:gzip_comp_level 3-5;
Context: http, server, location
#gzip压缩协议版本,压缩使用在http哪个协议,主流选择1.1版本
Syntax: gzip_http_version 1.0 | 1.1;
Default:gzip_http_version 1.1;
Context: http, server, location
2)压缩实例
[root@web01 conf.d]# vim gzip.conf
server {
listen 80;
server_name gzip.linux.com;
root /code/static;
location ~* \.(jpg|png|gif)$ {
gzip on;
gzip_types image/gif image/jpeg image/png;
gzip_comp_level 5;
gzip_http_version 1.1;
}
location ~* \.(css|js|txt)$ {
gzip on;
gzip_types text/css application/javascript text/plain;
gzip_comp_level 5;
gzip_http_version 1.1;
}
}
[root@web01 conf.d]# ll /code/static/
total 1064
-rw-r--r-- 1 root root 409722 Mar 11 15:35 1.png
-rw-r--r-- 1 root root 670293 Mar 12 09:29 1.txt
-rw-r--r-- 1 root root 5 Mar 11 15:40 index.html
[root@web01 conf.d]#
4.防资源盗链
防盗链,就是指资源被其他网站恶意盗用
基础防盗链设置思路:主要是针对客户端请求过程中所携带的一些Header信息来验证请求的合法性,
比如客户端在请求的过程中都会携带referer信息。优点是规则简单,配置和使用都很方便,
缺点是防盗链所依赖的Referer验证信息是可以伪造的,所以通过referer信息防盗链并非100%可靠,但是他能够限制大部分的盗链情况。
1)防盗链配置语法
Syntax: valid_referers none | blocked | server_name | string ...;
Default: -;
Context: server, location
#none: referer来源头部为空的情况
#blocked: referer来源头部不为空,这些都不以http://或者https://开头
#server_name: 来源头部信息包含当前域名,可以正则匹配
valid_referers none blocked www.linux.com server_names *.example.com example.* ~\.google\.;
if ($invalid_referer) {
return 403;
}
2)配置被盗连的机器
#1.配置nginx
[root@web02 conf.d]# vim beidl.conf
server {
listen 80;
server_name beidl.linux.com;
location / {
root /code;
index index.html;
}
}
#2.上传两张图片
[root@web02 code]# ll
total 123748
-rw-r--r-- 1 www www 657306 Mar 21 2019 1.jpg
-rw-r--r-- 1 www www 475653 Jul 17 2019 2.jpg
#3.重启nginx
3)配置盗链的机器
#1.配置nginx
[root@web01 conf.d]# vim dl.conf
server {
listen 80;
server_name dl.linux.com;
location / {
root /code/dl;
index index.html;
}
}
#2.配置盗链的页面
[root@web01 conf.d]# vim /code/dl/dl.html
<html>
<head>
<meta charset="utf-8">
<title>dl.com</title>
</head>
<body style="background-color:pink;">
<img src="http://beidl.linux.com/1.jpg"/>
</body>
</html>
#3.配置hosts
4)配置防盗链
[root@web02 conf.d]# vim beidl.conf
server {
listen 80;
server_name beidl.linux.com;
root /code;
location / {
index index.html;
}
location ~* \.(jpg|png|gif)$ {
valid_referers none blocked beidl.linux.com;
if ($invalid_referer) {
return 500; #直接返回错误
#rewrite (.*) /2.jpg; #跳转到另一张图片
}
}
}
5)允许匹配多个域名访问
server {
listen 80;
server_name beidl.linux.com;
root /code;
location / {
index index.html;
}
location ~* \.(jpg|png|gif)$ {
valid_referers none blocked beidl.linux.com server_name *.example.com;
if ($invalid_referer) {
return 500;
#rewrite (.*) /2.jpg break;
}
}
}
6)伪造refere信息访问
[root@web01 conf.d]# curl -e "https://www.example.com" -I beidl.linux.com/1.jpg
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Thu, 12 Mar 2020 03:10:32 GMT
Content-Type: image/jpeg
Content-Length: 657306
Last-Modified: Thu, 21 Mar 2019 05:54:55 GMT
Connection: keep-alive
ETag: "5c93272f-a079a"
Accept-Ranges: bytes
[root@web01 conf.d]# curl -e "https://www.google.com" -I beidl.linux.com/1.jpg
HTTP/1.1 500 Internal Server Error
Server: nginx/1.16.1
Date: Thu, 12 Mar 2020 03:10:41 GMT
Content-Type: text/html
Content-Length: 177
Connection: close
六、允许跨域访问
什么是跨域访问,当我们通过浏览器访问a网站时,同时会利用到ajax或其他方式,同时也请求b网站,
这样的话就出现了请求一个页面,使用了两个域名,这种方式对浏览器来说默认是禁止的。注意:跨域限制访问,其实是浏览器的限制!
1.配置被跨域的网站
#1.配置nginx
[root@web02 conf.d]# vim beikuayu.conf
server {
listen 80;
server_name beikuayu.linux.com;
location / {
root /code;
index index.html;
}
}
#2.重启nginx
#3.配置页面
[root@web02 conf.d]# echo "beikuayuwangzhan" > /code/index.html
2.配置跨域网站
#1.配置nginx
[root@web01 conf.d]# vim kuayu.conf
server {
listen 80;
server_name kuayu.linux.com;
location / {
root /code/kuayu;
index index.html;
}
}
#2.配置页面
[root@web01 conf.d]# mkdir /code/kuayu
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</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://beikuayu.linux.com",
success: function(data) {
alert("sucess 卧槽 卧槽 卧槽 成功了!!!");
},
error: function() {
alert("fail!!,跨不过去啊,不让进去啊,只能蹭蹭!");
}
});
});
</script>
<body>
<h1>测试跨域访问</h1>
</body>
</html>
#3.配置hosts
#4.重启nginx
3.配置允许跨域访问
[root@web02 conf.d]# vim beikuayu.conf
server {
listen 80;
server_name beikuayu.linux.com;
root /code;
index index.html;
location ~* \.html$ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
}
}
七、CPU亲和
CPU亲和(affinity)减少进程之间不断频繁切换,减少性能损耗,其实现原理是建CPU核心和Nginx工作进程绑定方式,
把每个worker进程固定到对应的cpu上执行,减少切换CPU的cache miss,获得更好的性能。
1.查看CPU状态
[root@web02 ~]# lscpu
Thread(s) per core: 1
CPU(s): 4
On-line CPU(s) list: 0-3
NUMA node0 CPU(s): 0-3
#一个物理CPU上面有四个内核,分别是 0 1 2 3
2.把worker进程绑定不同核心
#nginx worker进程数量,一定要与核心数保持一致
# 第一种绑定组合方式(不推荐)
worker_processes 12;
worker_cpu_affinity 000000000001 000000000010 000000000100 000000001000 000000010000 000000100000 000001000000 000010000000 000100000000 001000000000 010000000000 10000000000;
# 第二种方式(使用较少)
worker_processes 2;
worker_cpu_affinity 101010101010 010101010101;
# 第三种最佳绑定方式,修改nginx启动的work进程为自动。
worker_processes auto;
worker_cpu_affinity auto;
3.配置cpu亲和后
[root@web02 ~]# vim /etc/nginx/nginx.conf
user www;
worker_processes auto;
worker_cpu_affinity auto;
[root@web02 ~]# ps -eo pid,args,psr|grep [n]ginx
7063 nginx: master process /usr/ 3
7065 nginx: worker process 0
7066 nginx: worker process 1
7067 nginx: worker process 2
7068 nginx: worker process 3
[root@web02 ~]#
八、nginx通用优化配置
[root@nginx ~]# cat nginx.conf
user www; #nginx用户
worker_processes auto; #自动根据CPU核心数启动worker数量
worker_cpu_affinity auto; #开启亲和性
error_log /var/log/nginx/error.log warn; #错误日志
pid /run/nginx.pid; #指定pid文件
worker_rlimit_nofile 35535; #nginx最大打开文件句柄数
events {
use epoll; #使用epoll网络模型
worker_connections 10240; #每个worker处理的连接数
}
http {
include mime.types; #nginx可是别的文件类型
default_type application/octet-stream; #nginx不认识的文件类型就默认下载
charset 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 200m; #文件上传大小限制
sendfile on; #高效传输
tcp_nopush on; #高效传输
tcp_nodelay on; #实时传输
keepalive_timeout 65; #长连接
gzip on; #开启压缩
gzip_disable "MSIE [1-6]\."; #针对IE浏览器不进行压缩
gzip_http_version 1.1; #压缩传输版本
gzip_comp_level 2; #压缩的等级
gzip_buffers 16 8k; #压缩的缓冲区
gzip_min_length 1024; #最小1024字节才开始压缩
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg; #压缩的文件类型
include /etc/nginx/conf.d/*.conf; #虚拟主机配置文件
}
九、nginx安全优化总结
1、CPU亲和、worker进程数、调整nginx进程打开的文件句柄数
2、使用Epool网络模型、调整每个worker进程的最大连接数
3、文件的高效读取sendfile、nopush
4、文件的传输实时性、nodealy
5、开启tcp长连接,以及长连接超时时间keepalived
6、开启文件传输压缩gzip
7、开启静态文件expires缓存
8、异常nginx版本号
9、禁止通过ip地址访问,禁止恶意域名解析,只允许域名访问
10、配置防盗链、以及跨域访问
11、防DDOS、cc攻击,限制单IP并发连接,以及http请求
12、优雅限制nginx错误页面
13、nginx加密传输https优化
14、nginx proxy_cache、fastcgi_cache、uwsgi_cache 缓存,第三方工具(squid、varnish)