`

为重负网络优化 Nginx 和 Node.js

阅读更多
原文:http://linux.cn/forum.php?mod=viewthread&tid=10591&fromuid=1
为重负网络优化 Nginx 和 Node.js
在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对。他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以获得很高的并发,不过,要是大家想在廉价硬件上做到每秒数千以上的请求,还是有一些工作要做的。

这篇文章假定读者们使用NginX的HttpProxyModule来为上游的node.js服务器充当反向代理。我们将介绍Ubuntu 10.04以上系统sysctl的调优,以及node.js应用与NginX的调优。当然,如果大家用的是Debian系统,也能达到同样的目标,只不过调优的方法有所不同而已。

网络调优

如果不先对Nginx和Node.js的底层传输机制有所了解,并进行针对性优化,可能对两者再细致的调优也会徒劳无功。一般情况下,Nginx通过TCP socket来连接客户端与上游应用。

我们的系统对TCP有许多门限值与限制,通过内核参数来设定。这些参数的默认值往往是为一般的用途而定的,并不能满足web服务器所需的高流量、短生命的要求。

这里列出了调优TCP可供候选的一些参数。为使它们生效,可以将它们放在/etc/sysctl.conf文件里,或者放入一个新配置文件,比如/etc/sysctl.d/99-tuning.conf,然后运行sysctl -p,让内核装载它们。我们是用sysctl-cookbook来干这个体力活。

需要注意的是,这里列出来的值是可以安全使用的,但还是建议大家研究一下每个参数的含义,以便根据自己的负荷、硬件和使用情况选择一个更加合适的值。

·········10········20········30········40········50········60········
01.
net.ipv4.ip_local_port_range='1024 65000'
02.
net.ipv4.tcp_tw_reuse='1'
03.
net.ipv4.tcp_fin_timeout='15'
04.
net.core.netdev_max_backlog='4096'
05.
net.core.rmem_max='16777216'
06.
net.core.somaxconn='4096'
07.
net.core.wmem_max='16777216'
08.
net.ipv4.tcp_max_syn_backlog='20480'
09.
net.ipv4.tcp_max_tw_buckets='400000'
10.
net.ipv4.tcp_no_metrics_save='1'
11.
net.ipv4.tcp_rmem='4096 87380 16777216'
12.
net.ipv4.tcp_syn_retries='2'
13.
net.ipv4.tcp_synack_retries='2'
14.
net.ipv4.tcp_wmem='4096 65536 16777216'
15.
vm.min_free_kbytes='65536'
重点说明其中几个重要的。

net.ipv4.ip_local_port_range

为了替上游的应用服务下游的客户端,NginX必须打开两条TCP连接,一条连接客户端,一条连接应用。在服务器收到很多连接时,系统的可用端口将很快被耗尽。通过修改net.ipv4.ip_local_port_range参数,可以将可用端口的范围改大。如果在/var/log/syslog中发现有这样的错误: “possible SYN flooding on port 80. Sending cookies”,即表明系统找不到可用端口。增大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 -s

NginX

随着web服务器的负载逐渐升高,我们就会开始遭遇NginX的某些奇怪限制。连接被丢弃,内核不停报SYN flood。而这时,平均负荷和CPU使用率都很小,服务器明明是可以处理更多连接的状态,真令人沮丧。

经过调查,发现有非常多处于TIME_WAIT状态的连接。这是其中一个服务器的输出:

·········10········20········30········40········50········60········
01.
ss -s
02.
Total: 388 (kernel 541)
03.
TCP:   47461 (estab 311, closed 47135, orphaned 4, synrecv 0, timewait 47135/0), ports 33938
04.

05.
Transport Total     IP        IPv6
06.
*          541       -         -     
07.
RAW        0         0         0     
08.
UDP        13        10        3     
09.
TCP        326       325       1     
10.
INET       339       335       4     
11.
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。

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

·········10········20········30········40········50········60········
1.
upstream backend_nodejs {
2.
server nodejs-3:5016 max_fails=0 fail_timeout=10s;
3.
server nodejs-4:5016 max_fails=0 fail_timeout=10s;
4.
server nodejs-5:5016 max_fails=0 fail_timeout=10s;
5.
server nodejs-6:5016 max_fails=0 fail_timeout=10s;
6.
keepalive 512;
7.
}
我还按它的建议修改了server一节的proxy设置。同时,加了一个 p roxy_next_upstream来跳过故障的服务器,调整了客户端的 keepalive_timeout,并关闭访问日志。配置变成这样:

·········10········20········30········40········50········60········
01.
server {
02.
listen 80;
03.
server_name fast.gosquared.com;
04.

05.
client_max_body_size 16M;
06.
keepalive_timeout 10;
07.

08.
location / {
09.
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
10.
proxy_set_header   Connection "";
11.
proxy_http_version 1.1;
12.
proxy_pass http://backend_nodejs;
13.
}
14.

15.
access_log off;
16.
error_log /dev/null crit;
17.
}
采用新的配置后,我发现服务器们占用的socket 降低了90%。现在可以用少得多的连接来传输请求了。新的输出如下:

·········10········20········30········40········50········60········
01.
ss -s
02.

03.
Total: 558 (kernel 604)
04.
TCP:   4675 (estab 485, closed 4183, orphaned 0, synrecv 0, timewait 4183/0), ports 2768
05.

06.
Transport Total     IP        IPv6
07.
*          604       -         -     
08.
RAW        0         0         0     
09.
UDP        13        10        3     
10.
TCP        492       491       1     
11.
INET       505       501       4
Node.js

得益于事件驱动式设计可以异步处理I/O,Node.js开箱即可处理大量的连接和请求。虽然有其它一些调优手段,但这篇文章将主要关注node.js的进程方面。

Node是单线程的,不会自动使用多核。也就是说,应用不能自动获得服务器的全部能力。

实现Node进程的集群化

我们可以修改应用,让它fork多个线程,在同一个端口上接收数据,从而实现负载的跨越多核。Node有一个cluster模块,提供了实现这个目标所必需的所有工具,但要将它们加入应用中还需要很多体力活。如果你用的是express,eBay有一个叫cluster2的模块可以用。

防止上下文切换

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

我们曾经犯过一个错误,在服务器上部署了两个node.js应用,然后每个应用都开了N-1个进程。结果,它们互相之间抢夺CPU,导致系统的负荷急升。虽然我们的服务器都是8核的机器,但仍然可以明显地感觉到由上下文切换引起的性能开销。上下文切换是指CPU为了执行其它任务而挂起当前任务的现象。在切换时,内核必须挂起当前进程的所有状态,然后装载和执行另一个进程。为了解决这个问题,我们减少了每个应用开启的进程数,让它们公平地分享CPU,结果系统负荷就降了下来:



请注意上图,看系统负荷(蓝线)是如何降到CPU核数(红线)以下的。在其它服务器上,我们也看到了同样的情况。既然总的工作量保持不变,那么上图中的性能改善只能归功于上下文切换的减少。

链接和参考

● 10 Vital Aspects of building a Node.JS application

● Using NginX to avoid node.js load

● Commands to analyse system socket usage

● TCP/IP setting reference

● Linux kernel tuning

英文原文:Optimising NginX, Node.JS and networking for heavy workloads,编译:AlfredCheung
分享到:
评论

相关推荐

    nginx与node.js结合使用 – 运维生存时间1

    在IT运维领域,将Nginx与Node.js结合使用是一种常见的优化策略,旨在提升Web应用的性能和稳定性。本文将详细解析如何配置Nginx与Node.js协同工作,以及这种结合的优势。 首先,Node.js是一个基于Chrome JavaScript...

    nginx-1.21.6.zip和nginx-1.21.6.tar.gz

    Nginx是一款高性能的HTTP和反向代理服务器,广泛应用于Web服务领域,以其高效、稳定、轻量级的特性赢得了广大用户的青睐。...正确安装和配置Nginx,结合适当的运维策略,可以为用户提供高效、安全的Web服务环境。

    为高负载网络优化Nginx和Node.js的方法

    为高负载网络优化Nginx和Node.js,不仅需要关注两者的配置和性能调优,还需要深入理解TCP协议及其在网络层的影响。通过调整内核参数和监控网络状态,可以显著提升服务器应对高并发的能力,确保应用在廉价硬件上的高...

    基于 OpenResty 和 Node.js 的微服务架构实践.pdf

    根据提供的文档信息,本文将详细解析“基于 OpenResty 和 Node.js 的微服务架构实践”这一主题中的关键知识点。此文档主要围绕如何利用 OpenResty 和 Node.js 构建高效、可扩展的微服务架构展开讨论。 ### 一、...

    nginx-1.17.8.tar.gz

    1. **反向代理**:Nginx作为反向代理,可以将来自客户端的请求转发到多个后端服务器,例如Apache、Tomcat或其他Node.js应用。 2. **负载均衡**:利用`upstream`模块,Nginx可以实现基于轮询、权重、IP哈希等多种...

    Node.js开发实战详解源代码

    HTTP简单服务的搭建、Node.js静态资源管理、文件处理、Cookie和Session实践、Crypto模块加密、Node.js与Nginx配合;UDP服务器的搭建、Node.js与PHP之间合作;Node.js的实现机制、Node.js的原生扩展与应用;Node.js的...

    nginx-1.21.6安装包

    5. **URL重写**:Nginx可以通过配置文件实现URL重定向和重写,有助于优化SEO和提高用户体验。 6. **限速和限流**:可以通过限制连接数、带宽等方式,防止DDoS攻击和恶意访问,保护服务器资源。 7. **缓存服务**:...

    基于Node.js的高并发电商购物系统设计与实现

    Node.js是一个基于Chrome V8引擎的JavaScript运行环境,以其异步非阻塞I/O和事件驱动的特性,非常适合处理大量并发请求。在系统设计中,首先会构建一个高速静态资源服务器,通过CDN(Content Delivery Network)结合...

    nginx-1.21.6及Nginx依赖的rpm安装包

    Nginx-1.21.6是Nginx的一个特定版本,包含了已知的性能优化和安全修复。 2. **RPM安装包**: RPM是Red Hat Package Manager的缩写,是Linux发行版如CentOS中的软件包管理器。RPM用于安装、升级、查询和卸载软件,...

    nginx-1.9.8.zip

    在了解了Nginx的基本概念和操作流程后,你将能够更好地管理和优化你的Web服务器,提升网站的性能和稳定性。记住,Nginx的灵活性和可扩展性使得它在各种复杂环境中都能发挥出色的作用,是现代Web服务不可或缺的一部分...

    node.js+mysql博客全栈系统源码.zip

    在现代Web开发中,Node.js以其高效的非阻塞I/O模型和JavaScript的全栈能力,成为构建后端服务的热门选择。结合MySQL作为关系型数据库,可以搭建稳定、高性能的博客系统。本文将深入探讨如何利用Node.js和MySQL构建一...

    nginx-1.19.2.tar.gz

    3. **静态文件处理**:Nginx 在处理静态文件(如图片、CSS、JavaScript等)时非常高效,可以直接从内存中读取,减少磁盘I/O操作。 4. **缓存功能**:Nginx 可以作为HTTP缓存服务器,对频繁访问的资源进行本地缓存,...

    nginx-1.21.4.tar.gz

    nginx-1.21.4.tar.gz

    Node.js-基于socksv5的内网穿透工具

    Node.js 是一个强大的JavaScript运行环境,它允许开发者在服务器端执行JavaScript代码,为Web开发提供了丰富的可能性。在本文中,我们将深入探讨一个基于Node.js的内网穿透工具,该工具利用了socksv5协议,使得内网...

    nginx-1.19.6_nginx-http-flv-module(64位)

    Nginx的更新通常旨在提升服务质量和安全性,确保它能适应不断变化的网络环境和需求。 **Nginx-HTTP-FLV-Module** Nginx-HTTP-FLV-Module是一个专为Nginx设计的扩展模块,主要用于支持HTTP实时流...

    Node.js-node.jslayuibootstrap快速开发企业网站

    在企业级Web应用开发中,Node.js以其非阻塞I/O和事件驱动的特性,成为构建高效、可扩展网络应用的热门选择。LayUI和Bootstrap则是前端开发中常用的两个框架,它们能帮助开发者快速搭建美观且响应式的界面。本教程将...

    docker-workflow, 带有 node.js,Redis和 Nginx的样例 Docker 工作流.zip

    docker-workflow, 带有 node.js,Redis和 Nginx的样例 Docker 工作流 示例 Docker 工作流,带有 node.js,Redis和 Nginx 有关这里知识库中使用的工作流的详细说明,请参考我的博客中的: ...

Global site tag (gtag.js) - Google Analytics