宝哥软件园

用Node.js和Nginx实现高负载网络

编辑:宝哥软件园 来源:互联网 时间:2021-09-09

在构建高吞吐量web应用的话题上,NginX和Node.js是完美的搭配。它们都是基于事件驱动模型设计的,可以轻松突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以实现高并发了,但是如果你想在便宜的硬件上每秒做几千个请求,还有一些工作要做。

本文假设读者使用NginX的HttpProxyModule作为上游node.js服务器的反向代理。我们将介绍在Ubuntu 10.04及以上版本上sysctl的调优,以及node.js应用和NginX的调优。当然,如果使用Debian系统,可以达到同样的目的,但是调优方法不同。

网络调谐

如果不先了解Nginx和Node.js的底层传输机制,并有针对性地进行优化,仔细调整可能是徒劳的。一般情况下,Nginx通过TCP套接字连接客户端和上游应用。

我们的系统对TCP有很多阈值和限制,这些都是由内核参数设置的。这些参数的默认值通常是出于一般目的而确定的,不能满足web服务器高流量和短寿命的要求。

这里有一些调整TCP的候选参数。为了使它们有效,您可以将它们放在/etc/sysctl.conf文件中,或者将它们放在新的配置文件中,如/etc/sysctl.d/99-tuning.conf,然后运行sysctl -p让内核加载它们。我们用sysctl-cookbook来做这个手工工作。

需要注意的是,此处列出的值可以安全使用,但建议您研究每个参数的含义,以便根据自己的负载、硬件和使用情况选择更合适的值。

复制代码如下: net . IP v4 . IP _ local _ port _ range=' 102465000 ' net . IP v4 . TCP _ tw _ reuse=' 1 ' net . IP v4 . TCP _ fin _ time out=' 15 ' net . core . net dev _ max _ backlog=。rmem _ max=' 16777216 ' net . core . somaxcon=' 4096 ' net . core . wmem _ max=' 16777216 ' net . IP v4 . TCP _ max _ syn _ backlog=' 20480 ' net . IP v4 . TCP _ max _ tw _ bucket=' 400000 ' net . IP v4 . TCP _ no _ metrics _ save=' 1 ' net . IP v4 . TCP _ rmem=' 40999 '

关注几个重要的。

复制代码如下: net . IP v4 . IP _ local _ port _ range

为了服务于上游应用程序的下游客户端,NginX必须打开两个TCP连接,一个用于客户端,一个用于应用程序。当服务器接收到许多连接时,系统的可用端口将很快耗尽。可以通过修改net.ipv4.ip_local_port_range参数来扩大可用端口的范围。如果错误:”可能在端口80上出现syn泛洪。发送cookies”在/var/log/syslog中找到,这意味着系统找不到可用的端口。可以通过增加net.ipv4.ip_local_port_range参数来减少错误。

复制代码如下:net.ipv4.tcp_tw_reuse

当服务器需要在大量的TCP连接之间切换时,就会有大量的连接处于TIME_WAIT状态。TIME_WAIT表示连接本身已关闭,但资源尚未释放。将net_ipv4_tcp_tw_reuse设置为1允许内核在安全的情况下尽可能多地回收连接,这比创建新连接要便宜得多。

复制代码如下:net.ipv4.tcp_fin_timeout

这是处于TIME_WAIT状态的连接在回收之前必须等待的最短时间。把它做得更小可以加速回收。如何检查连接状态

使用netstat:

复制代码如下: netstat-tan | awk“{ print $ 6 }”| sort | uniq-c

或者使用ss:

复制代码如下:ss

NginX

随着web服务器负载的不断增加,我们将开始遇到NginX的一些奇怪的限制。连接被中断,内核没有停止报告SYN泛洪。这个时候平均负载和CPU使用量都很小,服务器可以处理更多的连接,真的很让人沮丧。

经过调查,发现TIME_WAIT状态的连接很多。这是其中一台服务器的输出:

复制代码如下: ss-s总计: 388(内核541) TCP : 47461 (estab311,关闭47135,孤立4,synrecv0,时间等待47135/0),端口33938

传输总IP IPv6 * 541-RAW 0 0 0 UDP 13 10 3 TCP 326 325 1 INET 339 335 4 FRAG 0 0 0

有47135个TIME_WAIT连接!而且,从ss可以看出,它们都是封闭连接。这表明服务器已经消耗了大部分可用端口,这也意味着服务器已经为每个连接分配了新的端口。调整网络有助于解决这个问题,但是端口仍然不够。

经过不断的研究,我找到了一个关于上行连接keepalive指令的文档,上面写着:

设置到上游服务器的空闲保持活动连接的最大数量,该数量将保留在工作进程的缓存中。有意思。理论上,此设置是为了通过在缓存的连接上传递请求来最小化连接的浪费。文档中还提到,我们应该将proxy_http_version设置为‘1.1’,并清除‘Connection’头。经过进一步的研究,我发现这是一个好主意,因为HTTP/1.1相比HTTP1.0大大优化了TCP连接的利用率,而Nginx默认使用HTTP/1.0。

按照文档建议修改后,我们的上行配置文件变成了:

复制代码如下:上游后端_ nodejs { server nodejs-3:5016 max _ failed=0 fail _ time out=10s;server nodejs-4:5016 max _ failed=0 fail _ time out=10s;server nodejs-5:5016 max _ failed=0 fail _ time out=10s;server nodejs-6:5016 max _ failed=0 fail _ time out=10s;keepalive 512}

我也根据它的建议修改了服务器部分的代理设置。同时增加p roxy_next_upstream跳过故障服务器,调整客户端keepalive_timeout,关闭访问日志。配置变成这样:

复制代码如下:server { listen 80服务器名fast.gosquared.com;

client _ max _ body _ size 16Mkeepalive _ timeout 10

location/{ proxy_next_upstream错误超时http _ 500 http _ 502 http _ 503 http _ 504;代理集头连接“”;proxy _ http _ version 1.1proxy _ pass后端_ nodejs}

access _注销;error _ log/dev/null crit;}

采用新配置后,我发现服务器占用的套接字减少了90%。现在可以用更少的连接传输请求。新输出如下:

复制代码如下:ss

Total: 558(内核604)TCP: 4675 (estab 485,关闭4183,孤立0,synrecv 0,timewait 4183/0),端口2768

传输总IP IPv6 * 604-RAW 0 0 0 UDP 13 10 3 TCP 492 491 1 INET 505 501 4

Node.js

得益于可以异步处理I/O的事件驱动设计,Node.js可以开箱即用地处理大量连接和请求。虽然还有其他调优方法,但本文将重点介绍node.js的过程

节点是单线程的,不会自动使用多核。也就是说,应用程序不能自动获取服务器的所有功能。

实现节点进程的集群化

我们可以修改应用程序,使其分叉多个线程,在同一个端口接收数据,从而实现跨多个内核的负载。Node有一个集群模块,它提供了实现这个目标的所有必要工具,但是它需要大量的物理工作来将它们添加到应用程序中。如果您正在使用express,易贝有一个名为cluster2的模块。

防止上下文切换

当运行多个进程时,应该确保每个CPU内核同时只忙于一个进程。一般来说,如果CPU有N个内核,我们应该生成N-1个应用进程。这可以确保每个进程都能获得合理的时间片,而剩下的核心则留给内核调度器来运行其他任务。我们还需要确保除Node.js之外的其他任务基本不在服务器上执行,以防止CPU争用。

我们曾经犯过一个错误,在服务器上部署两个node.js应用,然后每个应用打开N-1个进程。结果他们互相抢CPU,导致系统负载急剧增加。虽然我们的服务器都是8核机器,但我们还是能明显感受到上下文切换带来的性能开销。上下文切换是指CPU为了执行其他任务而挂起当前任务的现象。切换时,内核必须挂起当前进程的所有状态,然后加载并执行另一个进程。为了解决这个问题,我们减少了每个应用程序打开的进程数量,让它们公平地共享CPU。结果,系统负载下降了33,360

2015628112206774.png  (802404)

请关注上图,了解系统负载(蓝线)如何下降到CPU内核数(红线)以下。在其他服务器上,我们也看到同样的情况。由于总工作负载保持不变,上图中的性能提升只能归因于上下文切换的减少。

更多资讯
游戏推荐
更多+