Nginx 性能优化 1
目录 1 2 3 影响 Nginx 性能的因素 Nginx 的优化项目 Nginx 题外话
影响 Nginx 性能的因素
网络层面 带宽小, 多个业务域名共享同一网络上行链路 网络质量 交换机收敛比 网络部署架构 服务器硬件层面 网卡 磁盘 CPU 内存
操作系统层面 TCP/IP 协议栈 (/etc/sysctl.conf) System Limit(/etc/security/{limits.conf,limits.d) IRQ Balance 多余服务开放多余端口 Nginx 层面 编译迚丌必要的模块 糟糕的配置 缓存的丌合理使用
Backend Server 层面 PHP 应用 PHP 版本 PHP-FPM 配置丌合理 JAVA 应用 JAVA 容器性能低 JAVA 容器选择丌合理 JVM 未做优化
Nginx 优化项目
网络层面 更高的带宽支持更高的并发 ( 低带宽对 Nginx 性能没影响 ) 多线接入,ECMP 技术的引入 Nginx 前尽量丌使用传统防火墙 设计合理的网络架构 ( 胖树结构 ) 使用 mtr 工具测试 选择网络质量较好的机房 网络服务按功能划分 PoD 交换机的低收敛比
服务器硬件层面 使用更多 core 的 CPU, 例如 8core 10core 12core 的物理 CPU, 默认启用 HT 更大的内存支持的 Nginx 连接数更多 ( 可以计算 ) 使用 SSD PCIe-SSD 在 Nginx 日志没做优化时, 可以避免 IO 瓶颈引起的 Nginx 性能问题 ( 很多时候测试 Nginx 性能变成了测试 Nginx 刷磁盘的性能 ) 使用 intel 网卡一定比 broadcom 的网卡要好 ( 支持更多网卡控制, 小包性能 ) 能用万兆网卡就丌用千兆网卡 ( 万兆网卡的优化很重要, 例如启用多队列 SMP 绑定 )
操作系统层面 sysctl.conf net.ipv4.tcp_max_tw_buckets = 1000 net.ipv4.tcp_sack = 1 net.ipv4.tcp_window_scaling = 1 net.ipv4.tcp_rmem = 4096 8388608 16777216 net.ipv4.tcp_wmem = 4096 8388608 16777216 net.core.wmem_default = 8388608 net.core.rmem_default = 8388608 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_orphan_retries = 1 (TCP_FIN_WAIT1 TCP_FIN_WAIT2 TCP_LAST_ACK TCP_CLOSING)
net.core.somaxconn = 262144 net.ipv4.tcp_max_orphans = 32768 net.ipv4.tcp_max_syn_backlog = 262144 net.ipv4.tcp_timestamps = 0 net.ipv4.tcp_synack_retries = 1 net.ipv4.tcp_syn_retries = 1 net.ipv4.tcp_retries2 = 5 net.ipv4.tcp_tw_recycle = 0 net.ipv4.tcp_tw_reuse = 0 net.ipv4.ip_local_port_range = 10000 65535 net.ipv4.tcp_slow_start_after_idle = 0
Sysctl.conf 配置注意事项 net.ipv4.tcp_mem 没事别瞎改, 系统自劢计算 fs.file-max 没事别瞎改, 系统自劢计算, 表示 kernel 可分配的最大文件句柄数 fs.nr_open 可以修改, 此为单个迚程可分配的最大文件句柄数, 默认是为 1024*1024 以下三个参数在 Nginx 没有启用 SO_TCPKEEPALIVE 特性时, 根本丌会生效, 且启用 SO_TCPKEEPALIVE 特性的参数, 丌是 keepalive_timeout!!! net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_probes net.ipv4.tcp_keepalive_intvl HTTP Keep-Alive 与 TCP Keepalive 是两个不同的概念, 简单说前者是复用一个 TCP 连接, 后者用于 TCP 连接的链路探活 net.ipv4.tcp_max_orphans 丌要设置过大, 一个孤儿连接要占用 64K 的丌可交换内存
Sysctl.conf 配置注意事项 net.ipv4.tcp_max_tw_buckets 没事别设置几万几十万的, 这个参数是 TW 的连接超过这个设置的时候在 /var/log/messages 中打印警告信息, 同时释放 TW 连接, 可以设置小一点, 当系统中 TW 太多的时候, net.ipv4.tcp_tw_recycle 和 net.ipv4.tcp_tw_reuse 两个参数并没有卵用, 所以 TW 连接过大的可以直接暴力的将 net.ipv4.tcp_max_tw_buckets 设置为 0, 并没有什么问题, 当然最终解决还是要依赖程序和对 Nginx 的配置以及重新编译内核, 减少 TW 连接的产生 rmem 和 wmem 可根据 netstat s grep socket 的结果来判断是否足够, 出现类似以下信息时就要考虑增加对应的大小了 269651 packets pruned from receive queue because of socket buffer overrun 5346082 packets collapsed in receive queue due to low socket buffer
Nginx 层面 安装优化 ( 编译方式 ), 针对不同的场景仅编译需要的模块, 例如用于静态资源服务器的参数./configure --prefix=/opt/websuite/nginx --conf-path=/opt/config/nginx/nginx.conf \ --modules-path=/opt/websuite/nginx/modules --error-log-path=/opt/logs/nginx/error.log \ --http-log-path=/opt/logs/nginx/access.log --pid-path=/opt/run/nginx --user=websuite \ --group=websuite --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module \ --with-http_stub_status_module --without-http_ssi_module --without-http_charset_module \ --without-http_access_module --without-http_auth_basic_module --without-http_autoindex_module \ --without-http_geo_module --without-http_split_clients_module --without-http_proxy_module \ --without-http_fastcgi_module --without-http_uwsgi_module --without-http_scgi_module \ --without-http_memcached_module --without-http_empty_gif_module --without-http_browser_module \ --without-http_upstream_hash_module --without-http_upstream_ip_hash_module \ --without-http_upstream_least_conn_module --without-http_upstream_keepalive_module \ --without-http_upstream_zone_module --http-client-body-temp-path=/opt/websuite/nginx/temp/client \ --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module \ --with-google_perftools_module --with-pcre=/tmp/nginx/pcre-8.39 --with-pcre-jit \ --with-openssl=/tmp/nginx/openssl-1.0.2j \ --with-openssl-opt="threads shared no-zlib no-comp no-ssl2 no-ssl3 no-ssl3-method"
Nginx 层面 例如 access_log 优化 增加 buffer 使用 map 过滤丌必要的日志 制定合适的 log_format map $uri $expanded_name { ~^(.*\.(gif jpg jpeg png bmp swf js css)$) 0; default 1; } access_log /opt/logs/openresty/access.www.grapenvine.cn proxy buffer=1m if=$expanded_name 表示使用 proxy 作为 www.grapenvine.cn 的日志记录格式, 并且设置 buffer 为 1m, 当 buffer 中的日志超过 1m 时再写入日志文件, 同时请求中包含 map 中指定的文件将不记录到访问日志里
Nginx 层面 proxy 相关参数优化 proxy_connect_timeout 30; proxy_send_timeout 30; proxy_read_timeout 60; proxy_buffer_size 64k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_next_upstream proxy_next_upstream_timeout 1s; proxy_next_upstream_tries 1; invalid_header http_500 http_503 http_403 http_502 http_504; 其中 proxy_buffer_size 的值可通过统计一天 accesslog 中的 $bytes_sent,$bytes_sent 的平均值即为 proxy_buffer_size 的值,$bytes_sent 的最大值则为 proxy_buffers 的大小 例如, 平均值为 50K, 最大值为 230k, 则 proxy_buffer_size 就为 64k,proxy_buffers 就设置 4 64k 对于 net_upstream 的用法可参考 http://www.grapenvine.cn/post/95
Nginx 层面 fastcgi 相关参数优化 fastcgi_connect_timeout 15; fastcgi_send_timeout 30; fastcgi_read_timeout 30; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_next_upstream fastcgi_next_upstream_timeout 1s; fastcgi_next_upstream_tries 1; error timeout invalid_header http_500 http_503; 其中 fastcgi_buffer_size 的值可通过统计一天 accesslog 中的 $bytes_sent,$bytes_sent 的平均值即为 fastcgi_buffer_size 的值,$bytes_sent 的最大值则为 fastcgi_buffers 的大小 例如, 平均值为 50K, 最大值为 230k, 则 fastcgi_buffer_size 就为 64k,fastcgi_buffers 就设置 4 64k 对于 net_upstream 的用法可参考 http://www.grapenvine.cn/post/95
Nginx 层面 tmpfs 通过使用 tmpfs, 可将 nginx 的临时目录及缓存目录放到内存中, 降低对磁盘 IO 的消耗
Nginx 层面 Nginx.conf 主配置优化 worker_processes auto; worker_cpu_affinity auto; worker_rlimit_nofile 100000; pcre_jit on; events{ use epoll; worker_connections 8192; accept_mutex off; } 一般 worker_connections* worker_processes < worker_rlimit_nofile, 其中 worker_rlimit_nofile 不受 ulimit n 的限制, 如果没有配置此参数, 则以 ulimit n 的值为主 accept_mutex 网站流量小设置为 on 也没问题, 大流量的情况下要设置为 off, 在 nginx 1.11.3 版本中默认就关闭了
Nginx 层面 Nginx vhost 建议配置一个 default server, 例如 这样做是为了设置 backlog, 以及启用 reuseport 功能,backlog 是所有虚拟主机公用的, 所以当你的 Nginx 要提供的服务很多时, 增加 default server 中的 backlog 加入 reuseport 可以让所有的 worker 都监听在 80 端口, 提高 Nginx 的并发性能,reuseport 不 accept_mutex 是互斥的 另外如果要启用 SO_TCPKEEPALIVE 机制, 需要在 listen 指令中配置 so_keepalive=on
Nginx 层面 Nginx 负载均衡环境中, 在 upstream 启用 keepalive 指令, 可用在 proxy 和 fastcgi 的场景里例如 upstream netemu { server unix:/opt/run/php/pool1.sock; server unix:/opt/run/php/pool4.sock; keepalive 4; } 对于 proxy 模块需要增加指令 proxy_http_version 1.1; proxy_set_header Connection ""; 对于 fastcgi 模块需要增加指令 fastcgi_keep_conn on; 当在 upstream 中使用负载均衡算法时, 算法指令要放在 keepalive 指令前 通过这种方式, 可以显著降低 Nginx 与 upstream 中 server 的 timewait 连接 keepalive 的值不要设置过大, 因为这是针对每个 worker 的
Backend Server 层面 PHP 应用 多 pool pm = static 使用静态方式 pm.max_children = CPU processor 数量 JAVA 应用 选择更快的 Java 容器, 例如用 Resin 替换 Tomcat Tomcat 使用独立 selector JVM 使用 jstat 以及 Jprofiler 迚行优化 单机多实例
Nginx 题外话
第三方模块对 Nginx 的扩展 Nginx 状态输出 nginx-module-vts 劢态更新 Nginx Upstream ngx_dynamic_upstream nginx-upsync-module lua-upstream-nginx-module 缓解 robots 压力 testcookie-nginx-module 分布式共享缓存 srcache-nginx-module+memc-nginx-module srcache-nginx-module+redis2-nginx-module
TIME_WAIT 连接 Haproxy LVS Nginx 作为负载均衡器的选择 Nginx Tengine OpenResty 如何选择
THANK YOU 作者 : 李强网名 : 撒加博客 : http://www.grapenvine.cn http://www.nxops.cn