性能优化 - Nginx & Linux
来自 鑫哥 [鑫哥的技术思维]2022-05-07 09:26 发表于湖北
纲要
- Nginx 优化后的完整配置
- Linux 内核参数优化
- 修改最大打开文件句柄数
Nginx 优化后的完整配置
# 核心参数(其他参数大部分情况下用不到)
# user USERNAME [GROUP]
# 解释:指定运行nginx的worker子进程的属主和属组,其中属组可以不指定
user nginx;
# worker_processes NUMBER | auto
# 解释:指定nginx启动的worker子进程数量
# 【*auto:自动设置为物理CPU核心数】
worker_processes auto;
# pid DIR
# 解释:指定运行nginx的master主进程的pid文件存放路径
pid /opt/nginx/logs/nginx.pid;
# worker_rlimit_nofile NUMBER
# 解释:指定worker子进程可以打开的最大文件句柄数
# 【系统最大打开65535,每个子进程打开数乘子进程数,实际也不会超过65535】
# 这个值需要调大,最好与 ulimit -n 的值保持一致。
worker_rlimit_nofile 65535;
# worker_rlimit_core SIZE
# 指定worker子进程异常终止后的core文件,用于记录分析问题
worker_rlimit_core 50M;
working_directory /opt/nginx/tmp;#【必须对子进程用户赋写权限】
# 解释:将每个worker子进程与CPU物理核心绑定
# 【master负责调度,worker负责处理请求】
# 【假设CPU有4个核心,某一时刻worker1获取到了CPU1的工作调度时间片,时间片过后worker1从CPU1上面撤下来,CPU1去处理其他事件,下一时刻可能是CPU2、CPU3的时间片调度到了worker1上面,那么worker1就会在其他CPU上面工作,进程与CPU的调度切换是有损耗的,worker1如果绑定了CPU1,worker1将永远等待CPU1的调度,充分利用CPU缓存】
# 【【主要作用:将每个worker子进程与特定CPU物理核心绑定,优势在于:避免同一个worker子进程在不同的CPU核心上切换,缓存失效,降低性能;其并不能真正避免进程切换(进程切换是CPU工作特性)】】
# -- worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;# 8核心,8个worker
# -- worker_cpu_affinity 01 10;# 2核心,2个worker
worker_cpu_affinity 0001 0010 0100 1000;# 4核心,4个worker
# 解释:指定worker子进程的nice值,以调整运行nginx的优先级,通常设定为“负值”,以优先调用nginx
# 【值越小越优先;nice设定范围为-20到+19】
worker_priority -20;
# 指定worker子进程优雅退出时的超时时间,不管5秒内是否处理完,都强制退出
worker_shutdown_timeout 5s;
# worker子进程内部使用的计时器精度,调整时间间隔越大,系统调用越少,有利于性能提升;反之,系统调用越多,性能下降
# 比如某些计时的操作,worker需要去获取内核时间,频繁跟内核打交道会降低性能
timer_resolution 100ms;
# daemon on | off
# 设定nginx的运行方式,前台还是后台,前台用户调试,后台用于生产
daemon on;
events {
# Nginx使用何种事件驱动模型
# 【高并发场景下,I/O多路复用使用epoll模型,提高效率】
use epoll;
# 单个worker子进程能够处理的最大并发连接数,多核情况最大其实达不到65535,
worker_connections 65535;
# 是否打开负载均衡互斥锁,默认off(当master接收到请求时,会给每个worker发送消息去唤醒,状态为on时,则会有一个负载均衡锁,master会轮流发给每一个)
accept_mutex off;
}
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"';
#access_log logs/access.log main;
# 开启高效的 零拷贝技术 进行文件传输;
# 这样只需要 2 次上下文切换,和 2 次数据拷贝,在内核态即可完成,由DMA进行文件搬运,不需要CPU参与
sendfile on;
# 必须在sendfile开启时才有效,防止网路阻塞,减少网络报文段的数量(将响应头和正文的开始部分一起发送,而不一个接一个的发送)
tcp_nopush on;
# 客户端连接保持会话超时时间,超过这个时间,服务器断开这个链接
keepalive_timeout 60;
# 防止网络阻塞
tcp_nodelay on;
# 客户端请求头部的缓冲区大小,根据系统分页大小来设置,命令 getconf PAGESIZE 取得分页大小
client_header_buffer_size 4k;
# 为打开文件指定缓存,默认是没有启用的,max 指缓存数量,建议和打开文件数一致,inactive 指经过多长时间文件没被请求后删除缓存
open_file_cache max=65536 inactive=30s;
# 多长时间检查一次缓存的有效信息
open_file_cache_valid 30s;
# open_file_cache 指令中的 inactive 参数时间内文件的最少使用次数
# 如果超过这个数字,文件描述符一直是在缓存中打开的,如果一个文件在 inactive 时间内一次没被使用,它将被移除
open_file_cache_min_uses 1;
# 设置请求头的超时时间,如果超过这个时间没有发送任何数据,nginx将返回request time out的错误
client_header_timeout 15;
# 设置请求体的超时时间,超过这个时间没有发送任何数据,和上面一样的错误提示
client_body_timeout 15;
# 告诉nginx关闭不响应的客户端连接。这将会释放那个客户端所占有的内存空间
reset_timedout_connection on;
# 应客户端超时时间,这个超时时间仅限于两个活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx关闭连接
send_timeout 15;
# 上传文件大小限制
client_max_body_size 10m;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location /video/ {
sendfile on;
# 当文件大小超过8M时,启用AIP与directio
aio on;
directio 8m;
}
# HTTPS server
server {
# 开启http2
# http2 在底层传输做了很大的改动和优化:
# 1,每个服务器只用一个连接,节省多次建立连接的时间,在TLS上效果尤为明显
# 2,加速 TLS 交付,HTTP/2 只耗时一次 TLS 握手,通过一个连接上的多路利用实现最佳性能
# 3,更安全,通过减少 TLS 的性能损失,让更多应用使用 TLS,从而让用户信息更安全
listen 443 ssl http2;
server_name localhost;
## 证书部分
#ECC证书
# 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key,运算速度更快,同等安全条件下,ECC 算法所需的 Key 更短,所以 ECC 证书文件体积比 RSA 证书要小一些。
ssl_certificate ecc.crt;
#ECC密钥
ssl_certificate_key ecc.key; #ECC密钥
ssl_certificate cert.pem; # RSA证书
ssl_certificate_key cert.key; # RSA密钥
# TLS 握手优化
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
keepalive_timeout 75s;
keepalive_requests 100;
# 支持TLSv1.3
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
# 开启 1.3 o-RTT
ssl_early_data on;
ssl_prefer_server_ciphers on;
# gzip
gzip on;
# 压缩比例,用来指定GZIP压缩比,1压缩比最小,处理速度最快,9压缩比最大,传输速度快,但是处理慢,也比较消耗CPU资源
gzip_comp_level 6;
# 设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取,默认值是0
gzip_min_length 1k;
# 用来指定压缩的类型,‘text/html’类型总是会被压缩。默认值: gzip_types text/html (默认不对js/css文件进行压缩)
# 缩类型,匹配MIME型进行压缩,不能用通配符 text/* text/html默认已经压缩 (无论是否指定)
# 设置哪压缩种文本文件可参考 conf/mime.types
gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
# brotli:Google 推出的无损压缩算法,有以下优势:
# 1,针对常见的 Web 资源内容,Brotli 的性能要比 Gzip 好 17-25%;
# 2,Brotli 压缩级别为 1 时,压缩速度是最快的,而且此时压缩率比 gzip 压缩等级为 9(最高)时还要高;
brotli on;
brotli_comp_level 6;
brotli_min_length 1k;
brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
location / {
root html;
index index.html index.htm;
}
}
}
❝
支持 TLS1.3 和 brotli ,都需要编译时引入相应模块
cd /opt/$nginxVersion/ ./configure \ --prefix=/usr/local/nginx \ ## 编译后安装的目录位置 --with-openssl=/opt/$OpenSSLVersion \ ## 指定单独编译入 OpenSSL 的源码位置 --with-openssl-opt=enable-tls1_3 \ ## 开启 TLS 1.3 支持 --with-http_v2_module \ ## 开启 HTTP/2 --with-http_ssl_module \ ## 开启 HTTPS 支持 --with-http_gzip_static_module \ ## 开启 GZip 压缩 --add-module=/opt/ngx_brotli ## 编译入 ngx_BroTli 扩展 make && make install ## 编译并安装
❞
Linux 内核参数优化
- 修改文件:
/etc/sysctl.conf
- 执行
/sbin/sysctl -p
,使配置生效
# 表示进程(比如一个worker进程)可以同时打开的最大句柄数,这个参数直接限制最大并发连接数,需根据实际情况配置
fs.file-max = 999999
# 控制系统调试内核的功能,不同的值对应不同的功能
# 0 完全禁用 sysrq 组合键
# 1 启用 sysrq 组合键的全部功能
# 2 启用控制台日志级别控制
# 4 启用键盘控制(SAK、unraw)
# 8 启用进程的调试信息输出等
# 16 启用同步命令
# 32 启用重新挂载为只读
# 64 启用进程信号(终止、杀死、溢出杀死)
# 128 允许重启/关机
# 256 控制实时任务的优先级控制(nicing)
kernel.sysrq = 0
# core_uses_pid 可以控制 core 文件的文件名中是否添加 pid 作为扩展名
# 设置为1,表示添加 pid 作为扩展名,生成的 core 文件格式为 core.xxx;设置为0(默认),表示生成的 core 文件统一命名为 core
kernel.core_uses_pid = 1
# 规定了一个消息队列的最大值,即一个消息队列的容量,msgmnb 控制可以使用的共享内存的总页数
# Linux共享内存页大小为4KB,共享内存段的大小都是共享内存页大小的整数倍
# 一个共享内存段的最大大小是 16G,那么需要共享内存页数是16GB / 4KB = 16777216KB / 4KB = 4194304(页)
kernel.msgmnb = 65536
# 进程间的消息传递是在内核的内存中进行的。msgmax 指定了消息队列中消息的最大值(65536B=64KB)
kernel.msgmax = 65536
# 内核所允许的最大共享内存段的大小(bytes)
kernel.shmmax = 68719476736
# 表示在任何给定时刻,系统上可以使用的共享内存的总量(bytes)
kernel.shmall = 4294967296
# 表示内核套接字发送缓存区默认的大小
net.core.wmem_default = 8388608
# 表示内核套接字接受缓存区默认的大小
net.core.rmem_default = 8388608
# 表示内核套接字接受缓存区的最大大小
net.core.rmem_max = 16777216
# 表示内核套接字发送缓存区的最大大小
net.core.wmem_max = 16777216
# 接收自网卡,但未被内核协议栈处理的报文队列长度
net.core.netdev_max_backlog = 262144
# web 应用中 listen 函数的 backlog 默认会给我们内核参数的
# 对于一个TCP连接,Server与Client需要通过三次握手来建立网络连接
# 当三次握手成功后,我们可以看到端口的状态由LISTEN转变为ESTABLISHED,接着这条链路上就可以开始传送数据了
# 每一个处于监听(Listen)状态的端口,都有自己的监听队列.监听队列的长度与如somaxconn参数和使用该端口的程序中listen()函数有关
# somaxconn定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数,默认值为128
# 对于一个经常处理新连接的高负载 web服务环境来说,默认的 128 太小了。大多数环境这个值建议增加到 1024 或者更多
# 大的侦听队列对防止拒绝服务 DoS 攻击也会有所帮助
net.core.somaxconn = 40960
# 不充当路由器
net.ipv4.ip_forward = 0
# 控制系统是否开启对数据包源地址的校验
# 0 不开启源地址校验
# 1 开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径,则直接丢弃该数据包
# 2 开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包
net.ipv4.conf.default.rp_filter = 1
# 使用sysrq组合键是了解系统目前运行情况,为安全起见设为0关闭
net.ipv4.conf.default.accept_source_route = 0
# 启用有选择的应答(1表示启用)
# 通过有选择地应答乱序接收到的报文来提高性能,让发送者只发送丢失的报文段,(对于广域网通信来说)这个选项应该启用,但是会增加对CPU的占用
net.ipv4.tcp_sack = 1
# tcp窗口大于64K时,必须开启此值
net.ipv4.tcp_window_scaling = 1
# TCP读缓存的最小值、默认值、最大值,单位字节
net.ipv4.tcp_rmem = 10240 87380 12582912
# TCP读缓存的最小值、默认值、最大值,单位字节
net.ipv4.tcp_wmem = 10240 87380 12582912
# TCP的内存大小,单位是页,1页等于4096字节,单位为页的数量
net.ipv4.tcp_mem = 94500000 915000000 927000000
# 系统中最多有多少个 TCP 套接字不被关联到任何一个用户文件句柄上
# 这个限制仅仅是为了防止简单的 DoS 攻击,如果增加了内存之后,更应该增加这个值
net.ipv4.tcp_max_orphans = 3276800
# SYN队列的长度,默认为1024,加大队列长度为262144,可以容纳更多等待连接的网络连接数
net.ipv4.tcp_max_syn_backlog = 262144
# 用于设置时间戳,可以避免序列号的卷绕
# 一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。设置为 0 表示将其关掉
net.ipv4.tcp_timestamps = 0
# 内核放弃连接之前发送 SYN+ACK 包的数量
# 被动建立连接时,发送SYN/ACK的重试次数
net.ipv4.tcp_synack_retries = 1
# 主动建立连接时,发送SYN的重试次数
net.ipv4.tcp_syn_retries = 1
# 开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1
# 开启重用。作为客户端时,新连接可以使用仍然处于 TIME-WAIT 状态的端口,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
# TIME_WAIT 状态连接的最大数量,超出后直接关闭连接
net.ipv4.tcp_max_tw_buckets = 6000
# fin_wait1状态,发送fin报文的重试次数,0相当于8
net.ipv4.tcp_orphan_retries = 0
# fin_wait2状态,默认的 TIMEOUT 时间
net.ipv4.tcp_fin_timeout = 15
# 当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时
net.ipv4.tcp_keepalive_time = 1200
# 探测包发送间隔
net.ipv4.tcp_keepalive_intvl = 75
# 探测包重试次数
net.ipv4.tcp_keepalive_probes = 6
#开启SYN Cookies 当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1
# 建立连接时的本地端口可用范围
net.ipv4.ip_local_port_range = 1024 65000
修改最大打开文件句柄数
编辑文件:/etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
标签:core,application,worker,tcp,Nginx,ipv4,Linux,net,优化
From: https://www.cnblogs.com/starkzz/p/17553839.html