环境:

Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.2 LTS
Release:	16.04
Codename:	xenial

nginx version: openresty/1.11.2.5

8核心 Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz
16GB 物理内存

limit

$ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 64045
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 64045
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

nginx.conf

worker_processes  auto;
worker_cpu_affinity auto;
worker_priority -20;
worker_rlimit_nofile 65535;

events {
    use epoll; # 通常不需要设置, 默认情况下, Nginx 会自动选择最高效的方式的.  http://nginx.org/en/docs/events.html
    worker_connections 4096; 	# 经测试太大和太小最不好, 这个4096的值是比较适合的
    multi_accept off; # 建议为默认值 off, 除非你测试时确认为 on 时有性能提升
    accept_mutex off; # 当使用 epoll 或 listen reuseport 时, 要关掉这个, 当然, 默认情况下也是关闭的(注意, nginx 1.11.3之前默认是开启). http://nginx.org/en/docs/ngx_core_module.html#events
}


http {
	keepalive_timeout  65;
    gzip  on;
    
    upstream bid_server {
		# 竞价的 server
		server 内网IP:端口
        
        # 这时根据你的 bid 服务连接数大小和nginx的情况来决定
		keepalive 512;
	}
	server {
        listen 888 deferred backlog=65535 reuseport;
        server_name localhost 你的服务器网址或IP;
				# 不返回 server 标识, 减少响应数据
				server_tokens off;
				# 完全禁止返回 Server. 上面的只是不显示版本
				more_clear_headers Server;
				
				# 禁止返回 Date
				more_clear_headers Date;
				
				keepalive_requests 10000;
        keepalive_timeout 30;
				
        location / {
                # 配合 upstream 的 keepalive . 参考 https://www.nginx.com/blog/performance-tuning-tips-tricks/
                
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                proxy_pass http://bid_server;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                client_max_body_size 10m;
                client_body_buffer_size 512k;
                proxy_buffer_size 256k;
                proxy_buffers 4 256k;
                proxy_busy_buffers_size 512k;
                proxy_temp_file_write_size 512k;
        }
	}    
}

Server 下面的参数

  • keepalive_requests : 表示每个 keepalive TCP 连接, 最大可处理多少个请求. 这个在高 QPS 下要调高它

OS 层参数

sudo sysctl -a | grep "net.core\|net.ipv4.tcp" | grep "mem"

sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216
sudo sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'
sudo sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'
sudo sysctl -w net.core.netdev_max_backlog=300000

# 网卡队列
sudo ifconfig eth0 txqueuelen 2000
sudo ifconfig eth1 txqueuelen 2000

# 为了配合 listen 的 backlog=65535 参数
sudo sysctl -w net.core.somaxconn=65535

# 降低 TIME_WAIT 数量过多
sudo sysctl -w net.ipv4.tcp_fin_timeout=15

# 禁止自动 cork
sudo sysctl -w net.ipv4.tcp_autocorking=0

# 持久写入文件
# sudo sysctl -p

列出
sudo sysctl -a | grep tcp

关于 backlog 的参数, 可以参考 Socket参数资料收集与整理

检测是否有重传等问题

这时, 可以使用 tcpdump 输出文件, 然后利用 wireshark 分析.

一般这样子话, 可以在 nginx 的 upstream 里, keepalive 要保持好相应的大小.

client -> nginx -> upstream -> tomcat

每种情况都看看, 是否有网络传输问题.

或者

  • netstat -s
  • nstat -a

upstream 的 keepalive 问题

因为默认情况下, Nginx -> 后端的 upstream 服务器是使用 http 1.0 的. 官方文档 . 所以, 为了开启 keepalive , 可以修改该参数.

proxy_http_version 1.0 -> proxy_http_version 1.1

注意, 还要同时设置 proxy_set_header Connection "";

注意, upstream 指令下的 keepalive N; 中的 N, 表示的是每个 Nginx Worker 最大空闲的 keepalive 数量.

通过 tcpdump 可以看到. 如果不设置的话, 默认 nginx 与 upstream 后端的HTTP 通信的请求为

HTTP/1.0
Connection: close

对 Nginx 影响比较大的参数

  • upstream 中的 keepalive 以及设置 proxy_http_version 1.1;proxy_set_header Connection "";
  • worker_cpu_affinity auto;
  • worker_connections

应用程序

最好设置 CPU 亲和性
taskset -cp CPUID(从0开始) 进程 ID

查看亲和性
taskset -cp 进程 ID

减少带宽

  • 减少返回的 body 字节数
    • 压缩
    • JSON 的 null 字段去掉
    • 不必要的字节
    • 使用不同的算法来压缩值. 比如 long -> 36 进制
  • 减少 nignx 不必要的 Header
    • 204 可以只返回 HTTP/1.1 204 No Content\r\n
    • Date 去掉
    • Server 去掉
    • Connection 去掉(http1.1)

Connection 去掉要修改源码重新编译。。

541,542c541,542
<         b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
<                              sizeof("Connection: keep-alive" CRLF) - 1);
---
>         //b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
>          //                    sizeof("Connection: keep-alive" CRLF) - 1);

参考 http-应用估算带宽

资料收集

参考<码出高效>

  • TIME_WAIT : (主动关闭)无法真正释放句柄资源. 可通过 sudo sysctl -w net.ipv4.tcp_fin_timeout=15 来减小超时时间. 默认是 60 . (单位是秒).
  • CLOSE_WAIT : (被动关闭)过多的话, 很可能是程序自身的问题, 比如程序自己忘记关闭连接.

参考资料

https://www.nginx.com/blog/performance-tuning-tips-tricks/