5. nginx优化

5.1. 优化方法论

  • 软件方面提升使用率

  • 硬件提升

  • 使用dns

5.2. 如何有效使用CPU

能够使用全部的CPU资源

  • work进程数量大于等于cpu number .

  • master worker 多进程架构

nginx进程不做无用功浪费CPU

  • 不应该争抢cpu,worker进程数量大于等于cpu合数。

  • 不应该调用第三方模块让出cpu

nginx不被其他进程抢用

  • 提升优先级

  • 减少非nginx进程存在

5.2.1. 设置worker进程的数量

worker_processes: 设置数量,auto的话,自动和cpu数量保持一致。

5.2.2. 为何cpu可以同时运行多个进程

时间片分割,进程被分配时间片,微观上是串行的,宏观是并行的。

阻塞(读文件,网络)等会导致主动让出。

5.2.3. 确保处于运行态

5.2.4. 减少进程切换

  • 主动切换: 阻塞api

  • 被动切换: 时间片耗尽

5.2.5. 如何查看上下文切换

[zhaojiedi_dxm@instance-zj2zr2l1-15 conf]$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
4  0      0 824280 133348 123614624    0    0     8   115    0    0  8  4 87  0  0

[root@instance-dduk3gev-19 ~]# dstat
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw
8   4  87   0   0   0| 264k 3671k|   0     0 |   0     0 |3168   110k

# cswch/s 主动的,nv 被动的
[root@instance-dduk3gev-19 ~]# pidstat -w  |head -n 10
Linux 3.10.0-957.21.3.el7.x86_64 (instance-dduk3gev-19.bcc-bjdd)    01/21/2022      _x86_64_        (32 CPU)

07:18:27 PM   UID       PID   cswch/s nvcswch/s  Command
07:18:27 PM     0         1      1.32      0.08  systemd
07:18:27 PM     0         2      0.32      0.01  kthreadd
07:18:27 PM     0         3      4.66      0.00  ksoftirqd/0
07:18:27 PM     0         5      0.00      0.00  kworker/0:0H
07:18:27 PM     0         7      0.22      0.00  migration/0
07:18:27 PM     0         8      0.00      0.00  rcu_bh

5.2.6. 什么决定cpu时间片的大小

nice优先级-20到19的。

o1调度算法优先级影响还是挺大的, 优先级对应的时间片可以在5ms-800ms的。

通过worker_priority 设置优先级。 也就是nice值。

5.3. 多核间如何负载均衡

5.3.1. 多队列网卡对多核cpu的优化

  • rss: 硬中断负载均衡

  • rps: 软中断负载均衡

  • rfs:

5.3.2. 提升cpu缓存命中率

worker_cpu_affinity: 设置cpu粘性。

查看cpu缓存

[root@instance-dduk3gev-19 ~]# cat /sys/devices/system/cpu/cpu0/cache/index{0,1,2,3}/size
32K
32K
1024K
11264K

5.4. 控制tcp握手参数

../_images/nginx41.png

syn_sent 状态

  • net.ipv4.tcp_syn_retries=6 主动发送syn的重试次数

  • net.ipv4.ip_local_range = 32768 60999 建立连接时候的本地端口可用范围。

  • proxy_connect_time: 主动建立连接时间

syn_revd 状态

  • net.ip4.tcp_max_syn_backlog: syn_revd状态的最大个数

  • net.ipv4.tcp_synack_retries: 发送syn/ack的重试次数

服务器怎么处理三次握手

../_images/nginx42.png

如何控制syn攻击

攻击者为准不同的ip地址的syn报文,快速占满backlog队列。

  • net.core.netdev_max_backlog: 接受自网卡,但是没有被内核协议栈处理的报文长度。

  • net.ipv4.tcp_max_syn_backlog: sync_rcvd状态的连接个数。

  • net.ipv4.tcp_abort_on_overflow: 超出处理能力对新来的syn直接回包RST,丢弃连接。

启用tcp_syncookies: 当syn队列满了,就不进入syn队列,计算cookie直接进入backlog队列。

5.5. 建立tcp连接的优化

5.5.1. 句柄的上限

操作系统级别

  • fs.file-max: 操作系统最大的句柄数

  • fs.file-nr: 当前分配和正使用以及上限。

用户级别

/etc/security/limits.conf
root soft nofile 65535

限制进程

# 限制work进程打开文件的个数
worker_rlimit_nofile number  ;
# 限制work打开的连接个数
woker_connection number;

5.5.2. 队列长度

  • syn队列: net.ipv4.tcp_max_syn_backlog

  • accept队列: net.core.somaxconn

  • backlog=number: 应用级别的。

5.5.3. tcp fast open

../_images/nginx43.png
net.ipv4.tcp_fastopen
    0: 关闭
    1: 作为客户端可以使用tfo
    2: 作为服务端可以使用tfo
    3: 都是用tfo

fastopen=number 可以防止携带数据的syn攻击,限制以最大长度。

5.6. 滑动窗口和缓冲区

5.6.1. 滑动窗口

功能:

限制连接的网速,解决报文乱序和可靠传输问题。通过操作系统内核实现。

发送窗口:

用于发送内容

接收窗口:

用于接收内容

5.6.2. 发送tcp消息

../_images/nginx44.png

5.6.3. tcp接收消息

../_images/nginx45.png

5.6.4. nginx的超时时间和滑动窗口

  • client_body_timeout: 2次读操作间的超时时间。

  • send_timeout: 2次写操作的超时时间。

  • proxy_timeout: 2次读或者2次写的超时时间。

5.6.5. 丢包重传

  • net.ipv4.tcp_retries1 = 3 达到上限后更新路由缓存。

  • net.ipv4.tcp_retries2 = 15 达到上限后关闭tcp连接

5.7. 优化滑动窗口和传输效率

5.7.1. tcp缓冲区

  • net.ipv4.tcp_rmem 设置读取缓冲区最小值,默认值和最大值。单位字节。

  • net.ipv4.tcp_wmem: 设置写缓冲区最小值,默认值和最大值。单位字节。

  • net.ipv4.tcp_mem: 系统无内存压力、启动压力模式阈值、最大值。单位为页的数量。

  • net.ipv4.tcp_moderate_rcvbuf=1: 开启自动调整缓存模式。

  • revbuf: 接受缓冲区大小

  • sndbuf: 发送缓冲大小

最大接受窗口应该=带宽x时延

5.7.2. nagle算法

避免一个连接上同事存在大量小报文。提升带宽利用率 tcp_nodelay on 禁用nagle算法。

postpone_output 不到足够大小不发送。

5.7.3. cork算法

仅仅针对sendfile on 开启时候生效,完全禁止小报文的发送,提升网络效率 tcp_nopush on 。

5.8. 慢启动和拥塞窗口

5.8.1. 流量控制

  • 拥塞窗口: 发送端主动限制流量

  • 通告窗口: 接受方限制流量

  • 实际流量: 拥塞窗口和通告的最小值。

5.8.2. 拥塞处理

  1. 慢启动方式: 指数扩展拥塞窗口。

  2. 拥塞避免: 窗口大于threshold.

  3. 拥塞发生: 计算降低拥塞窗口。

  4. 快速恢复:

5.9. tcp keepalive

应用场景:

检测实际断掉的连接 用于维持与客户端间的防火墙有活跃网络包。

  • netipv4.tcp_keepalive_time: 发送心跳周期

  • net.ipv4.tcp_keepalive_intvl: 探测包发送间隔。

  • net.ipv4.tcp_keepalive_probes: 探测包重试次数。

  • so_keepalive= nginx的tcp keep alive参数指定。

5.10. 减少连接的timewait的状态数量

  • net.ipv4.tcp_orphan_retries: 发送fin的重试次数。

  • net.ipv4.tcp_fin_timeout: 保持在wait2的时间。

  • net.ipv4.tcp_tw_reuse=1 作为客户端可以服用tw的端口。

  • net.ipv4.tcp_timestamps :拒绝迟到的包

  • net.ipv4.tcp_tw_recycle 作为客户端和服务端都可以使用tw的端口。

  • net.ipv4.tcp_max_tw_buckets 设置最大数量超过就直接关闭了。

5.11. lingering_close 延迟关闭连接

nginx处理完成调用close关闭连接,可能会导致客户端收到rst忽略response.

lingering_close 会自动跟进实际情况关闭。

5.12. 应用层协议优化

ssl_session_cache: 定义共享内存,为所有worker进程提供session缓存服务,1mb可以使用4ksession。

5.13. tls/ssl中的会话票证

nginx将会话session的信息作为tickets加密发送给客户端,下次客户端发起请求tls连接的时候带上tickets,nginx解密验证后复用会话session.

  • ssl_session_tickets: 是否启用ssl tickets

  • ssl_session_ticket_key: 秘钥文件。

5.14. http长连接

  • 减少握手次数

  • 降低tcp拥塞控制影响。

5.15. gzip压缩

通过实时压缩http包体,提升网络传输效率。

  • gzip on 开启

  • gzip_types: 哪些类型压缩

  • gzip_min_length: 低于特定大小不压缩

  • gzip_disable : 哪些不压缩。

  • gzip_proxied:是否压缩上游响应

5.16. 升级更高效的http2.0协议

5.17. 磁盘io的优化

优化读取

  • sendfile 0copy

  • 内存盘ssd盘

减少写入

  • aio

  • 增加日志级别

  • 关闭access_log

  • 压缩日志

  • syslog替代本地io

5.17.1. 直接io

当磁盘的文件大小超过特定size后,启用直接io可以避免磁盘页缓存中的copy消耗。

  • directio 是否开启

  • directio_alignment: 超过的大小。

5.17.2. aio

  • aio 是否启用

  • aio_write:

5.17.3. 定义线程池

适合静态集群

5.18. 减少磁盘读写次数

5.18.1. empty_gif模块

这是一个1x1的图片,大小43个字节。

5.18.2. 日志压缩

access_log 设置buffer flush等参数减少日志打印次数。

5.18.3. error_log日志输出到内存

开发环境中定位问题打开debug级别的日志,但对debug的级别大量日志引发的性能问题不能容忍,将日志打印到内存中。

官方参考: https://nginx.org/en/docs/debugging_log.html

5.18.4. sysylog

官方参考: https://nginx.org/en/docs/syslog.html

5.19. 零copy和gzip_static

../_images/nginx46.png

如果磁盘文件需要压缩的话, 直接有同名.gz的文件响应给用户。

gunzip当客户端不支持gzip,磁盘有压缩文件的话,则解压缩并发送客户端。

5.20. tcmalloc

分配内存的性能更高。

  • 并发能力高

  • 减少内存碎片

编译时候指定 –with-ld-opt=-ltcmalloc –with-google_perftools_module

5.21. 使用google perf 分析

分析nginx哪些函数消耗的时间比较久。

5.22. statu模块监控nginx数据

stub-status可以通过http接口,返回实时的监控的nginx连接状态。