故障排查与优化深入:企业级NginxWeb服务优化
nginx性能优化
nginx安全优化
一、Nginx基本安全优化
1.1 调整参数隐藏Nginx软件版本号信息
一般来说,在软件开发中存在漏洞通常与软件版本相关联。这种现象类似于汽车制造过程中所出现的质量缺陷问题:同一批次的产品出现问题则普遍存在;而不同批次的产品则可能表现良好或不良不一的情况出现差异性问题由此可知,在Web服务中我们应采取有效措施来隐藏或避免向访问者展示各类敏感信息(包括但不限于Web软件名称及其版本号等关键信息)。这样可以防止恶意攻击者通过分析这些敏感信息推断出目标服务器是否存在特定漏洞或是某个特定版本的漏洞从而提高Web服务的安全防护能力这就好比武侠小说中的隐身术一旦掌握就能有效地保护自己免受敌人的侵害。
此外 在Linux操作系统环境下想要实现对客户端进行隐身保护可以通过以下步骤操作:首先 请确认当前系统环境下运行curl命令获取Nginx服务端的状态信息 这种方法能够帮助我们及时发现潜在的安全威胁并采取相应的防范措施。
为了实现对Web服务的隐身保护 首先需要了解并获取目标服务器的准确版本号 在Linux操作系统环境下可以通过以下方式获取Nginx服务端的具体版本信息:在终端窗口中运行curl命令 这种方法不仅能够提供必要的版本信息还可以帮助我们更好地判断当前系统是否存在已知的安全漏洞进而采取有效的防护措施。
[root@localhost html]# curl -I 192.168.100.114
HTTP/1.1 200 OK
Server: nginx/1.10.2 #这里清晰的暴露了Web版本号(1.10.2)及软件名称(nginx)
Date: Mon, 21 Jan 2019 10:30:10 GMT
Content-Type: text/html
Content-Length: 4
Last-Modified: Mon, 21 Jan 2019 10:20:25 GMT
Connection: keep-alive
ETag: "5c459ce9-4"
Accept-Ranges: bytes
基于Windows客户端环境,在Web服务中使用浏览器访问时,默认错误信息如图所示。

虽然来自不同的客户端系统但他们都成功地获取了服务器软件名称并确定了服务器版本号这将直接导致Web服务的安全性受到影响为了避免潜在的风险建议采取相应的保护措施以隐藏此类关键信息或采用其他替代名称进行配置类似的做法可以在其他服务器中实施
[root@localhost html]# curl -I www.baidu.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Length: 277
Content-Type: text/html
Date: Mon, 21 Jan 2019 10:32:06 GMT
Etag: "575e1f60-115"
Last-Modified: Mon, 13 Jun 2016 02:50:08 GMT
Pragma: no-cache
Server: bfe/1.0.8.18 #将Web服务软件更名为了bfe,并且版本号改为1.0.8.18(闭源软件名称和版本就无所谓了)
[root@localhost html]# curl -I baidu.com
HTTP/1.1 200 OK
Date: Mon, 21 Jan 2019 10:32:52 GMT
Server: Apache #将Web服务软件更名为了Apache,并且版本号也去掉了
Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
ETag: "51-47cf7e6ee8400"
Accept-Ranges: bytes
Content-Length: 81
Cache-Control: max-age=86400
Expires: Tue, 22 Jan 2019 10:32:52 GMT
Connection: Keep-Alive
Content-Type: text/html
网站如同一般情况,在我们身上也体现了这种做法。实际上,在我们身上还体现了这一现象。此外,在我们身上还体现了一种特性。网站如同一般情况,在我们身上也体现了这种做法。网站如同一般情况,在我们身上也体现了这种做法。
#在Nginx配置文件nginx.conf中的http标签段内加入“server_tokens off;”
[root@localhost nginx]# vim conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
}
[root@localhost nginx]# /usr/local/nginx/sbin/nginx -s reload
该参数被安置于http标签内,并发挥着主要职责去控制http response header中的Web服务版本信息的呈现情况;同时,在错误信息中也需展示Web服务版本相关信息以供参考。
server_tokens参数的官方说明如下:
syntax: server_tokens on|off; #此行为参数语法,on为开启状态,off为关闭状态
default: server_tokens on; #此行意思是不配置该参数,软件默认情况的结果
context: http,server,location #此行为server_tokens参数可以放置的位置参数作用:激活或禁止Nginx的版本信息显示在报错信息和Server的响应首部位置中。
官方资料地址:http://nginx.org/en/docs/http/ngx_http_core_module.html
配置完毕后保存设置,并重新加载配置文件;随后再次通过curl命令进行检查
[root@localhost nginx]# curl -I 192.168.100.114
HTTP/1.1 200 OK
Server: nginx #版本号已经消失
Date: Mon, 21 Jan 2019 10:35:26 GMT
Content-Type: text/html
Content-Length: 4
Last-Modified: Mon, 21 Jan 2019 10:20:25 GMT
Connection: keep-alive
ETag: "5c459ce9-4"
Accept-Ranges: bytes
此时,浏览器的报错提示中没有了版本号,如下图所示,修改成功。

在修改源代码以隐藏Nginx软件名称及版本号之后,在进一步采取措施时就可以将Web服务软件的名字隐匿起来,并将其重命名为另一种Web服务软件名称来迷惑黑客。然而对软件名称进行隐藏或修改的过程由于涉及商业隐私保护等多方面因素通常不会设置成公开的操作选项因此在这种情况下必须对Nginx源代码进行相应的改动以便实现目标
本流程主要包含以下几个关键环节:
首先需要确认目标配置项的位置;
然后根据具体情况选择合适的修改方式;
在实际操作过程中请确保数据的安全性和完整性;
最后及时记录所有操作日志以便追踪回溯;
以上步骤均需严格遵循技术规范以保证系统的稳定运行。
[root@LNMP ~]# cd /usr/src/nginx-1.6.2/src/core/
[root@LNMP core]# ls -l nginx.h
-rw-r--r--. 1 1001 1001 351 Sep 16 2014 nginx.h
[root@LNMP core]# sed -n '13,17p' nginx.h
#define NGINX_VERSION "1.6.2" #修改为想要显示的版本号
#define NGINX_VER "nginx/" NGINX_VERSION
#将nginx修改为想要修改的软件名称。
#define NGINX_VAR "NGINX" #将nginx修改为想要修改的软件名称
#define NGX_OLDPID_EXT ".oldbin"
修改后的结果如下:
[root@LNMP core]# sed -n '13,17p' nginx.h
#define NGINX_VERSION "0.0.0.0"
#define NGINX_VER "yunjisuan/" NGINX_VERSION
#define NGINX_VAR "YUNJISUAN"
#define NGX_OLDPID_EXT ".oldbin"
具体的字符串信息位于
[root@LNMP http]# ls -l /usr/src/nginx-1.6.2/src/http/ngx_http_header_filter_module.c
-rw-r--r--. 1 1001 1001 19321 Sep 16 2014 /usr/src/nginx-1.6.2/src/http/ngx_http_header_filter_module.c
[root@LNMP http]# grep -n 'Server: nginx' ngx_http_header_filter_module.c
49:static char ngx_http_server_string[] = "Server: nginx" CRLF; #修改本行结尾的nginx
通过sed替换修改,后如下:
[root@LNMP http]# grep -n 'Server: nginx' ngx_http_header_filter_module.c
49:static char ngx_http_server_string[] = "Server: nginx" CRLF;
[root@LNMP http]# sed -i 's#Server: nginx#Server: yunjisuan#g' ngx_http_header_filter_module.c
[root@LNMP http]# grep -n 'Server: yunjisuan' ngx_http_header_filter_module.c
49:static char ngx_http_server_string[] = "Server: yunjisuan" CRLF;
修改的下一个版本文件是nginx-1.6.3/src/http/nginx_http_special_response.c,在处理错误页面时,它会控制是否展开敏感信息。这里展示原始代码片段:ngx_http_special_response.c中的第21~30行,如下:
[root@LNMP http]# sed -n '21,30p' ngx_http_special_response.c
static u_char ngx_http_error_full_tail[] =
"<hr><center>" NGINX_VER "</center>" CRLF #此行需要修改
"</body>" CRLF
"</html>" CRLF
;
static u_char ngx_http_error_tail[] =
"<hr><center>nginx</center>" CRLF #此行需要修改
"</body>" CRLF
修改后的结果如下:
[root@LNMP nginx-1.6.2]# sed -n '21,32p' src/http/ngx_http_special_response.c
static u_char ngx_http_error_full_tail[] =
"<hr><center>" NGINX_VER " (Mr.chen 2018-08-26)</center>" CRLF #此行是定义对外展示的内容
"</body>" CRLF
"</html>" CRLF
;
static u_char ngx_http_error_tail[] =
"<hr><center>yunjisuan</center>" CRLF #此行将对外展示的Nginx名字更改为yunjisuan
"</body>" CRLF
"</html>" CRLF
;
1.2.2 第一步是对软件进行修改后的编辑

如前述:Nginx软件名称及其版本号均进行了调整,并附加了本人标识信息。
[root@LNMP conf]# curl -I localhost/xxx/
HTTP/1.1 404 Not Found
Server: yunjisuan/0.0.0.0 #也更改了
Date: Wed, 23 Aug 2017 15:33:54 GMT
Content-Type: text/html
Content-Length: 196
Connection: keep-alive
1.3 更改Nginx服务的默认用户
- 为提升Web服务的安全性水平,则需对软件预设的所有配置参数进行全面调整。
- 现将对Apache Nginx服务器的默认设置进行优化。
- 首先采取措施确认Nginx服务对应的系统权限设置情况:通常情况下,Nginx服务器启动后,默认使用的系统权限设置为nobody,建议逐一排查并确认相关设置是否符合安全规范要求。
[root@LNMP conf]# cd /usr/local/nginx/conf/
[root@LNMP conf]# grep "#user" nginx.conf.default
#user nobody;
为防止黑客推断该Web服务的用户身份而设,在服务器配置中需对现有用户的账号信息进行加密处理,并相应地调整相关参数设置。然而需要注意的是,在此过程中所使用的特殊账号名称必须预先已经被分配好并存在系统中。例如以Nginx用户为例说明:第一步需要对Nginx服务建立新用户的账户结构,并确保其安全配置符合相关要求。
useradd nginx -s /sbin/nologin -M
#不需要有系统登录权限,应当禁止登陆。
有两种方法可以更改Nginx服务默认使用的用户身份。其中一种方法是直接修改配置文件中的相关参数设置(将默认设置为#user nobody;)。
user nginx nginx;
如果注释或未设置相关参数,则默认采用nobody账户作为操作主体;这种做法并不推荐直接使用nobody用户名;通常情况下建议建立一个普通用户的账户来进行配置管理,默认情况下会继承之前建立好的nginx用户的账户设置。
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
#提示:
#前文在编译Nginx服务时,就是这样带着参数的,因此无论配置文件中是否加参数,默认都是nginx用户。
重新加载配置后,确认Nginx服务组件的对应用户
[root@LNMP conf]# ps -ef | grep nginx | grep -v grep
root 52023 1 0 11:30 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 52024 52023 0 11:30 ? 00:00:00 nginx: worker process
在查看修改后的Nginx服务配置后发现,在worker processes进程中所对应的用户均为nginx账户。因此可以推断这两种方法均可用于设置Nginx worker进程中执行的应用程序所使用的用户账户。值得注意的是其主进程中始终运行于root账户。
二,根据参数优化Nginx服务性能
2.1 优化Nginx服务的worker进程个数
在高并发与高访问量的Web服务环境中运行时,在服务端需要预先启动足够的Nginx进程来确保能够迅速响应并处理大量并发客户的请求。
类似于经营一家饭店,在营业前就需要预先招聘一定数量的服务员来接待顾客。然而这里存在一个问题:如果对客流量预估不准确就会导致一些问题发生。例如当服务员数量多于客流量时服务员可能会出现空闲状态无法有效利用人力资源从而增加了运营成本;而当客流量超出预期而服务员数量不足时不仅会导致服务质量下降还可能导致顾客流失影响整体业务发展因此必须根据客流量及处理能力的变化来合理配置服务员数量并在检测到人数变化后及时进行最优配置。
接下来将重点分析如何根据实际需求动态调整Nginx进程的数量。
2.1.1 优化Nginx进程对应的配置
#优化Nginx进程对应Nginx服务的配置参数如下:
worker_processes 1; #指定了Nginx要开启的进程数,结尾数字就是进程个数
该参数的更改作用于Nginx服务中的worker进程中数量的变化。Nginx包含一个Master进程与多个Worker进程,在这种架构下 Master负责管理职责, 而Worker进程中则接收请求并处理客户端连接。
2.1.2 优化Nginx进程个数的策略
- 前面已经详细讲解了worker_processes参数的作用及其设置方法。
- 对于新环境或新部署的情况,在确定Worker_processes参数大小时,请结合实时访问人数进行合理配置。
- 在服务器部署阶段,请将初始Worker进程数目设定为其对应的物理CPU核心数量。
- 这种设定能够有效应对因短期内服务请求激增而导致系统资源紧张的问题。
- 从而降低了系统初始化时间和首次响应时间。
- 当处理高流量和高并发请求时,请考虑将Worker进程数目提升至物理CPU核心数量的两倍。
- 这种做法不仅能够提升初期性能表现,并且还能适应更高负载需求。
- 具体来说,则需要根据实际应用的情况来决定工人数目是否需要相应调整。
- 该参数不仅要与物理CPU核数目匹配,并且还要考虑其他因素如存储容量、I/O吞吐量等的影响。
- 这也是官方推荐的最佳实践之一。
[root@localhost nginx]# vim conf/nginx.conf
worker_processes 2;
...以下省略
[root@localhost nginx]# /usr/local/nginx/sbin/nginx -s reload
[root@localhost nginx]# ps -ef | grep nginx | grep -v grep
root 3810 1 0 05:19 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx #监听nginx的socket进程
www 7075 3810 0 06:16 ? 00:00:00 nginx: worker process
www 7076 3810 0 06:16 ? 00:00:00 nginx: worker process
2.1.3 检索Web服务器的CPU硬件资源信息
[root@LNMP ~]# grep processor /proc/cpuinfo
processor : 0
processor : 1
processor : 2
processor : 3
[root@LNMP ~]# grep processor /proc/cpuinfo | wc -l
4 #表示为1颗CPU四核
[root@LNMP ~]# grep -c processor /proc/cpuinfo
4 #表示为1颗CPU四核
#查看CPU总颗数示例如下:
[root@LNMP ~]# grep "physical id" /proc/cpuinfo
physical id : 0 #物理ID一致,同一颗CPU
physical id : 0 #物理ID一致,同一颗CPU
physical id : 0 #物理ID一致,同一颗CPU
physical id : 0 #物理ID一致,同一颗CPU
[root@LNMP ~]# grep "physical id" /proc/cpuinfo | sort | uniq | wc -l
1 #去重复,表示1颗CPU
(2)通过执行top命令,然后按数字1,即可显示所有的CPU核数,如下:

如果一台服务器拥有1颗CPU核心且4个内核的话,则设置初始配置的方法是通过查看预设好的nginx.conf文件中的worker_processes值来确定所需的数量。具体操作步骤如下:
[root@LNMP ~]# grep worker_processes /usr/local/nginx/conf/nginx.conf
worker_processes 1;
[root@LNMP ~]# sed -i 's#worker_processes 1#worker_processes 4#' /usr/local/nginx/conf/nginx.conf
[root@LNMP ~]# grep worker_processes /usr/local/nginx/conf/nginx.conf
worker_processes 4; #提示可以通过vi修改
#优雅重启Nginx,使修改生效,如下:
[root@LNMP ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@LNMP ~]# /usr/local/nginx/sbin/nginx -s reload
#现在检查修改后的worker进程数量,如下:
[root@LNMP ~]# ps -ef | grep "nginx" | grep -v grep
root 1110 1 0 11:12 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 1429 1110 0 11:33 ? 00:00:00 nginx: worker process
nginx 1430 1110 0 11:33 ? 00:00:00 nginx: worker process
nginx 1431 1110 0 11:33 ? 00:00:00 nginx: worker process
nginx 1432 1110 0 11:33 ? 00:00:00 nginx: worker process
从'worker_processes 4'表明,工人数目为4个. Nginx Master主进程并不属于该参数范围内的进程,而Nginx Master的主进程则作为管理类进程,其主要职责是调度并管理所有的Worker进程中运行的任务(即程序用户相关的任务)。
syntax: worker_processes number; #此行为参数语法,number为数量
default: worker_processes 1; #此行意思是不匹配该参数,软件默认情况数量为1
context: main; #此行为worker_processes参数可以放置的位置
worker_processes用于定义 worker 进程的数量。建议将其设置为其所承载的系统负载情况相关联的具体数值,并推荐其值设定为其所对应的 CPU 核心数量或其两倍(如双倍于 CPU 核心数目)。具体配置应根据实际业务需求来确定。该参数不仅需与 CPU 核心数量一致,并且还需考虑其所承载的系统负载情况密切相关。将该参数设置为其核心数量作为初步配置是一个合理的选择。
2.2 优化绑定不同的Nginx进程到不同的CPU上
- 默认情况下, Nginx多个进程可能运行在同一台CPU或单个CPU的不同核心上, 导致Nginx进程占用硬件资源出现分配不均的情况, 本节的重点在于通过合理分配不同Nginx进程到各自独立的多线程服务器上, 充分发挥多线程服务器的最佳处理能力, 达到高效利用硬件资源的目的。
- 在优化不同的Nginx进程对应不同的CPU配置时, 四核CPU服务器的参数配置参考如下:
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
#worker_cpu_affinity就是配置Nginx进程与CPU亲和力的参数,即把不同的进程分给不同的CPU处理。这里0001 0010 0100 1000是掩码,分别代表第1,2,3,4核CPU,由于worker_processes进程数为4,因此,上述配置会把每个进程分配一核CPU处理,默认情况下进程不会绑定任何CPU,参数位置为main段。
四核和八核CPU服务器的参数配置参考如下:
#八核掩码
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
#四核掩码
worker_cpu_affinity 0001 0010 0100 1000;
worker_cpu_affinity 负责将不同的Worker进程分配到一组特定的CPU上。通过设置bitmask参数来指定哪些CPU被允许供相应的Worker进程使用,默认情况下每个Worker进程都不会被分配任何CPU(采用自动平均分配策略)。
2.2.1 实验环境准备
| 主机名 | IP地址 | 备注 |
|---|---|---|
| Nginx | 192.168.100.114 | nginxWeb |
| 测试机1 | 192.168.100.115 | Webbench压力测试 |
| 测试机2 | 192.168.100.116 | Webbench压力测试 |
#安装webbench
[root@localhost ~]# tar xf webbench-1.5.tar.gz
[root@localhost ~]# cd webbench-1.5
[root@localhost webbench-1.5]# mkdir /usr/local/man
[root@localhost webbench-1.5]# make install clean
cc -Wall -ggdb -W -O -c -o webbench.o webbench.c
webbench.c: In function ‘alarm_handler’:
webbench.c:77:31: warning: unused parameter ‘signal’ [-Wunused-parameter]
static void alarm_handler(int signal)
^
cc -Wall -ggdb -W -O -o webbench webbench.o
install -s webbench /usr/local/bin
install -m 644 webbench.1 /usr/local/man/man1
install -d /usr/local/share/doc/webbench
install -m 644 debian/copyright /usr/local/share/doc/webbench
install -m 644 debian/changelog /usr/local/share/doc/webbench
rm -f *.o webbench *~ core *.core tags
[root@localhost webbench-1.5]# which webbench
/usr/local/bin/webbench
虚拟机开启4核心

2.2.2 第一步:不绑定worker进程进行压力测试
#配置文件如下:(未绑定worker进程)
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
worker_processes 6;
#worker_cpu_affinity 000001 000010 000100 001000 010000 100000;
events {
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
}
#在NginxWeb上执行如下命令:
[root@www ~]# top -u www
top - 09:56:10 up 14 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 140 total, 1 running, 139 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 997980 total, 742104 free, 120292 used, 135584 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 720076 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1357 www 20 0 50640 5664 556 S 0.0 0.6 0:00.05 nginx
1358 www 20 0 50640 5664 556 S 0.0 0.6 0:00.06 nginx
1359 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
1360 www 20 0 50640 5664 556 S 0.0 0.6 0:00.07 nginx
1361 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
1362 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
#在以上界面时按键盘的数值1键,出现如下界面:
top - 09:56:53 up 14 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 140 total, 1 running, 139 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu4 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 997980 total, 742056 free, 120292 used, 135632 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 720028 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1357 www 20 0 50640 5664 556 S 0.0 0.6 0:00.05 nginx
1358 www 20 0 50640 5664 556 S 0.0 0.6 0:00.06 nginx
1359 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
1360 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
1361 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
1362 www 20 0 50640 5664 556 S 0.0 0.6 0:00.08 nginx
在另外的两台测试机器上同时进行压力测试,命令如下:
webbench -c 2000 -t 60 http://192.168.100.114/
结果如下:

2.2.3 第二步:绑定worker进程进行压力测试
#配置文件如下(绑定worker进程)
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
worker_processes 6;
worker_cpu_affinity 000001 000010 000100 001000 010000 100000; #修改本行
events {
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
}
在另外的两台测试机器上同时进行压力测试,命令如下:
webbench -c 2000 -t 60 http://192.168.110.114/
结果如下:

第三阶段:通过调整Nginx配置参数以实现所有worker进程集中分配到CPU3资源。
#配置文件如下所示:
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
worker_processes 6;
worker_cpu_affinity 100000 100000 100000 100000 100000 100000;
events {
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
}

根据上图所示,在worker进程的负载压力主要集中在CPU3这一核心处理单元上。(其中CPU0作为默认使用的核心单元)
2.3 Nginx事件处理模型优化
- Nginx的连接处理机制根据操作系统而异,在特定的操作系统如Linux中采用了epoll的I/O多路复用模式,在FreeBSD上则采用kqueue模式,在Solaris系统中应用的是基于/dev/poll的方式进行I/O管理,在Windows环境下则使用icop模式。
- 根据系统类型来选择合适的事件处理模型是必要的,“use [kqueue|rtsig|epoll|/dev/poll|select|poll]”提供了一系列可选选项。考虑到教学环境运行的是CentOS 6.5 Linux系统这一特定情况,“epoll”成为最佳选择。
proc目录中的文件i被存储在内存中。对应于特定进程id的目录中的内容构成进程资源池,并通过共享内存机制允许线程间资源互换。各进程间相互独立运行以适应服务器端高并发处理的需求但这种模式难以同时支持大量并发请求且运行稳定。
Apache采用单线程模式处理客户端请求不会出现典型的死锁现象。
面对海量数据时Redis建议避免启动过多子进程以防止因资源竞争导致数据损坏的问题。
为了防止同一时刻多个线程争抢相同资源导致系统冲突我们通常会设置线程锁来限制这种行为。
死锁现象发生在两个相互依赖的线程之间:一个试图获取A资源而另一个试图获取B资源,在此状态下双方都无法取得对方所需的资源从而陷入等待僵局。
当Nginx承受高强度并发访问压力时其高性能优势可能会转变为致命缺陷即容易陷入无法恢复的状态。
Tomcat作为常见的应用服务器经常会在这种情况下出现性能瓶颈并影响整体服务可用性
#具体的配置参数如下:
events #events指令是设定Nginx的工作模式及连接数上限
{
use epoll; #use是一个事件模块指令,用来指定Nginx的工作模式。Nginx支持的工作模式有select,poll,kqueue,epoll,rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中。对于Linux系统Linux2.6+内核,推荐选择epoll工作模式,这是高性能高并发的设置
}
根据官方文档的说明可知,在不指定事件处理模型的情况下,默认情况下Nginx系统将自动选择最适合的服务程序。对于采用连接进程的方法而言,默认情况下Nginx无需进行任何操作即可实现最优配置。
请根据具体情况设定Nginx单个进程允许的客户端最大连接数。其中该参数名为worker_connections。worker_connections的具体数值应基于服务器性能以及程序所需的内存容量来确定(其中单个进程所需的内存量由程序本身决定)。如下:
events #events指令是设定Nginx的工作模式和连接数上线
{
worker_connections 20480;
#worker_connections也是个事件模块指令,用于定义Nginx每个进程的最大连接数,默认是1024.最大客户端连接数由worker_processes和worker_connections决定,即Max_client= worker_processes*worker_connections。进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -HSn 65535”或配置相应文件后,worker_connections的设置才能生效。
}
官方文档详细介绍了worker_connections这一配置项及其相关设置。参数定义:worker_connections类型为number类型,默认设置为512个连接。配置位置在events事件处理中。
说明:
用于配置 worker 过程最大并发连接数量的参数是 worker_connections。该数值涵盖的所有类型链接均会被计算在内(如代理服务器与客户端之间的通信),实际可用的 concurrent connections 会受到 worker_connections 参数以及最大打开文件数 worker_rlimit_nofile 的共同影响(参考下文)。在 Nginx 中的整体 concurrent connections 是 worker 数量乘以 worker_connections 参数。
2.5 配置Nginx worker进程最大打开文件数
完成三个步骤,在运行过程中使用的线程数量必须达到Worker processes的数量;同时确保操作系统对文件打开次数的限制值不超过ulimit -n;最后将nginx服务器设置为worker_rlimit_nofile参数以控制其对文件打开次数的限制
下一步优化Nginx worker进程的最大打开文件数;管理连接数量的参数通常称为worker_rlimit_nofile,在实际应用中通常会设置为128或更高。
worker_rlimit_nofile 65535;
#最大打开文件数,可设置为系统优化后的ulimit -HSn的结果
下面是worker_rlimit_nofile number的官方说明:
参数语法:worker_rlimit_nofile number
默认配置:无
放置位置:主标签段
说明:此参数的作用是改变worker processes能打开的最大文件数
参考资料:http://nginx.org/en/docs/ngx_core_module.html
备注:
Linux系统文件最大打开数设置:ulimit -n 65535
永久修改limits.conf主配置文件
[root@localhost ~]# vim /etc/security/limits.conf
2、在主配置文件最后加入下面两句
- soft nofile 65535
- hard nofile 65535
在文件中添加一个特殊标记符'_'后,在运行时会触发特定的安全策略设置。这些设置分别说明了软限制和硬限制对最大可打开文件数的影响。其中'hard'设置对应于操作系统的全局权限控制;而带下划线的部分则意味着这一规则适用于所有用户。将该标记保存到配置文件中时,默认情况下仅root用户拥有访问权限。
在保存该文件之后, 配置不会立即生效. 为了使本次shell会话中的配置立即生效, 我们需要利用ulimit命令更改本次的shell会话设置(当然您如果要重启系统, 我也无能为力).
[root@localhost ~]# ulimit -n 65535
在任务中避免设置至极限以防止服务器承受压力导致崩溃;假设将文件最大打开数量设定为44,444次后将触发502错误提示;然而Nginx则不受此限制能够处理更高的并发请求受限于Linux文件操作限制。
2.5.1 实验环境准备
| 主机名 | IP地址 | 备注 |
|---|---|---|
| Nginx | 192.168.100.114 | nginxWeb |
| 测试机1 | 192.168.100.240 | Webbench压力测试 |
| 测试机2 | 192.168.100.245 | Webbench压力测试 |
2.5.2 修改nginx.conf配置文件
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
worker_processes 6;
worker_cpu_affinity 100000 100000 100000 100000 100000 100000;
worker_rlimit_nofile 65535;
events {
worker_connections 20480;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_tokens off;
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
}
将连接数设定为1核1024。建议在实际操作中多部署几台虚拟机来执行压力测试。否则的话,请确保不仅关注Web服务本身还需扩展资源以避免其率先崩溃的情况。
2.5.2 测试nginx服务连接数的极值
#使用这个命令可以抓取nginx的连接数
#使用这个命令可以抓取nginx的连接数
[root@LNMP nginx]# netstat -antp | grep nginx | wc -l
554
[root@LNMP nginx]# netstat -antp | grep nginx | wc -l
471
逐渐提高压力,抓连接数,看看nginx啥时候down
2.6 启用高效的文件传输模式
#sendfile参数的官方说明如下:
syntax: sendfile on | off; #参数语法
default: sendfile off; #参数默认大小
context: http,server,location,if in location #可以放置的标签段
参数作用:
启用或禁用sendfile()功能的功能。
sendfile()充当两个文件描述符之间数据复制的函数,在内核层中执行这一操作被称为‘零拷贝’技术。相比read和write等应用程序层操作而言,sendfile()更为高效是因为它们需要将数据传输至应用层后再执行处理。
另一个关键参数是sendfile_max_chunk。
同学门可以通过文档获取详细信息。
细节见http://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile
(2)设置参数:tcp_nopush on;
#tcp_nopush参数的官方说明如下:
syntax: tcp_nopush on | off; #参数语法
default: tcp_nopush off; #参数默认大小
context: http,server,location #可以放置的标签段
参数作用:
通过启用或禁用Linux系统中TCP_CORK接口功能进行配置(注意:该功能仅在发送文件时才会启用),该接口参数能够允许将HTTP响应头信息与文件开头部分合并放置在一个文件中(细节请参考官方文档)。通过启用tcp_nopush参数可以有效减少网络报文的数量(从而提高传输效率)。
2.7 优化Nginx连接参数,调整连接超时时间
2.7.1 什么是连接超时
- 先来个比喻吧,某饭店请了服务员招待顾客,但是现在饭店不景气,此时,为多余的服务员发工资使得成本被提高,想减少饭店开支成本就得解雇服务员。
- 这里的服务员就相当于Nginx服务建立的连接,当服务器建立的连接没有接收处理请求时,可在指定的时间内就让它超时自动退出。还有当Nginx和FastCGI服务建立连接请求PHP时,如果因为一些原因(负载高,停止响应),FastCGI服务无法给Nginx返回数据,此时可以通过配置Nginx服务参数使其不会死等,因为前面用过户还等着它返回数据呢,例如,可设置为如果请求FastCGI 10秒内不能返回数据,那么Nginx就中断本次请求,向用户汇报取不到数据的错误。
2.7.2 连接超时的作用
- 将那些无用的网络连接快速配置为超时状态以便释放服务器资源。
- 当有大量网络请求建立时 应及时终止那些长时间未产生任何响应却已存在的连接 以减少资源占用。
- 有时黑客或恶意攻击者试图攻击网站 就会不断地尝试与服务器建立多个连接 这些行为虽然增加了网络负担 但也可能造成大量资源消耗。
- 在LNMP环境配置中 如果用户请求了动态服务 Nginx就会主动建立与FastCGI服务及后端MySQL服务的连接 此时Nginx需要设定一个合理的超时时间 在用户可接受的时间范围内返回数据或者等待后端服务返回结果 最终由业务需求决定具体的超时策略。
- 后端的服务系统同样也会对 incoming connections进行超时控制 以防止资源耗尽并确保系统的稳定运行。
2.7.3 连接超时带来的问题,以及不同程序连接设定知识
- 服务器占用新连接也是会占用资源的。因此,在并行请求过多的情况下(即超时设置时间太短),服务器无法及时响应用户的请求而导致用户体验下降。
- 企业生产中有些PHP程序站点倾向于使用较短连接。这是因为PHP程序相比其他语言(如Java)建立连接时所占用了较少的计算资源和时间。
- 对于Java程序站点,则建议使用较长的连接方式。这是因为Java语言本身的特性决定了其建立连接所需的资源和时间更多一些。
2.7.4 Nginx 连接超时的参数设置
(1)配置客户端保持会话的超时时间参数为 60 秒;
具体用于设定客户端连接保持会话的时间限制。当超出该时间后,服务器将终止该连接;其中此数值可作为参考依据。
keepalive_timeout参数的官方说明如下:
syntax: keepalive_timeout timeout [header_timeout] #参数语法
default: keepalive_timeout 75s; #参数默认大小
context: http,serverr,location #可以放置的标签段
参数作用:
keep-alive能够使客户端与服务器端已有的连接保持长期运行而不退出,在服务器面临持续请求的情况下,keep-alive会利用现有连接来提供服务以缓解因新连接而产生的额外负担
此配置项用于设定keep-alive(即客户端连接在服务器端维持多久后退出),单位为秒,并与HTTP响应Header域中的'Keep-Alive: timeout=time'相关联;这些Header信息也会被客户端浏览器识别并处理;然而,并非所有客户端都能严格遵循服务器端的设置;例如:IE通常会在约60秒后关闭keep-alive连接。更多详细信息,请参阅:http://nginx.org/en/docs/http/ngx_http_core_module.html。(2)配置参数:tcp_nodelay on; 用于启用tcp_ondelay功能以提升I/O性能
#tcp_nodelay参数的标准解释如下:
Syntax section: tcp_nodelay can be configured to either enable or disable.
Default setting for tcp_nodelay is on.
Applicable context includes HTTP requests, server configurations, and location-based services.
参数作用:
默认情况下,在数据发送时系统不会立即发送到内核中可能会延迟一段时间以完成数据包的形成从而提高I/O性能。但在处理每次仅传输少量字节的业务场景中启用该功能会导致等待时间增加。
参数生效条件:
当连接处于keep-alive状态时该选项将被启用或禁用取决于具体配置细节可参考官方文档获取详细信息。
(3)配置参数:client_header_timeout 15;
用于配置读取客户端请求头数据的时间超限值。此处指定的数值15表示以秒为单位的时间长度,默认采用经验参考值获取方式确定该值。
#client_header_timeout参数的官方说明如下:
syntax: client_header_timeout time; #参数语法
default: client_header_timeout 60s; #参数默认大小
context: http,server #可以放置的标签段
参数作用:
该参数用于配置读取客户端请求头数据的时间超限值。当超过该超限值……未发送完整header数据的情况下……服务器将返回"Request timeout (408)"错误提示信息。建议指定一个适当的超时时间……防止客户端滥用HTTP协议进行攻击行为。细节请参考:http://nginx.org/en/docs/http/ngx_http_core_module.html
配置参数 client_body_timeout 设置为15;其中用于表示客户端请求主体的超时时间字段,默认设置为60
#client_body_timeout参数的官方说明如下:
syntax: client_body_timeout time; #参数语法
default: client_body_timeout 60s; #默认60
context: http,server,location #可以放置的标签段
参数作用:
配置读取客户端请求主体的数据连接超时时间。该超时仅指两次成功读取操作之间的重试时间,并不涉及完整请求体数据传输的连接重试时间。其中,默认情况下设置为60秒(单位:秒),具体数值可参考文档http://nginx.org/en/docs/http/ngx_http_core_module.html获取详细信息。
配置参数设置:指定响应客户端的超时时间为25秒;该超时时间仅适用于两个连接活动之间的间隔时间。默认设定为60秒,请根据需要将该值调整为参考值25秒。
#send_timeout参数的官方说明如下:
syntax: send_timeout time; #参数语法
default: send_timeout 60s; #默认值60
context: http,server,location #可以放置的标签段
参数作用:
定义服务器发送HTTP响应至客户端的时间限制,在这种情况下仅指两次成功握手后的时间间隔,并非针对整个响应数据传输的时间限制。若在此时间段内客户端未能接收到任何数据,则会触发连接关闭机制。详细信息可参考http://nginx.org/en/docs/http/ngx_http_module.html。

本节我们将深入探索动态应用中的文件大小限制问题。(2.8)在这一小节中我们将详细讨论并深入分析这种特殊场景下的上传文件大小限制机制及其影响因素
#首先,我们可以在Nginx主配置文件里加入如下参数:
client_max_body_size 8m;
#具体大小根据公司的业务做调整,如果不清楚就先设置为8m把,有关客户端请求主体的解释在HTTP原理一节已经解释过了,一般情况下,HTTP的post方法在提交数据时才会携带请求主体信息。
#client_max_body_size参数的官方说明如下:
syntax: client_max_body_size size; #参数语法
default: client_max_body_size 1m; #默认值1m
context: http,server,location #可以放置的1标签段
参数作用:
配置最大允许的客户端请求体长度,在HTTP协议中,“Content-Length”字段用于指定资源内容的大小。当客户端提交的数据量超出该配置值范围时,“Content-Length”字段会触发413超限错误提示信息。建议将该值设为0,则表示不再检查客户端提交资源的数据量限制;这一参数有助于提升服务器端的安全防护能力,并可参考文档http://nginx.org/en/docs/http/ngx_http_core_module.html获取详细说明
FastCGI参数主要用于配置Nginx向后请求PHP动态服务的相关设置。在Nginx架构中,默认情况下会将静态资源与动态资源分开管理,并通过特定机制实现两者的分离与整合;如图所示的是Nginx FastCGI工作流程的可视化表示:

在本处将涉及Nginx FastCGI客户端向后请求PHP动态引擎服务(php-fpm(FastCGI服务器端))的相关参数。这些参数作为Nginx配置的一部分被详细说明。以下表格列举了Nginx FastCGI常见参数及其说明。


请参考文档... http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_cache中详细说明了FastCGI缓存的相关设置方法。
注:【
[root@LNMP nginx]# cat /usr/local/nginx/conf/nginx.conf
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
worker_rlimit_nofile 65535;
user nginx;
events {
use epoll;
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
tcp_nodelay on;
client_header_timeout 15;
client_body_timeout 15;
send_timeout 15;
log_format main '$remote_addr - $remote_user [$time_local] "$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent""$http_x_forwarded_for"';
server_tokens off;
fastcgi_connect_timeout 240; #Nginx允许fcgi连接超时时间
fastcgi_send_timeout 240; #Nginx允许fcgi返回数据的超时时间
fastcgi_read_timeout 240; #Nginx读取fcgi响应信息的超时时间
fastcgi_buffer_size 64k; #Nginx读取响应信息的缓冲区大小
fastcgi_buffers 4 64k; #指定Nginx缓冲区的数量和大小
fastcgi_busy_buffers_size 128k; #当系统繁忙时buffer的大小
fastcgi_temp_file_write_size 128k; #Nginx临时文件的大小
# fastcgi_temp_path /data/ngx_fcgi_tmp; #指定Nginx临时文件放置路径
fastcgi_cache_path /data/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:512m inactive=1d; #指定Nginx缓存放置路径
# web
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html;
index index.php index.html index.htm;
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
}
access_log logs/web_www_access.log main;
location ~ .*\.(php|php5)?$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_cache ngx_fcgi_cache; #开启fcgi缓存并起名叫ngx_fcgi_cache,很重要,有效降低CPU负载,并且防止502错误发生。
fastcgi_cache_valid 200 302 1h; #指定应答代码的缓存时间,1h=1小时
fastcgi_cache_valid 301 1d; #1d=1天
fastcgi_cache_valid any 1m; #and 1m:将其他应答缓存1分钟
fastcgi_cache_min_uses 1; #待缓存内容至少要被用户请求过1次
fastcgi_cache_use_stale error timeout invalid_header http_500; #当遇到error,timeout,或者返回码500时,启用过期缓存返回用户(返回过期也比返回错误强)
# fastcgi_cache_key http://$host$request_uri;
}
}
upstream www_yunjisuan {
server 192.168.0.225:8000 weight=1;
}
server {
listen 8000;
server_name www.yunjisuan.com;
location / {
# root html;
proxy_pass http://www_yunjisuan;
proxy_set_header host $host;
proxy_set_header x-forwarded-for $remote_addr;
}
access_log logs/proxy_www_access.log main;
}
}

在配置设置上,Nginx的FastCGI配置项与反向代理服务器(proxy)的相关设置极为相近。对于学习者而言,在实际应用中将这两个配置进行对比分析能够加深对相关机制的理解。
2.10 配置Nginx gzip压缩实现性能优化
2.10.1 Nginx gzip压缩功能介绍
该模块采用gzip算法对文件内容进行压缩处理,在将请求内容传输至客户端之前,在服务器端依据一系列特定策略执行数据压缩操作,并有效降低服务器端发送数据量的同时提升客户端接收到数据的速度和实时性,并进而改善用户体验水平。
2.10.2 Nginx gzip压缩的优点
- 提高网站用户体验:向用户提供信息量大的内容后,在单位时间内访问到大小合适的页面会更加高效快速地运行, 带来良好的声誉。
- 降低网站带宽成本:经过数据压缩后再进行传输能够有效减少占用带宽资源, 不过在进行数据压缩的过程中会伴随一定量的CPU开销, 这一消耗通常可以忽略不计。
此功能既能显著提升用户体验, 同时也能为企业节省开支, 实现双赢的局面. 对于几乎所有Web服务器而言, 这是一个极为关键的功能特性. Apache服务器同样具备这一优势.
- 降低网站带宽成本:经过数据压缩后再进行传输能够有效减少占用带宽资源, 不过在进行数据压缩的过程中会伴随一定量的CPU开销, 这一消耗通常可以忽略不计。
2.10.3 需要和不需要压缩的对象
- 由于纯文本内容的压缩比通常较高,在实际应用中我们通常会对其实施压缩处理;包括HTML、JavaScript、CSS、XML以及SHTML等格式的文件。
- 为了确保被压缩的纯文本文件不会因压缩算法的原因导致文件变大,在实际操作中我们建议选择至少1KB大小的文件进行处理。
- 对于图片和视频(流媒体)等类型的文件来说,在不失质量的前提下应尽量避免进行无损或有损压缩。
此压缩功能采用了与早期Apache服务中mod_deflate模块相同的压缩机制,在Nginx中gzip压缩功能主要依赖于ngx_http_gzip_module模块,默认情况下该模块已成功加载并进行配置。相应的压缩参数设置如下:
#######压缩的配置介绍######
gzip on;
#开启gzip压缩功能
gzip_min_length 1k;
#设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取。默认值0,表示不管页面多大都进行压缩。建议设置成大于1K,如果小于1K可能会越压越大。
gzip_buffers 4 16K;
#压缩缓冲区大小。表示申请4个单位为16K的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
gzip_http_version 1.1;
#压缩版本(默认1.1,前端为squid2.5时使用1.0),用于设置识别HTTP协议版本,默认是1.1,目前大部分浏览器已经支持GZIP解压,使用默认即可。
gzip_comp_level 2;
#压缩比率。用来指定gzip压缩比,1压缩比最小,处理速度最快;9压缩比最大,传输速度快,但处理最慢,也比较消耗CPU资源。
gzip_types text/plain application/x-javascript text/css application/xml;
#用来指定压缩的类型,“text/html”类型总是会被压缩,这个就是HTTP原理部分讲的媒体类型。
gzip_vary on;
#vary header支持。该选项可以让前端的缓存服务器缓存经过gzip压缩的页面,例如用Squid缓存经过Nginx压缩的数据。
在不同版本的Nginx配置中,gzipped content types的配置可能会有所不同。以该示例为例,在Nginx 1.6.3版本中是适用的。为了获取相关信息,请参考安装目录中的mime.types文件。
2.10.5 Nginx压缩配置效果检查
通过火狐浏览器搭配firebug扩展以及yslow扩展进行测试与分析gzip压缩效果及expires缓存参数表现。在安装完成后启动yslow扩展并启用监控功能后访问博客网站时即可查看到下图所示的压缩结果:

2.10.6 重要的前端网站调试工具介绍
常见的前端网站调试工具有如下几种:
- Google浏览器(Chrome):在该浏览器中按下F12键即可查看压缩及缓存结果,并且谷歌浏览器(Chrome)还可以直接安装yslow扩展
- 火狐浏览器:在该浏览器中安装Firebug和yslow插件即可实现调试功能(火狐需使用旧版本如V28)
- IE浏览器:在该浏览器中安装HttpWatch扩展即可实现调试功能
2.11 配置Nginx expires缓存实现性能优化
2.11.1 Nginx expires功能介绍
- 简单来说,Nginx expires功能的作用是将用户首次访问的网站内容存储在浏览器本地缓存中,在后续访问时避免从服务器获取这些内容直至缓存过期或被清除。
- 更深入地理解expires功能:该模块允许通过Nginx配置文件指定HTTP ‘Expires’ 头部和 ‘Cache-Control’ 头部的内容,从而控制客户端浏览器缓存的内容及其保时效。
- 这些HTTP头信息告知客户端哪些内容被缓存及其有效性持续时间。如果客户端已存在相应缓存,则会从本地缓存中获取内容而非从服务器获取;客户端会检查本地副本是否过期失效,并决定是否更新内容自服务。
在网站开发与运营过程中,在视频、图片、CSS、JS等网页元素的变更频率较低的情况下(尤其是图片),可以将图片设置为客户浏览器本地缓存365天或3650天的时间段内。同时将CSS、JS、HTML等代码进行本地缓存至10至30天之间。这样,在用户首次访问页面时,在浏览器中会按照设置的过期日期保存相应的文件内容;当用户再次访问类似页面时(如重复的元素),无需重新下载相关内容即可快速加载页面内容;从而显著提升用户的访问速度。此外通过减少用户的请求量以及缓存相关数据量也能有效降低服务器端所需的带宽负担。该功能与Apache服务器中的expires功能具有相似的功能特性
2.11.3 Nginx expires功能优点
- expires能够减少网站带宽消耗并降低成本。
- 提高用户的网站访问速度将改善他们的用户体验。
- 服务器端负载减少了会导致服务器压力得到缓解;同时也能节省运营支出;此外还能减少人力投入。
- 几乎所有Web服务都具备这一功能。
2.11.4 Nginx expires配置详解
前面已经介绍了expires的功能原理,接下来就来配置Nginx expires的功能。这里以location标签为例进行讲解,通过location URI规则将需要缓存的扩展名列出来,然后指定缓存时间。如果针对所有内容设置缓存,也可以不用location。Nginx默认安装了expires功能。
(1)根据文件扩展名进行判断,添加expires功能范例
范例1:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 3650d;
}
该示例表明当用户访问网站URL结尾处的文件并具有上述指定类型的名字时
location ~ .*\.(js|css)$
{
expires 30d;
}
此示例表明,在用户浏览网站中以. js和.css格式命名的文件时,默认设置缓存有效期为30天(即1个月)。 (2)通过分析访问路径中的目录结构增添缓存过期功能的示例 范例3:
location ~ ^/(images|javascript|js|css|flash|media|static)/
{
expires 360d;
}
具体说明如下:当网站URL中包含指定路径(例如images、js、css)时,在服务器端将其内容缓存至客户端360天(即1年)。
2.11.5 Nginx expires 配置效果 检查
采用相同的方式 进行 Nginx expires 配置 和 Nginx gzip 配置 的 检查 过程 是 相同 的。
建议在 执行 测试 之前 先 安装 好 所需 的 软 件 工 具 : 火 狐 浏 览器 和 yslow 插 件 。 启 动 监控 功能 后 , 在 LNMP 部署 的 博客 地 址 上 ( 包含 图 片 、 JavaScript 代 码 和 CSS 样 式 表 ) 就 可 以 观 察 到 如 图 所 示 的 结 果 。

在Linux客户端可通过如下curl命令查看图片URL的缓存header信息:
[root@localhost ~]# curl -I 192.168.0.220:8000
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 30 Aug 2017 02:15:54 GMT
Content-Type: text/html
Content-Length: 18
Connection: keep-alive
Last-Modified: Tue, 29 Aug 2017 19:37:44 GMT
ETag: "59a5c288-12"
Expires: Sat, 09 Sep 2017 02:15:54 GMT #缓存的过期时间
Cache-Control: max-age=864000 #缓存的总时间,单位秒
Accept-Ranges: bytes
2.11.6 Nginx expires功能缺点及解决方法
许多事物都具有双重特性,在完美无缺的理想状态下也难以实现。Nginx的时间限制功能也不例外,在其优点得到充分体现的同时也可能会带来一定的困扰。
一旦网站上的缓存项更新完毕后,在用户端仍然可能看到未更新的内容这将影响用户体验因此需要采取相应的解决方案。
针对这种情况我们可以采取以下措施:
第一,在服务器端对那些频繁需要更改的对象缩短其缓存时间例如将一张节日主题图片设置为1天的有效期这样可以使该图片在下次更新前失效。
第二,在进行网站升级时应该对相关的JavaScript代码CSS样式文件等元素进行重命名这有助于避免后续操作带来的混乱。
通常情况下,网站上的附件不会被直接修改因为它们通常由后台系统管理而只有经过授权的操作人员才有权限对这些文件进行修改。
在升级过程中,前端可能会遇到一些变化特别是在处理JavaScript脚本或者CSS样式文件时需要注意相关资源是否已正确重命名以避免潜在的问题。
2.11.7 企业网站缓存日期以往的案例参考
如果企业的业务规模与网站日均访问量存在差异,则相应地应在服务器端调整网页的缓存期限。
例如,在某些企业的实践中,
- 51CTO:1周
- 新浪:15天
- 京东:25年
- 淘宝:10年
2.11.8 企业网站有可能不希望被缓存的内容
- 广告图片用于广告服务都被存储后难以精确展示。
- 网站流量统计工具基于JS代码存储的流量数据会导致统计结果不够准确。
- 更新频率高的文件如Google logo如果按天保存则仍能带来良好的效果。
三,Nginx日志相关优化与安全
为实现对Nginx access日志的自动轮转功能开发相应的脚本。每当用户发起一次请求时, 大多数软件都会记录用户的访问信息, Nginx服务也未例外。目前, Nginx尚未提供类似于Apache cronolog或rotatelog的日志分段处理功能, 因此运维人员可以通过编写特定的脚本来利用Nginx的信号控制功能或reload机制来实现日志的自动分割和轮转。
日志切割脚本如下:
[root@localhost nginx]# cat /server/scripts/cut_nginx_log.sh
#!/bin/bash
#日志切割脚本可挂定时任务,每天00点整执行
Dateformat=`date +%Y%m%d`
Basedir="/usr/local/nginx"
Nginxlogdir="$Basedir/logs"
Logname="access"
[ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1
[ -f ${Logname}.log ] || exit 1
/bin/mv ${Logname}.log ${Dateformat}_${Logname}.log
$Basedir/sbin/nginx -s reload
[root@localhost nginx]# cat >>/var/spool/cron/root << KOF
#cut nginx access log by Mr.chen
00 00 * * * /bin/bash /server/scripts/cut_nginx_log.sh >/dev/null 2>&1
在实际应用中, 针对负载均衡器的健康检查或特定文件日志(如图片、JavaScript、CSS)无需额外记录, 因为PV统计基于页面计算, 而频繁的日志写入会导致过高的磁盘I/O消耗, 从而影响服务性能。具体的配置方法如下:
location ~ .*\.(js|jpg|JPG|jpeg|JPEG|css|bmp|gif|GIF)$
{
access_log off;
}
#这里用location标签匹配不记录日志的元素扩展名,然后关闭日志
3.3 访问日志的权限设置
假如日志目录为/app/logs,则授权方法如下:
chown -R root.root /app/logs
chmod -R 700 /app/logs
无需在日志目录授予Nginx用户读写权限;然而许多网民忽视了这一问题;他们将该权限错误地分配给了Nginx或Apache;从而形成了潜在的安全隐患。
