跳转到内容

Nginx笔记

nginx安装

linuxmint上使用apt安装

bash
sudo apt update
sudo apt install nginx -y

安装完,默认nginx创建了www-data用户与用户组。

此外,已经自动配置了开机自启动。

默认是一个守护进程(root用户启动),两个worker进程(www-data用户启动)。

常用命令:

bash
sudo systemctl stop nginx
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl restart nginx
sudo systemctl reload nginx

如果需要sudo + nginx命令不用输入密码,则需要编辑 /etc/sudoers 文件来配置:

text
nginxuser ALL=(ALL) NOPASSWD: /usr/sbin/nginx

nginxuser为普通用户。这样以后sudo + nginx命令就不用输入密码了。

此外,还有:

bash
sudo nginx -s reload
sudo nginx -t

等等。

nginx的默认配置文件为:

设置普通用户编辑配置文件不用密码:

text
nginxuser ALL=(ALL) NOPASSWD: /bin/vim /etc/nginx/nginx.conf

或者修改文件属性,改成用户组www-data有修改配置的权限,然后将普通用户加入这个用户组:

bash
sudo chown root:www-data /etc/nginx/nginx.conf
sudo chmod 0664 /etc/nginx/nginx.conf

普通用户加入www-data用户组:

bash
sudo usermod -aG www-data nginxuser

以上操作完之后,需要重启nginx或者重启操作系统,才能最终生效,切记。

测试修改nginx配置文件,比如去掉nginx返回时候的版本信息。

注释掉server_tokenks off;然后reload就生效了。

更好的安装方式

实际上更好地使用nginx,是不用apt来安装nginx,而且不用apt,也不用nginx,而是直接使用源码编译,而且是使用openresty来替换nginx,自由灵活,直接普通用户就可以,编译参数可选的很多。

nginx一些命令

nginx压缩相关

动态压缩

服务器给客户端返回响应时,消耗自身的资源进行实时压缩,保证客户端拿到 gzip 格式的文件,这个模块是默认编译的。

静态压缩

直接将预先压缩过的 .gz 文件返回给客户端,不再实时压缩文件,这个模块需要单独编译。

适用场景

似乎静态压缩存在“压倒性”优势(性能差距50倍),那什么场景适合动态压缩,什么场景适合静态压缩呢?

纯静态不会变化的文件适合静态压缩,提前使用gzip压缩好避免CPU和带宽的浪费。

动态压缩适合API接口返回给前端数据这种动态的场景,数据会发生变化,这时候就需要nginx根据返回内容动态压缩,以节省服务器带宽。

  • 纯文本内容的压缩比很高,因此,纯文本的内容最好进行压 缩,例如:html、js、css、xml、shtml等格式的文件。
  • 被压缩的纯文本文件必须要大于1KB,由于压缩算法的特殊原因,极小的文件压缩后可能反而变大。
  • 图片、视频(流媒体)等文件尽量不要压缩,因为这些文件大多都是经过压缩的,如果再压缩很可能不会减小或减小得很少,甚至还有可能增大,同时压缩时还会消耗大量的CPU、内存资源

参考

nginx事件处理

Nginx的连接处理机制在不同的操作系统中会采用不同的I/O模型,在Linux下,Nginx使用epoll的I/O多路复用模型,在Freebsd中使用kqueue的I/O多路复用模型,在Solaris中使用/dev/poll方式的I/O多路复用模型,在Windows中使用的是icop,等等。

根据Nginx的官方文档建议,也可以不指定事件处理模型,Nginx会自动选择最佳的事件处理模型服务

nginx worker进程

类比:Nginx服务就相当于饭店,网站用户就相当于顾客,Nginx的进程就相当于服务员,饭店要根据客户的流量及并发量来调整接待的服务人员数量,然后根据顾客量变化的监测结果及时调整到最佳的配置。

搭建服务器时,worker进程数最开始的设置可以等于CPU的核数;高流量高并发场合也可以考虑将进程数提高至CPU核数 ×2,具体情况要根据实际的业务来选择,因为这个参数除了要和CPU核数匹配之外,也与硬盘存储的数据及系统的负载有关,设置为CPU的核数是一个好的起始配置,这也是官方的建议。

优化绑定不同的Nginx进程到不同的CPU上: 默认就是比较平均的,可能是Nginx软件自身正在逐渐优化,使其使用多核CPU时更为均衡。

单个进程允许的客户端最大连接数,控制连接数的参数为worker_connections

worker_connections的值要根据具体服务器的性能和程序的内存使用量来指定(单个进程启动使用的内存根据程序来确定)。

在linuxmint虚拟机上,默认给定了配置是:

txt
worker_processes auto;
worker_connections 768;

worker_connections用来设置一个worker process支持的最大并发连接数,这个连接数包括了所有连接,例如:代理服务器的 连接、客户端的连接等,实际的并发连接数除了受worker_connections参数控制之外,还与nginx另一个参数:最大打开文件数worker_rlimit_nofile有关,Nginx总并发连接=worker数量×worker_connections。调整配置Nginx worker进程的最大打开文件数,这个控制连接数的参数为worker_rlimit_nofile,一般可以设置为优化后的ulimit -n的结果。

nginx连接数统计

在默认主机里面加上location或者你希望能访问到的主机里面加上如下配置:

txt
location /status
{
        stub_status on;
        access_log off;
}

重启nginx,在浏览器中输入nginx的地址:http://127.0.0.1/status,即可查看nginx的状态信息:

Active connections – 活跃的连接数量 server accepts handled requests — 总共处理了7个连接 , 成功创建7次握手, 总共处理了36个请求。

  • reading — 正在读取http请求头的连接总数。也有解释为:nginx读取到客户端的Header信息数,倾向前者的解释
  • writing — 正在向客户端发送响应的连接总数。也有解释为:nginx返回给客户端的Header信息数,倾向前者的解释
  • waiting — 当前空闲的http keep-alive连接总数。开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是nginx已经处理完成,正在等候下一次请求的驻留连接(空闲持久连接)。

对以上waiting连接数的理解:

HTTP/1.1(以及 HTTP/1.0 的各种增强版本)允许 HTTP 设备在事务处理结束之后将 TCP 连接保持在打开状态,以便为未来的 HTTP 请求重用现存的连接。在事务处理结束之后仍然保持在打开状态的 TCP 连接被称为持久连接。非持久连接会在每个事务结束之后关闭。持久连接会在不同事务之间保持打开状态,直到客户端或服务器决定将其关闭为止。重用已对目标服务器打开的空闲持久连接,就可以避开缓慢的连接建立阶段。而且,已经打开的连接还可以避免慢启动的拥塞适应阶段,以便更快速地进行数据的传输。

所以,在访问效率高,请求很快被处理完毕的情况下,Waiting数比较多是正常的。

如果reading + writing数较多,则说明并发访问量非常大,正在处理过程中,尤其是writing比较大的时候,需要特别注意。 实际的连接上,现在都是并行连接+持久连接。并行的数量一般是个位数,比如4-6之间,是一个经验值。

waiting数量太高也不大好,毕竟是实在的开销。

管理持久连接时要特别小心,不然就会累积出大量的空闲连接,耗费本地以及远程客户端和服务器上的资源。

网络上有人分享的:

如果reading或writing的值很高,说明正在处理的数据量很大,可能后端的程序处理慢(MYSQL等后端处理),另一个原因很可能就是IO慢,或者客户端的网络慢。

困惑:writing是nginx已经从后端拿到全部响应数据了再返回给客户端,还是后端数据还没全部返回给nginx?这个应该是分段发送的,tcp流。

nginx 499状态码

首先,我们要知道,Nginx 499 是 Nginx 自身定义的状态码,并非任何 RFC 中定义的 HTTP 状态码。它表示的是“Nginx 收到完整的 HTTP request 前(或者已经接收到完整的 request 但还没来得及发送 HTTP response 前),客户端试图关闭 TCP 连接”这种反常情况。

第二,超时时间跟 499 报错数量也有直接关系。如果我们有办法延长消息网关的超时时间,比如从 5 秒改为 50 秒,那么客户端就有比较充足的时间去等待丢失的报文被成功重传,从而在 50 秒内完成 HTTP 事务,499 日志也会少很多。

第三,我们要关注网络延迟对通信的影响。比如客户端发出的两个报文(报文 3 和报文 4)间隔了 3 秒钟,这在网络通信中是个非常大的延迟。而造成这么大延迟的原因,会有两种可能:一是消息网关端本身是在握手后隔了 3 秒才发送了这个报文,属于应用层问题;二是消息网关在握手后立刻发送了这个报文,但在公网上丢失了,微信消息网关就根据“超时重传”的机制重新发了这个报文,并于 3 秒后到达。这属于网络链路问题。

由于上面的抓包是在服务端做的,所以未到达服务器的包自然也不可能抓到,也就是无法确定是具体哪一种原因(客户端应用层问题或网络链路问题)导致,但这并不影响结论。

最后一点,就是我们要清楚,公网上丢包现象不可能完全消失。千分之一左右的公网丢包率属于正常范围。由于客户发送量比较大(这是主要原因),加上微信消息网关设置的 5 秒超时相对比较短(这是次要原因),这两个因素一结合,问题就会在这个案例中被集中暴露出来。

那么,像上面第二点说的那样,设置更长的超时阈值(比如 50 秒)能解决问题吗?相信出错率会降低不少,但是这样新的问题也来了:

  • 消息网关会有更多的资源消耗(内存、TCP 源端口、计算能力等);
  • 消息网关处理事务的平均耗时会增加。

所以,选择 5 秒应该是一个做过权衡后的适中的方案。

而从排查的方法论上来说,对于更广泛的应用层报错日志的排查,我的推荐是这样的:

  • 首先查看应用文档,初步确定问题性质,大体确定排查方向。
  • 通过对比应用日志和抓取的报文,在传输层和网络层寻找可疑报文。在这一步,可以采用以下的比对策略来找到可疑报文:
    • 日志中的 IP 跟报文中的 IP 对应;
    • 日志和报文的时间戳对应;
    • 应用层请求信息和报文信息对应。
  • 结合协议规范和报文现象,推导出根因。

nginx一些参数解释

设置参数:sendfile on;

参数用于开启文件的高效传输模式。同时将tcp_nopush 和tcp_nodelay两个指令设置为on,可防止网络及磁盘I/O阻塞,提升 Nginx工作效率。

sendfile参数作用:激活或禁用sendfile()功能。sendfile()是作用 于两个文件描述符之间的数据复制函数,这个复制操作是发生在内核 之中的,被称为“零复制”,sendfile()比read和write函数要高效 很多,因为,read和wrtie函数要把数据复制到应用层再进行操作。相关控制参数还有sendfile_max_chunk,读者可以自行查询。

tcp_nopush参数作用:激活或禁用Linux上的TCP_CORK socket选项,此选项 仅仅当开启sendfile时才生效,激活这个tcp_nopush参数可以允许把 http response header和文件的开始部分放在一个文件里发布,其积极的作用是减少网络报文段的数量。

tcp_nodelay参数作用:默认情况下当数据发送时,内核并不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高I/O性能。但是, 在每次只发送很少字节的业务场景中,使用tcp_nodelay功能,等待时间会比较长。设置为on,意思是马上发送,默认是off,不会马上发送。

设置参数:keepalive_timeout 60;

用于设置客户端连接保持会话的超时时间为60秒。若超过这个时 间,服务器就会关闭该连接,此数值仅为参考值。参数作用:keep-alive可以使客户端到服务器端已经建立的连接 一直工作不退出,当服务器有持续请求时,keep-alive会使用已经建立的连接提供服务,从而避免服务器重新建立新连接处理请求。

设置参数:client_header_timeout 15;

用于设置读取客户端请求头数据的超时时间。此处的数值为15, 其单位是秒,为经验参考值。

参数作用:设置读取客户端请求头数据的超时时间。如果超过这个时间,客户端还没有发送完整的header数据,那么服务器端将返回 “Request time out(408)”错误,可指定一个超时时间,防止客户 端利用http协议进行攻击。

设置参数:client_body_timeout 15;

用于设置读取客户端请求主体的超时时间,默认值是60。

参数作用:设置读取客户端请求主体的超时时间。这个超时仅仅为两次成功读取操作之间的一个超时,而不是请求整个主体数据的超时时间,如果在这个超时时间内,客户端没有发送任何数据,Nginx将返回“Request time out(408)”错误,默认值是60,这样效果更好。

设置参数:send_timeout 25;

用于指定响应客户端的超时时间。这个超时仅限于两个连接活动 之间的时间,如果超过这个时间,客户端没有任何活动,Nginx将会关 闭连接,默认值为60秒,可以改为参考值25秒。

参数作用:设置服务器端传送HTTP响应信息到客户端的超时时间,这个超时仅仅为两次成功握手后的一个超时,而不是请求整个响应数据的超时时间,如在这个超时时间内,客户端没有接收任何数据,那么连接将被关闭。

设置参数:client_max_body_size 8m;

上传文件大小的限制,具体大小可根据公司的业务做调整,如果不清楚就先设置为8m

参数作用:设置允许的最大客户端请求主体大小,在请求头域有“Content-Length”,如果超过了此配置值,则客户端会收到413错 误,意思是请求的条目过大,有可能浏览器不能正确显示。设置为0则表示禁止检查客户端请求主体大小。此参数对提高服务器端的安全性 有一定的作用。