返回介绍

最佳实践 31:安装与优化

发布于 2025-04-20 17:44:42 字数 8584 浏览 0 评论 0 收藏

Nginx 的安装过程比较简单,参照如下命令:

# wget http://nginx.org/download/nginx-1.9.7.tar.gz
# tar zxvf nginx-1.9.7.tar.gz 
# cd nginx-1.9.7
# yum -y install pcre pcre-devel
# ./configure --prefix=/usr/local/nginx --with-pcre  --with-http_stub_status_module --with-http_ssl_module
# make
# make install

其中:

- --with-pcre 在 Nginx 添加对正则表达式的支持。

- --with-http_stub_status_module 添加对状态页面的支持。

- --with-http_ssl_module 在 Nginx 添加对 https 站点的支持。

以下实践基于图 6-2 所示的架构图。

图 6-2 Nginx 反向代理架构图

配置 Nginx 代理后端两台服务器,配置文件 nginx.conf 内容如代码清单 6-1 所示。

代码清单 6-1 初始 Nginx 配置

user  nobody;
worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

error_log  logs/error.log;

pid        logs/nginx.pid;

events {
    use epoll;
    worker_connections  10000;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile       on;
    tcp_nopush     on;
    keepalive_timeout  60;
    gzip  on;
    upstream www {
        server 10.1.6.21;
        server 10.1.6.44;
    }
    server {
        listen       80;
        server_name  localhost;
        charset koi8-r;
        access_log  logs/host.access.log  main;
        location / {
             proxy_set_header Host $host;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_connect_timeout 3;
             proxy_send_timeout 3;
             proxy_read_timeout 3;
             proxy_buffer_size 256k;
             proxy_buffers 4 256k;
             proxy_busy_buffers_size 256k;
             proxy_temp_file_write_size 256k;
             proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
             proxy_max_temp_file_size 128m;
          proxy_pass http://www;
        }

    }
}

Nginx 的核心配置参数

Nginx 的核心配置参数如下:

- worker_processes:配置多少个工作进程,设置为与服务器核心(core)数量相同。

- worker_cpu_affinity(重要优化项):将进程与 CPU 绑定,提高了 Cpu Cache 的命中率,从而减少内存访问损耗,提高程序的速度。

- sendfile:对于静态大文件,启用 sendfile 加速文件读取。

- tcp_nopush:在 Linux socket 上启用 TCP_CORK 选项,和 sendfile 合用,加速大文件读取。

以下是超时相关的设置。

- client_header_timeout:客户端必须在此指定的时间内把请求的 header 传输完成,请设置成 5s 或以下值。对于抵挡慢速攻击有作用。

- client_body_timeout:Nginx 2 次连续读取客户端请求体的超时时间,请设置成 5s 或以下值。

- keepalive_timeout:定义保活时间,一般建议是 60s。

- proxy_connect_timeout:Nginx 连接后端服务器的超时时间,请设置成 5s 或以下值。

- proxy_send_timeout:Nginx 2 次连续向后端服务器发送请求的超时时间,请设置成 5s 或以下值。

- proxy_read_timeout:Nginx 2 次连续读取后端服务器返回的超时时间,请设置成 5s 或以下值。

以上超时时间,对于大型繁忙网站是最重要的调优项目。

请参照业务实际需求按照推荐值进行微调。

Nginx 负载均衡算法

在 Nginx 中,反向代理的负载均衡算法有以下 3 种。

- 轮询:不同的后端服务器按照请求轮询访问。

- 最小连接数:下一个请求被转发到当前活动连接数最小的服务器。

- IP 哈希:基于客户端 IP 来哈希,定位到该客户端需要被调度到的后端服务器。

Nginx Proxy 协议的选择

Nginx 反向代理 HTTP 协议时,默认使用的是 HTTP 1.0 去后端服务器获取响应内容,再返回给客户端。

HTTP 1.0 和 HTTP 1.1 的一个重要区别是前者不支持 HTTP Keep-Alive。

以最佳实践 26 中的配置为例,使用 webbench( http://home.tiscali.cz:8080/~cz210552/webbench.html )进行压力测试时可以看到在 Web1 服务器上:

#  netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t", state[key]}'
TIME_WAIT            23704 #注意 TIME_WAIT 值非常高
FIN_WAIT1            18
ESTABLISHED       18
# netstat -an |more
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address        Foreign Address         State      
tcp     0      0 0.0.0.0:5666            0.0.0.0:*               LISTEN      
tcp     0      0 0.0.0.0:8649            0.0.0.0:*               LISTEN      
tcp     0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      
tcp     0      0 10.1.6.21:80            10.1.6.28:52200         SYN_RECV    
tcp     0      0 10.1.6.21:80            10.1.6.28:52201         SYN_RECV    
tcp     0      0 0.0.0.0:38422           0.0.0.0:*               LISTEN      
tcp     0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      
tcp     0      0 10.1.6.21:80           10.1.6.28:53257          
TIME_WAIT #TIME_WAIT 的情况

同时在 Nginx1 的服务器上,看到有如下的报错信息,显示 Nginx 连接后端服务器失败:

2015/12/08 11:24:34 [error] 20137#0: *3293812 upstream timed out (110: Connection timed out) while connecting to upstream, client: 10.1.6.38, server: localhost, request: "GET /index.html HTTP/1.0", upstream: "http://10.1.6.44:80/index.html", host: "10.1.6.28"

看一下 TIME_WAIT 状态的产生过程,如图 6-3 所示。

图 6-3 TIME_WAIT 状态演进图

由图 6-3 可以看出后端服务器主动关闭了连接,未使用 Keep-Alive。

后端服务器主动关闭连接的动作,是由 Nginx1 的特殊 HTTP Header 引起的(文件:Nginx_proxy_without_Keep-Alive.pcap,Frame 15),如图 6-4 所示。

图 6-4 HTTP 1.0 协议反向代理时 Nginx 的网络行为

如图 6-4 所示,Nginx1 在向后端服务器请求时使用了 HTTP 1.0 同时使用 HTTP Header 的 Connection:Close 通知后端服务器主动关闭连接。

后端服务器在处理完请求返回时(文件:Nginx_proxy_without_Keep-Alive.pcap,Frame 19),发送了如下的数据包(TCP 的 flag 设置为 FIN,在应用层设置为“Connection:Close”),如图 6-5 所示。

图 6-5 HTTP 1.0 协议反向代理时后端服务器的网络行为

这样会导致任何一个客户端的请求都在后端服务器上产生一个 TIME_WAIT 状态的连接。

对于以上问题,需要修改 Nginx 使用协议 HTTP 1.1 向后端发送请求,同时支持 Keep-Alive。

这里修改 Nginx 的配置,配置文件如代码清单 6-2 所示。

代码清单 6-2 修改后的 Nginx 配置

user  nobody;
worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

error_log  logs/error.log;

pid        logs/nginx.pid;
events {
    worker_connections  10000;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile       on;
    tcp_nopush     on;
    keepalive_timeout  60;
    gzip  on;
   upstream www {
        keepalive 50; #必须配置,建议值 50-100。
        server 10.1.6.21;
        server 10.1.6.44;
    }
    server {
        listen       80;
        server_name  localhost;
        charset koi8-r;
        access_log  logs/host.access.log  main;
        location / {
             proxy_http_version 1.1; #后端配置支持 HTTP 1.1;必需。
             proxy_set_header Connection ""; #后端配置支持 HTTP 1.1;必需。
             proxy_set_header Host $host;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             proxy_connect_timeout 3;
             proxy_send_timeout 3;
             proxy_read_timeout 3;
             proxy_buffer_size 256k;
             proxy_buffers 4 256k;
             proxy_busy_buffers_size 256k;
             proxy_temp_file_write_size 256k;
             proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
             proxy_max_temp_file_size 128m;
             proxy_pass http://www;
        }

    }
}

通过对比代码清单 6-1 和代码清单 6-2,可以看出,设置 Nginx 代理使用 HTTP 1.1 和 Keep-Alive 时,必须要增加 3 个参数:keepalive 50、proxy_http_version 1.1、proxy_set_header Connection""。

此时通过分析网络行为可以看到(文件:Nginx_proxy_with_Keep-Alive.pcap,Frame 91),配置后 Nginx 重用了后端连接,如图 6-6 所示。

图 6-6 HTTP 1.1 协议反向代理时 Nginx 的网络行为概况

Frame 91 和 Frame 448 使用了同一个连接,如图 6-7 和图 6-8 所示。

图 6-7 HTTP 1.1 协议反向代理时 Nginx 第一次请求时的源端口号

由图 6-8 对比图 6-7 可以知道,2 次使用了同一个 TCP 连接。

图 6-8 HTTP 1.1 协议反向代理时 Nginx 第一次请求时的源端口号

Nginx 中 ip_local_port_range 问题

Nginx 在向后端服务器发起代理请求时,以本地的 IP 作为源 IP、以本地的随机端口号作为源端口号,因此同样存在和第 5 章中 HAProxy 相同的 ip_local_port_range 问题。

具体修改配置的方法,请参考第 5 章中的相关内容。

Nginx 被代理的后端服务器获取客户端 IP

根据上一小节的叙述,在 Nginx 被代理的后端服务器上,使用 netstat 等命令可以看到,和后端服务器建立 TCP 连接的来源 IP 不是客户端的 IP,而是 Nginx 的 IP。因此在后端应用程序需要获取客户端实际来源 IP 地址时,需要使用 Header X-Forwarded-For。

具体代码,请参考第 5 章中的相关内容。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。