我们从以下几个方面来介绍常用的优化措施:
CPU
优化
我们可以通过修改Nginx
中CPU
相关指令来提升服务器的性能。
这里主要涉及到两个指令,分别是worker_processes
和worker_cpu_affinity
指令。
worker_processes
指令
这个指令用来设置Nginx
的worker
进程数量。我们在本系列文章的开始时候就介绍过,Nginx
是一种Master-Worker
机制,真正干活的是worker
进程,所以适当的提高worker
进程的数量,可以提高服务器处理请求的速度。但是worker
进程的数量也不是越多越好,worker
进程数量太多的话会增加CPU
切换进程的负担,一般建议设置为和当前服务器核心数量相同。
worker_cpu_affinity
指令
我们先看一下affinity
的意思是亲和力
。那么cpu_affinity
就是cpu亲和力
。那么什么是cpu亲和力
呢?
这个概念是对于进程来说的。我们知道,在现代的多核处理器上面,OS
在多次调度同一个进程的时候,可能将进程分配到不同的处理器上面进行处理,这样就可能导致进程的缓存不可用,会增加进程执行的时间。所以就产生了cpu亲和力
这个东西,这个功能可以把一个进程和一个处理核绑定在一起,这样就可以充分利用CPU
的缓存,提高缓存命中率,加快进程的执行速度。
它的值是一个二进制,对应物理核心数量,置1
的那一位表示绑定到该物理核。worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000
缓存控制
对于任何一个优秀的软件来说,都离不开缓存buffer
。在Nginx
中对buffer
处理的方法都比较一致,一般情况下我们设置单个buffer
的大小以及使用buffer
的数量。如果单个buffer
不够,那么继续分配buffer
,直到达到指定数量。如果还不够,还可能使用临时文件来保存。这里就要尽量的避免开辟临时文件,这样可以保证所有的内容都保存在内存中,可以提高响应速度。
我们要合理的评估相关内容的大小,分配适应的缓存。
和buffer
相关的几个常用配置指令如下:
client_max_body_size
:客户端请求服务器最大的body
大小client_body_buffer_size
:Nginx
分配给请求数据的Buffe
r大小,如果请求的数据小于client_body_buffer_size
直接将数据先在内存中存储。如果请求的值大于client_body_buffer_size
小于client_max_body_size
,就会将数据先存储到临时文件中client_header_buffer_size
: 指定用于请求header
的缓存区大小
此外还有很多类似的buffer
大小,功能都是大同小异。
超时时间
这个时间用于控制一些时间参数,比如从客户端接收请求头的时间,接收请求体的时间,反向代理服务器接收请求内容的时间等等。通过对他们设置一些合理的值,可以让一些请求直接结束。
常用的超时时间有下面几个:client_body_timeout
: 客户端和服务器建立连接之后接收一个完整body
体的时间。client_header_timeout
: 服务器接收一个完整的请求header
的时间
默认的操作系统内核参数考虑的是最通用场景,不太符合用于支持高并发访问的Web
服务器的场景,所以需要修改一些操作系统内核参数,使得Nginx可以拥有更高的性能。
优化内核参数
内核有非常多的参数,所以我们在在优化的时候,要根据业务特点来进行调整。在不同的场景下,比如当Nginx
作为静态web
服务器、或者反向代理或者提供压缩服务器的时候,其内核参数的调整都是不同的。下面我们就看看有哪些常用的参数可以提高Nginx
的性能:
文件句柄
我们知道,在Linux
系统中,所有的东西都是文件,对于一个TCP
连接也一样,Linux
使用一个文件句柄来标识一个连接。每个进程可以使用的文件句柄数量是有限的,所以我们要调节这个值用以满足要求,防止因为文件句柄数量达到上限而导致建立TCP
连接失败。
fs.file-max = 999999 # 单进程可以使用的最大文件句柄数量
建连参数
建连队列
建立TCP
连接的时候有两个队列(大家可以查阅相关的文档),通过设置队列的长度,可以加快建连的速度。
net.ipv4.tcp_max_syn_backlog = 8192
这个参数是设置三次握手阶段时候处于SYN
状态的队列大小。
端口号范围
其实这个参数影响的是客户端可以使用的端口号数量,和服务端没有关系。但是我还是要在这里说一下这个参数,因为我们的Nginx
服务器可能会作为客户端去请求其他服务器,这个情况下,该参数就会影响到Nginx
服务器了。
net.ipv4.ip_local_port_range = 1024 65000 # tcp和upd使用的端口号范围
这个值由空格分隔的两部分组成,分别代表start port
和end port
,要把这个值调节的稍微大一点。
TCP
状态参数
我们先看一下TCP
的时序状态转移图:
TIME_WAIT
状态
正常情况下,处于TIME_WAIT
状态的套接字是不能使用的,这是为了防止识别错误的报文。但是如果有大量的套接字处于TIME_WAIT
的话,就会导致服务端的套接字数量不够,所以我们可以让处于这个状态的套接字可以服用。
# 让处于TIME_WAIT状态的套接字可复用
net.ipv4.tcp_tw_reuse = 1
#设置处于TIME_WAIT状态的套接字的最大数量
net.ipv4.tcp_max_tw_buckets = 5000
FIN_WAIT2
状态
net.ipv4.tcp_fin_timeout = 30
设置这个时间也是为了尽快的释放套接字资源。
套接字参数
也有很多选项可以控制套接字相关的性能,我们来简单的了解一下。因为这些配置项都非常的简单易懂。
套接字缓冲区
共有四个常用的参数控制着套接字缓冲区的性能,分别如下:
#内核套接字接受缓存区默认大小
net.core.rmem_default = 6291456
#内核套接字发送缓存区默认大小
net.core.wmem_default = 6291456
#内核套接字接受缓存区较大大小
net.core.rmem_max = 12582912
#内核套接字发送缓存区较大大小
net.core.wmem_max = 12582912
上面几个参数要根据服务器的硬件进行相应的设定。
长连接事件
我把长连接也放到了这个部分,因为我认为因为长连接,所以可以让一个套接字被循环使用,避免了重复建立连接,销毁连接的操作。但是如果一个连接一直没有数据,我们应该及时的把他销毁,避免消耗一个套接字。
# 长连接保持的事件
ner.ipv4.tcp_keepalive_time = 600
Nginx
配置
在这里我们要了解两个一个配置指令,这是 Nginx
专门为防盗链准备的。
valid_referers 指令
$invalid_referer 变量
顾名思义,valid_referers
就是设置一些符合要求的 Referer
。如果遇到我们符合我们设置的 Referer
,那么 $invalid_referer
变量的值就是 0
,否则就是 1
。
所以我们可以在 Nginx
的配置文件中增加下面的代码段:
location ~* \.(jpeg|png|gif|jpg)$ {
valid_referers none www.test.com;
if ($invalid_referer){
return 200 "don't steal my pic";
}
}
这段代码的作用是这样:
如果请求的 Referer
为空,或者为 www.test.com
,那么 $valud_referer
的值是 0
,否则是 1
。
当 $valud_referer
的值是 1
的时候,会返回一个固定的字符串 don't steal my pic
。当然了,真实的线上环境中,应该返回 404
,或者一张其他固定的图片。我们这里是为了测试才这样做的。
OpenResty
的目标是让你的Web
服务直接跑在 Nginx
服务内部,充分利用 Nginx
的非阻塞 I/O
模型,不仅仅对 HTTP
客户端请求,甚至于对远程后端诸如 MySQL
、PostgreSQL
、Memcached
以及 Redis
等都进行一致的高性能响应。