1、提高worker连接限制

events {
    worker_connections 100000;
}

提示:缺省为1024

2、优化worker数量

worker_processes auto;

3、配置UpStream连接复用

upstream demo1 {
    server 1.1.1.1:80;
    keepalive 128;
}

4、配置CPU亲和性与进程优化级

以双核为例

worker_processes 2;
worker_cpu_affinity 0101 1010;
worker_priority -20;

5、配置日志缓存

access_log   /var/log/nginx/access.log   main buffer=1m;

6、配置缓存

# filename: proxy_cache.conf

proxy_cache_path /data/nginx/proxy_cache levels=1:2 keys_zone=CACHE:1024m max_size=10g inactive=12h use_temp_path=off;

# cache_path:           缓存存放的目录
# keys_zone:            缓存 zone名为 CACHE, 内存分配大小为 1024M,每M大约能存储8000个key
# loader_files:         最大加载文件数量 (缺省: 100)
# loader_threshold:     迭代的持续时间,以毫秒为单位(缺省: 200)
# max_size:             缓存最大上限空间
# inactive:             清空 12h 没有访问过的文件,缺省10分钟
# use_temp_path:        为off时将在缓存直接写到proxy_cache_path目录下,on时先写入到proxy_temp_path然后重命名到 proxy_cache_path下[建议使用off]

proxy_cache_key	            $scheme$host$request_method$request_uri;
proxy_no_cache              $cookie_nocache $arg_nocache $http_authorization;

7、开启gzip压缩

# filename: gzip.conf

gzip             on;
gzip_min_length  4k;
gzip_buffers     4 256k;
gzip_comp_level  6;
gzip_types       application/atom+xml
                 application/javascript
                 application/json
                 application/ld+json
                 application/manifest+json
                 application/rss+xml
                 application/vnd.geo+json
                 application/vnd.ms-fontobject
                 application/x-font-ttf
                 application/x-web-app-manifest+json
                 application/xhtml+xml
                 application/xml
                 font/opentype
                 image/bmp
                 image/svg+xml
                 image/x-icon
                 text/cache-manifest
                 text/css
                 text/plain
                 text/vcard
                 text/vnd.rim.location.xloc
                 text/vtt
                 text/x-component
                 text/x-cross-domain-policy;
gzip_vary        on;
gzip_proxied     expired no-cache no-store private auth;

提示: 也可以使用Google的br压缩算法(需要手动编译)

8、固定连接队列的大小

TCP 全连接队列的最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)。在高并发环境下,如果队列过小,可能导致队列溢出,使得连接部分连接无法建立。要调大 Nginx Ingress 的连接队列,只需要调整 somaxconn 内核参数的值即可。Nginx 监听 socket 时没有读取 somaxconn,而是有自己单独的参数配置。在 nginx.conf 中 listen 端口的位置,还有个叫 backlog 参数可以设置,它会决定 nginx listen 的端口的连接队列大小。

优化参考
在 listen 中声明backlog的大小。

server {
    listen  8080  backlog=1024;
    ...

backlog 是 listen(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;还有 Go 程序标准库在 listen 时,默认直接读取 somaxconn 作为队列大小。就是说,即便你的 somaxconn 配的很高,nginx 所监听端口的连接队列最大却也只有 511,高并发场景下可能导致连接队列溢出。所以在这个在 Nginx 中, Nginx 会自动读取 somaxconn 的值作为 backlog 参数写到生成的 nginx.conf 中: https://github.com/kubernetes/ingress-nginx/blob/controller-v0.34.1/internal/ingress/controller/nginx.go#L592 也就是说,Nginx 的连接队列大小只取决于 somaxconn 的大小。所以也可以直接使用更新容器内核中的参数也可以达到一致的目标。

sysctl -w net.core.somaxconn=65535

9、SO_REUSEPORT- 惊群效应

NGINX 1.9.1 引入了一项新功能,可以使用SO_REUSEPORT套接字选项,许多操作系统的较新版本都提供该选项,包括 DragonFly BSD 和 Linux(内核版本 3.9 及更高版本)。此套接字选项允许多个套接字侦听相同的 IP 地址和端口组合。然后内核对套接字之间的传入连接进行负载平衡。
reuseport是一种套接字利用机制,此选项允许主机,上的多个套接字同时绑定到相同的IP地址/端口上,可以实现多个服务进程或线程接收到同一个端口的连接,这种方式旨在提高在多核系统之上运行的多线程服务器应用程序的性能和吞吐率。
原来的mutex锁这种技术的问题在于,如果有多个工作进程/线程在accept()调用中等待,当有新连接建立时,对于各工作进程/线程的唤醒是不公平的,会导致惊群效应的出现。在高负载下,这种不均衡会导致CPU内核的利用率不足。虽然可以通过增加锁来解决此问题,但这样由于有锁竞争又以导致吞率下降。相比之下,采用reuseport方式后,SO_REUSEPORT连接均匀地分布在同一端口,在内核层面实现了CPU之间的均衡处理,这样当有新连接建立时,内核只会唤醒一个进程/线程,并且保证每次唤醒的均衡性。
更多关于原理与测试结果,可以参考:
https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/

优化参考

http {
     server {
         listen 8080 reuseport;
         server_name  localhost;
         # ...
     }
}
stream {
     server {
         listen 30004 reuseport;
         # ...
     }
}

理论上可以提升2~3倍+的QPS,不能在同端口中开启。