为什么是Nginx而不是apache?
- 轻量级,同样起web服务器,比apache占用更少的内存资源
- 静态处理,Nginx静态处理性能比apache高3倍以上
- 抗并发,Nginx处理请求时异步非阻塞的,而apache则是阻塞型的,在高并发下Nginx能保持低资源低消耗高性能
- 高度模块化的设计,编写模块相对简单
- 社区活跃,各种高性能模块出品迅速
Nginx是如何做到高性能和高可扩展的?
- 事件驱动架构
一个主进程和若干worker进程和helper进程
- 每个worker进程一非阻塞的方式处理多个连接,这减少了上下文切换的次数
- 状态机的调度
Nginx运行工作进程数量优化(worker_processes)
- 如何查看工作进程数据?
ps -ef |grep nginx
- IO密集型号:调整worker进程数=CPU的核心数x2
原作者的话:
As a general rule you need the only worker with large number of worker_connections, say 10,000 or 20,000.
However, if nginx does CPU-intensive work as SSL or gzipping and you have 2 or more CPU, then you may
set worker_processes to be equal to CPU number.
Besides, if you serve many static files and the total size of the files is bigger than memory, then you may
increase worker_processes to utilize a full disk bandwidth.
Igor Sysoev
翻译:
一般一个进程足够了,你可以把连接数设得很大。(worker_processes: 1,worker_connections: 10,000)
如果有SSL、gzip这些比较消耗CPU的工作,而且是多核CPU的话,可以设为和CPU的数量一样。(worker_processes: CPU核心数)
或者要处理很多很多的小文件,而且文件总大小比内存大很多的时候,也可以把进程数增加,以充分利用IO带宽(主要似乎是IO操作有block)
worker_processes 2;
- 调整后的检查进程:ps -ef |grep nginx
Nginx运行CPU亲和力优化(worker_processes、worker_cpu_affinity)
- 为什要绑定Nginx进程到不同的CPU上?
- 如何分配不同的Nginx进程给不同的CPU处理?
nginx默认是没有开启利用多核cpu的配置的。需要通过增加worker_cpu_affinity配置参数来充分利用多核cpu,cpu是任务处理,当计算最费时的资源的时候,cpu核使用上的越多,性能就越好。
查了下,配置nginx多核cpu,worker_cpu_affinity使用方法和范例
2核cpu,开启2个进程
worker_processes 2;
worker_cpu_affinity 01 10;
解释:01表示启用第一个CPU内核,10表示启用第二个CPU内核
worker_cpu_affinity 01 10;表示开启两个进程,第一个进程对应着第一个CPU内核,第二个进程对应着第二个CPU内核。
2核cpu,开启4个进程
worker_processes 4;
worker_cpu_affinity 01 10 01 10;
解释:开启了四个进程,它们分别对应着开启2个CPU内核
4个cpu,开启4个进程
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推
4核cpu,开启2个进程
worker_processes 2;
worker_cpu_affinity 0101 1010;
解释:0101表示开启第一个和第三个内核,1010表示开启第二个和第四个内核;2个进程对应着四个内核;worker_cpu_affinity配置是写在/etc/nginx/nginx.conf里面的;2核是 01,四核是0001,8核是00000001,有多少个核,就有几位数,1表示该内核开启,0表示该内核关闭。
8核cpu,开启8个进程
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推;worker_processes最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。
配置完之后可以重启nginx,用ab工具或者wrk工具,可以进行性能测试,在服务器上执行top,然后按1,就可以看到cpu工作情况,如果多个cpu内核的利用率差不多,就证明nginx已经成功利用了多核cpu,测试结束后,cpu内核的负载都同时降低。
Nginx最大打开文件数优化(worker_rlimit_nofile、worker_connections)
1.默认:worker_connections: 1024
2.调大:worker_connections: 100000,(调大到10万连接)
worker_connections解析
1.connections不是随便设置的,而是与两个指标有重要关联,一是内存,二是操作系统级别的“进程最大可打开文件数”。
2.内存:每个连接数分别对应一个read_event、一个write_event事件,一个连接数大概占用232字节,2个事件总占用96字节,那么一个连接总共占用328字节,通过数学公式可以算出100000个连接数大概会占用 31M = 100000 * 328 / 1024 / 1024,当然这只是nginx启动时,connections连接数所占用的nginx。
3.进程最大可打开文件数:进程最大可打开文件数受限于操作系统,可通过 ulimit -n 命令查询,以前是1024,现在是65535,
nginx提供了worker_rlimit_nofile指令,这是除了ulimit的一种设置可用的描述符的方式。 该指令与使用ulimit对用户的设置是同样的效果。此指令的值将覆盖ulimit的值,如:worker_rlimit_nofile 20960;
设置ulimits:ulimit -SHn 65535
nginx配置worker_rlimit_nofile、worker_connections、ulimit的值的误解纠正
worker_rlimit_nofile = x
误解: ningx worker 同时打开的文件总和(连接)
正确: 整个 nginx 打开文件数的总和,如果不设的话上限就是系统的ulimit –n xxx
ulimit -n x = worker_rlimit_nofile
worker_connections=x
误解: 单 worker 户端连接数
worker_rlimit_nofile >= worker_connections * worker_process
正确:
客户端正向代理数 = worker_rlimit_nofile / 2 >= worker_connections * worker_process /2
客户端可连反向代理数据 = worker_rlimit_nofile /4 >= worker_connections * worker_process /4
Nginx事件处理模型优化(events)
常见的事件处理模型举例
- select:
select库是在linux和windows平台都支持的事件驱动模型库,并且接口的定义也基本相同,只是部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型。
- poll:
Linux的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用–with-poll_module和–without-poll_module这两个指定是否编译select库。
- epoll:
epoll库是Nginx服务器支持的最高性能的事件驱动库之一,epoll是poll的升级版,但是与poll的效率有很大的区别。
epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候再去轮询检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的IO效率不随描述数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。
- rtsig:
一个不常用事件驱动模型,最大队列1024
- kqueue:
用于支持BSD系列平台的最高效事件驱动模型,主要用于FreeBSD4.1及以上版本、OpenBSD2.0及以上版本、NetBSD及以上版本及Mac OS X平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮询操作提供效率。
- /dev/poll:
用于支持unix衍生平台的高效事件驱动模型,主要在Solaris平台、HP/UX,该模型是sun公司在开发Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要监视的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使用/dev/poll事件驱动机制。
- eventport:
该方案也是sun公司在开发Solaris的时候提出的事件驱动库,支持Solaris 10以上的版本,该驱动库能有效防止内核崩溃等情况的发生。
不同的操作系统会采用不同的I/O模型:
Linux下,Nginx使用epoll的I/O多路复用模型
Freebsd下,Nginx使用kqueue的I/O多路复用模型
Solaris下,Nginx使用/dev/poll的I/O多路复用模型
Windows下,Nginx使用icopI/O多路复用模型
Nginx在linux下指定最佳事件处理模型
events {
use epoll;
multi_accept on;
}
Nginx开启高效传输模式(sendfile、tcp_nopush)
- nginx中的“零拷贝”
- sendfile参数详解
Nginx中的sendfile参数用于启用或禁用在两个文件描述符之间直接传递数据的功能。
sendfile是Nginx中的一个配置项,它允许在内核层面上直接将文件数据发送到网络接口,而不需要经过用户空间的缓冲区。这种方式被称为零拷贝(zero-copy),因为它减少了不必要的数据复制,从而提高了文件传输的效率。在默认配置下,Nginx在读取本地文件并进行网络传输时,会先将硬盘文件读取到内核文件缓冲区,然后再从内核文件缓冲区复制到应用缓冲区。最后,数据会从应用缓冲区复制到内核网络缓冲区,再发送到网络接口。这个过程涉及到两次数据复制,而sendfile参数的作用就是减少这个过程中的一次数据复制。
要启用sendfile功能,你可以在Nginx的配置文件中设置:
http {
sendfile on;
}
需要注意的是,虽然sendfile可以提高文件传输效率,但它并不是在所有情况下都适用。例如,如果你的应用程序需要对数据进行某些处理,那么使用sendfile可能不会带来性能上的提升。因此,是否启用sendfile应根据具体的应用场景和需求来决定。此外,sendfile参数在某些操作系统上可能需要特定的内核支持才能正常工作,因此在配置前应确保你的系统支持这一功能。
- tcp_nopush参数详解
在 Nginx 中,tcp_nopush 参数用于控制是否使用 TCP_CORK 选项。TCP_CORK 也称为 “TCP NOPUSH”,是一种 Linux 内核中的 TCP/IP 网络栈优化机制,它允许将多个小的数据包合并成一个大的数据包发送,以减少网络传输的开销。
在默认情况下,Nginx 会尽可能地合并小的数据包,以减少网络传输次数和提高性能。然而,在某些情况下,如客户端请求非常频繁或数据包大小差异较大时,启用 tcp_nopush 可能会降低性能。
要在 Nginx 中设置 tcp_nopush 参数,可以在配置文件中的 http、server 或 location 块中添加以下指令:
tcp_nopush on;
或
tcp_nopush off;
启用 tcp_nopush(设置为 on)时,Nginx 会尽量将多个小的数据包合并成一个大的数据包发送。禁用 tcp_nopush(设置为 off)时,Nginx 会立即发送每个数据包,而不会尝试合并它们。
需要注意的是,tcp_nopush 参数的效果可能因网络条件、操作系统和其他因素而异。因此,在调整此参数时,建议进行性能测试,以找到适合您特定环境的最佳配置。
Nginx连接超时时间优化
- 什么是连接超时?
- 举个例子,某饭店请了服务员招待顾客,但是现在饭店不景气,因此要解雇掉一些服务员,这里的服务员相当于Nginx服务建立的连接
- 当服务器建立的连接没有接收处理请求时候,可以在指定时间内让它超时自动退出。
- 连接超时的作用
- 将无用的连接设置为尽快超时,可以保护服务器的系统资源(CPU、内存、磁盘)
- 当连接很多时,及时断掉那些建立好的但又长时间不做事的连接,以减少其占用的服务器资源
- 如果黑客攻击,会不断地和服务器建立连接,因此设置连接超时以防止大量消耗服务器的资源
- 如果用户请求了动态服务,则Nginx就会建立连接,请求FastCGI服务以及后端MySQL服务,设置连接超时,使得在用户容忍的时间内返回数据
- 连接超时存在的问题
- 服务器建立新连接是要消耗资源的,高并发的时候,连接超时时间不宜设置得过长,否则导致服务器会瞬间资源耗尽
- 有些PHP站点会希望设置成短连接,因为PHP程序建立连接消耗的资源和时间相对要少些
- 有些Java站点会希望设置长连接,因为Java程序建立连接消耗的资源和时间要多一些,这时由语言的运行机制决定的
- 设置连接超时
keepalive_timeout:该参数用于设置客户端连接保持会话的超时时间,超过这个时间服务器会关闭该连接
client_header_timeout: 该参数用于设置读取客户端请求头数据的超时时间,如果超时客户端还没有发送完整的header数据,服务器将返回“Rquest time out(408)”错误
client_body_timeout: 该参数用于设置读取客户端请求主体数据的超时时间,如果超时客服端还没有发送完整的主体数据,服务器将返回“Request time out(408)”错误
- 设置连接超时
send_timeout: 用于指定响应客服端的超时时间,如果超过这个时间,客户度没有任何活动,Nginx将会关闭连接
tcp_nodelay: 默认情况下当数据发送时,内核并不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高I/O性能,但是,在每次只发送很少字节的业务场景中,使用tcp_nodelay功能,等待时间会比较长
fastcgi优化
- 什么是CGI?
CGI又叫通用网关接口;主要是HTTP服务器和其他机器数据通信的工具。一般web Server接受浏览器的请求后,会判断请求资源属静态资源(CSS,JS,JPG)还是动态资源(PHP);一般静态资源直接返回给浏览器渲染即可,而PHP文件之类的动态资源就需要CGI进行处理了
- 为什么选择FastCGI?
FastCGI就是为了提高CGI的性能的,每当有PHP文件请求CGI,CGI每次都会进行环境的初始化,非常消耗性能,响应速度也非常慢;所以FastCGI出现了,FastCGI会启动一个master进程,master主要负责环境的初始化(只要一次),这样每当有php文件请求的时候,只需要将请求传递给worker进程就行了
- FastCGI的各大配置项详解
fastcgi_connect_timeout 240; # Nginx服务器和后端FastCGI服务器连接的超时时间
fastcgi_send_timeout 240; # Nginx允许FastCGI服务器返回数据的超时时间,即在规定时间内后端服务器必须传完所有的数据,否则Nginx将断开这个连接
fastcgi_read_timeout 240; # Nginx从FastCGI服务器读取响应信息的超时时间,表示连接建立成功后,Nginx等待后端服务器的响应时间
fastcgi_buffer_size 64k; # Nginx FastCGI的缓冲区大小,用来读取从FastCGI服务器端收到的第一部分响应信息的缓冲区大小
fastcgi_buffers 4 64k; # 设定用来读取从FastCGI服务器端收到的响应信息的缓冲区大小和缓冲区数量
fastcgi_busy_buffers_size 128k; # 用于设置系统很忙时可以使用的proxy_buffers大小
gzip优化
- Gzip
将响应报文发送至客户端之前可以启用压缩功能,这能够有效地节约带宽,并提高响应至客户端的速度。Gzip压缩可以配置http,server和location模块下
- Gzip配置修改
gzip on; # 开启gzip压缩功能
gzip_min_length 10k; # 设置允许压缩的页面最小字节数;这里表示如果文件小于10个字节,就不用压缩,因为没有意义,本来就很小
gzip_buffers 4 16k; # 设置压缩缓冲区大小,此处设置为4个16k内存作为压缩结果流缓存
gzip_http_version 1.1; # 压缩版本
gzip_comp_level 2; # 设置压缩比率,最小为1,处理速度快,传输速度慢;9为最大压缩比,处理速度慢,传输速度快;这里表示压缩级别,可以是0到9中的任一个,级别越高,压缩就越小,节省了带宽资源,但同时也消耗CPU资源,所以一般折中为6;
gzip_types text/css text/xml application/javascript; # 指定压缩的类型,线上配置时尽可能配置多的压缩类型
gzip_disable “MSIE [1-6].”; # 配置禁用gzip条件,支持正则。此处表示ie6及以下版本不启用gzip(因为ie低版本不支持)
gzip_vary on; # 选择支持vary header;该选项可以让前端的缓存服务器缓存经过gzip压缩的页面;这个可以不写,表示在传送数据时,跟客户端说明我使用了gzip压缩
- Gzip注意点
Nginx的Gzip压缩功能虽然好用,但是下面两类文件资源不太建议启用此压缩功能。
1、图片类型资源(包括视频文件)
2、大文件资源
expires缓存优化
- expires注意点
nginx的缓存设置可以提高网站性能。对于网站的图片,尤其是新闻站,图片一旦发布,改动的可能是非常小的,我们希望在用户访问一次后,图片缓存在用户的浏览器端,且时间比较长的缓存可以用到nginx的expires设置,nginx中设置过期时间。一般在location里设置
- expires优点
- expires可以降低带宽,节约成本
- 同时提升用户访问体验
- 减轻服务器的压力,节约服务器成本,是web服务非常重要的功能
- expires缺点
- 被缓存的页面或数据更新了,用户看到的可能还是旧的内容,反而影响用户体验
- 网站流量统计不准确
- 更新频繁的文件
expires设置
格式:expires 30s; # 30s
expires 30m; # 30分钟
expires 2h;# 2个小时
expires 30d; # 30天
# 客户端对静态内容缓存
location ~*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d; # 30天
root html;
}
内核参数优化
- 修改/etc/sysctl.conf设置相关参数
# 设置系统允许的最大文件描述符数量
fs.file-max = 999999
# 用于设置TCP连接的TIME_WAIT状态的最大数量
net.ipv4.tcp_max_tw_buckets = 6000
# 用于设置系统允许的本地端口范围
net.ipv4.ip_local_prot_range = 1024 65000
# 用于设置是否启用TCP连接的TIME_WAIT状态的快速回收
net.ipv4.ip_tw_recycle = 1
# 用于设置是否启用TCP连接的TIME_WAIT状态的重用
net.ipv4.tcp_tw_reuse = 1
# 用于设置TCP连接的保活时间
net.ipv4.tcp_keepalive_time = 30
# 用于设置是否启用TCP SYN Cookie保护机制
net.ipv4.tcp_syncookies = 1
# 用于设置网络设备的最大队列长度
net.core.netdev_max_backlog = 2622144
# 用于设置TCP连接的SYN队列的最大长度
net.ipv4.tcp_max_syn_backlog = 262144
# 用于设置TCP接收缓冲区的默认大小
net.core.rmem_default = 6291456
更改完后执行sysctl -p 生效
Nginx防盗链
- 防盗链3中解决方法
- 水印,品牌宣传;你的带宽、服务器足够
- 防火墙,直接控制,前提是知道IP来源
- 直接给予404的错误提示
- 设置防盗链的两种配置方案
- 设置防盗链的两种配置方案
location ~*\.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.xxx.com
if ($invalid_referer) {
rewrite ^/ http://www.xxx.com/errror.html;
# return 403;
}
}
- 针对图片目录防止盗链
location /images/ {
alias /data/images/;
valid_referers none bloacked server_names *.xok.la xok.la;
if ($valid_referers) {
return 403;
}
}