nginx 学习5-性能优化-cpu/tcp/ssl/io/syslog/

421 阅读5分钟

1.性能优化方法论

从软件层面提升硬件使用效率

  • 增大CPU的利用率
  • 增大内存的利用率
  • 增大磁盘IO的利用率
  • 增大网络带宽的利用率

提升硬件规格

  • 网卡: 万兆网卡,例如10G、25G、40G等
  • 磁盘:固态硬盘,关注IOPS和BPS指标
  • CPU:更快的主频,更多的核心,更大的缓存,更优的架构
  • 内存:更快的访问速度

超出硬件性能上限后使用DNS

2.如何高效使用CPU

如何增大Nginx使用CPU的有效时长?

能够使用全部CPU资源

  • master-worker多进程架构
  • worker进程数量应当大于等于CPU核数

Nginx进程间不做无用功浪费CPU资源

  • worker进程不应在繁忙时,主动让出CPU
  • worker进程间不应由于争抢造成资源耗散 worker进程数量应当等于CPU核数0
  • worker进程不应调用一些API导致主动让出CPU 拒绝类似的第三方模块.

不被其他进程争抢资源

  • 提升优先级占用CPU更长的时间
  • 减少操作系统上耗资源的非Ninx进程

设置worker进程的数量

worker_processes 1;

为何一个CPU就可以同时运行多个进程?

宏观上并行,微观上串行

  • 把进程的运行时间分为一段段的时间片
  • OS调度系统依次选择每个进程,最多执行时间片指定的时长

阻寨API引发的时间片内主动让出CPU。

  • 速度不一致引发的阻塞API,硬件执行速度不一致例如CPU和磁盘
  • 业务场景产生的阻寨API,例如同步读网络报文

确保进程在运行态!

  • R运行:正在运行或在运行队列中等待
  • S中断:休眠中,受阻,在等待某个条件的形成或接受到信号。
  • D不可中断:收到信号不唤醒和不可运行,进程必须等待直到有中断发生
  • Z僵死: 进程已终止,但进程描述符存在,直到父进程调用wait40系统调用后释放。T停止: 进程收到SIGSTOP,SIGSTP,SIGTIN,SIGTOU信号后停止运行。

减少进程间切换

Nginxworker尽可能的处于R状态

R状态的进程数量大于cpu核心时,负载急速增高

尽可能的减少进程间切换

何为进程间切换

  • 是指CPU 从一个进程或线程切换到另一个进程或线程
  • 类别 : 主动切换, 被动切换:时间片耗尽
  • Cost: <5us
  • 减少主动切换
  • 减少被动切换:增大进程优先级

绑定cpu

延迟处理新连接

使用TCP DEFER ACCEPT 延迟处理新连接
Syntax: listen address[:port] [deferred];
Default: listen *:80 | *:8000;

如何查看上下文切换次数?

# Pidstat
Pidstat -w
ps -ef | grep nginx ; # 先查看master进程id 

pidstat -w -p 12196
pidstat -w -p 12196 1 # 查看第一个cpu

# Vmstat
 vmstat 1

# Dstat
dstat 1 

什么决定CPU时间片的大小?

  • Nice静态优先级:-20 - 19
  • Priority动态优先级:0-139

O1 调度算法(CFS)

优先级动态调整

  • 幅度 +5
  • 依据: CPU消耗型进程, IO消耗型进程
  • 分时: 时间片 5ms-800ms

设置worker进程的静态优先级

worker_priority 0;

3.多核间的负载均衡

worker进程间负载均衡

多队列网卡对多核CPU的优化

  • RSS 硬中断负载均衡
  • RPS 软中断负载均衡
  • RFS

提升CPU缓存命中率: worker_cpu_affinity

cat /sys/devices/system/cpu/cpul/cache/index0/size
# 32k
cat /sys/devices/system/cpu/cpul/cache/index1/size
# 32k
cat /sys/devices/system/cpu/cpul/cache/index2/size
# 256k
cat /sys/devices/system/cpu/cpul/cache/index3/size
# 20480k
cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_list
 # 0,,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
cat /sys/devices/system/cpu/cpu1/cache/index3/shared_cpu_list
 # 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31

绑定worker到指定CPU

worker_cpu_affinity cpumask ...;
worker_cpu_affinity auto \[cpumask];

NUMA架构

当部署多台服务器时,可以让多台服务器像单台使用,同时使cpu就近访问最近的内存信息。

image.png

numactl --hardware
numastat

4.控制TCP三次握手参数

image.png

TCP连接

  • 3次握手
  • 4次挥手
netstat -anp | grep tcp
# 显示 状态分别有
LISTEN/ESTABLISHED/TIMEWAIT

## SYN SENT状态
net.ipv4.tcp_syn_retries = 6 主动建立连接时,发SYN的重试次数
net.ipv4.ip_local_port_range = 32768 - 60999 建立连接时的本地端口可用范围

## 主动建立连接时应用层超时时间
proxy_connect_timeout 60s; 
proxy_connect_timeout 60s;

## SYN RCVD状态
net.ipv4.tcp_max_syn_backlog    SYN RCVD状态连接的最大个数
net.ipv4.tcp_synack_retries  被动建立连接时,发SYN/ACK的重试次数

服务器端处理三次握手

系统内核接受网络信号,处理SYN(tcp_max_syn_backlog)队列和ACCEPT(backlog)队列的插入和取出

image.png

  1. 收到SYN网络分组信号
  2. 插入SYN队列
  3. SYN/ACK回复客户端信号
  4. ACK信号到达
  5. 从SYN队列中取出
  6. 插入ACCEPT(backlog)队列
  7. nginx读取ACCEPT(backlog)队列中的连接套接字

5.建立TCP连接的优化

如何应对SYN攻击?

攻击者短时间伪造不同PP地址的SYN报文,快速占满backlog队列,使服务器不能为正常用户服务

  • net.core.netdev_max_backlog : 接收自网卡、但未被内核协议栈处理的报文队列长度
  • net.ipv4.tcp_max_syn_backlog : SYN RCVD状态连接的最大个数
  • net.ipv4.tcp_abort_on_overflow : 超出处理能力时,对新来的SYN直接回包RST,丢弃连接

tcp syncookies

net.ipv4.tcp_syncookies = 1

当SYN队列满后,新的SYN不进入队列,计算出cookie再以SYN+ACK中的序列号返回客户端,正常客户端发报文时,服务器根据报文中携带的cookie重新恢复连接

由于cookie占用序列号空间,导致此时所有TCP可选功能失效,例如扩充窗口、时间戳等

linux 一切皆文件:句柄数的上限

操作系统全局

fs.file-max

操作系统可使用的最大句柄数使用fs.file-nr可以查看当前已分配、正使用、上限

fs.file-nr =21632 040000500

限制用户

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

限制进程

Syntax: worker_rlimit_nofile number;

设置worker进程最大连接数量

包括Nginx与上游、下游间的连接

Default: worker_connections 512;
Context: events

例子

sysctl -a grep file-max
sysctl -a grep file-nr

cat /etc/security/limits.conf 

Tcp Fast Open

第一次请求返回,服务器顺便带上数据 image.png

net.ipv4.tcp_fastopen

netipv4.tcp fastopen:系统开启TFO功能

  • 0:关闭
  • 1:作为客户端时可以使用TFO
  • 2:作为服务器时可以使用TFO
  • 3:无论作为客户端还是服务器,都可以使用TFO
Syntax: listen address[:port] [fastopen=number];
Default: listen *:80 | *:8000;

fastopen=number : 为防止带数据的SYN攻击,限制最大长度,指定TFO连接队列的最大长度

两个队列的长度

SYN队列未完成握手 net.ipv4.tcp_max_syn_backlog = 262144 ACCEPT队列已完成握手 net.core.somaxconn 系统级最大backlog队列长度

6.滑动窗口与缓冲区

image.png

功能

  • 用于限制连接的网速,解决报文。乱序和可靠传输问题

  • Nginx中limit rate等限速指令皆依赖它实现

  • 由操作系统内核实现

  • 连接两端各有发送窗口与接收窗

  • 发送窗口 : 用于发送内容

  • 接收窗口 : 用于接收内容

通告窗口

发送TCP消息流程

  1. nginx 调用send发送
  2. 内核调用tcp_sendmsg
  3. 复制到内核态 MSS分组1,MSS分组2,MSS分组3 (循环将待发送的字节流分成MSS分组拷贝到内核态)
  4. 缓存
  5. 超时或有空闲缓存
  6. tcp_push 加入 tcp发送队列
  7. 按 Nalge 慢启动等算法发送报文
  8. 取出MSS分组并发送
  9. 告诉nginx已经发送

TCP消息接收

  1. 接收网卡报文s1-s2插入receive队
  2. 按收网卡失序的s3-s4,插入out_of_order列表
  3. 接收网卡报文s2-s3插入receive队列
  4. 遍历out_of_order列表取出s3-s4放入receive队列
  5. 通知nginx 调用recv接收阻塞socket
  6. 内核调用 tcp_recvmsg,锁住socket,获取最低接收阀值
  7. 处理receive队列中已排序的报文,开始复制报文到用户态
  8. 报文S1-S2复制到用户态
  9. 报文S2-S3复制到用户态
  10. 报文S3-S4 复制到用户态
  11. 检查是否接收到超过最低阀值TCP消息长度
  12. 已经拷贝的字节数超过最低接收阀值,而且backlog队列为空
  13. recv方法返回已经拷贝的S4-S1字节数

TCP消息接收发生CS

TCP消息接收接收时新报文到达

nginx的超时指令与滑动窗口

client_body_timeout 60s; #两次读操作间的超时下
send_timeout 60s;   # 两次写操作间的超时

proxy_timeout 10m; # 以上两者兼具

丢包重传

#限制重传次数
net.ipv4.tcp retries1 = 3 #达到上限后,更新路由缓存
net.ipv4.tcp retries2 = 15 #达到上限后,关闭TCP连接
#仅作近似理解,实际以超时时间为准,可能少于retries次数就认定达到上限

7.优化缓冲区与传输效率

net.ipv4.tcp_rmem = 4096 87380 6291456 # 读缓存最小值、默认值、最大值,单位字节,覆盖  
net.ipv4.tcp_wmem = 4096 16384 4194304 # 写缓存最小值、默认值、最大值,单位字节,覆盖 
net.ipv4.tcp_mem = 1541646 2055528 3083292 # 系统无内存压力、启动压力模式阀值、最大值,单位为页的数量 
net.ipv4.tcp_moderate_rcvbuf = 1 # 开启自动调整缓存模式

listen address[:port] [rcvbuf=size] [sndbuf=size];
listen *:80 | *:8000; 

调整接收窗口与应用缓存

net.ipv4.tcp_adv_win_scale = 1

应用缓存 = buffer / (2^tcp_adv_win_scale)

BDP-带宽x时延,吞吐量-窗口/时延

image.png

禁用Nagle算法

Nagle算法

  • 避免一个连接上同时存在大量小报文最多只存在一个小报文合并多个小报文一起发送
    • 吞吐量优先:启用Nagle算法,tcp_nodelay off
    • 低时延优先:禁用Nagle算法,tcp nodelay on
  • 提高带宽利用率

image.png

# 仅针对HTTP KeepAlive连接生效
Syntax: tcp_nodelay on | off; 
Default: tcp_nodelay on; 
Context: http, server, location


Syntax: tcp_nodelay on | off;
Default: tcp_nodelay on;
Context: stream, server

Nginx也可以避免发送小报文

postpone_output 1460;

启用CORK算法

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

tcp_nopush on | off:

8.慢启动与拥塞窗口

流量控制

  • 拥塞窗口: 发送方主动限制流量
  • 通告窗口 (对端接收窗口): 接收方限制流量
  • 实际流量: 拥塞窗口与通告窗口的最小值

拥塞处理

慢启动

指数扩展拥塞窗口 (cwnd为拥塞窗口大小)。

  • 每收到1个ACK,cwnd = cwnd +l
  • 每过一个RTT,cwnd =cwnd * 2

拥塞避免:窗口大于threshold

线性扩展拥塞窗口

  • 每收到1个ACK,cwnd=cwnd + 1/cwnd
  • 每过一个RTT,窗口加1

拥塞发生

急速降低拥塞窗口 RTO超时,threshold = cwnd/2, cwnd =1 Fast Retransmit,收到3个duplicate ACK,cwnd = cwnd/2,threshold = cwnd

快速恢复

当Fast Retransmit出现时,cwnd调整为threshold +3*MSS

慢启动

TCP Slow Start

RTT与RTO

RTT: Round Trip Time

时刻变化

  • 组成
  • 物理链路传输时间

末端处理时间

  • 路由器排队处理时间
  • 指导RTO

RTO: Retransmission TimeOut.

正确的应对丢包

9.TCP协议的keepalive功能

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

TCP的Keep-Alive功能

### Linux的tcp keepalive
net.ipv4.tcp keepalive time = 7200 # 发送心跳周期 
net.ipv4.tcp keepalive intvl = 75 # 探测包发送间隔 
net.ipv4.tcp kecpalive probes = 9  #探测包重试次数
### Nginx的Tcp keepalive
so_keepalive=30m::10
keepidle,keepintvl,keepcnt

10.减少关闭连接时的time_wait端口数量

image.png 4次挥手

#客户端 
FIN_WAIT_1
FIN_WAIT_2
TIME_WAIT 
#服务器
CLOSE_WAIT
LAST_ACK

被动关闭连接端的状态

  • CLOSE_WAIT状态: 应用进程没有及时响应对端关闭连接
  • LAST_ACK状态: 等待接收主动关闭端操作系统发来的针对FIN的ACK报文

主动关闭连接端的状态

# FIN_WAIT1状态
net.ipv4.tcp_orphan_retries = 0 #发送FIN报文的重试次数,0相当于8
# FIN_WAIT2状态
net.ipv4.tcp_fin_timeout = 60  #保持在FIN_WAIT_2状态的时间

TIIME_WAIT状态过短或者不存在会怎么样?

image.png

  • MSL(Maximum Segment Lifetime) 报文最大生存时间
  • 维持2MSL时长的TIME-WAIT状态。保证至少一次报文的往返时间内端口是不可复用

image.png

TIME_WAIT优化

net.ipy4.tcp_tw_reuse = 1 # 开启后,作为客户端时新连接可以使用仍然处于TIME-WAIT状态的端口
net.ipv4.tcp_timestamps = 1 # 由于timestamp的存在,操作系统LASTACK可以拒绝迟到的报文

TIME WAIT优化

net.ipv4.tcp_tw_recycle = ( # 开启后,同时作为客户端和服务器都可以使用TIME-WAIT状态的端口。 不安全,无法避免报文延迟、重复等给新连接造成混乱
net.ipv4.tcp_max_tw_buckets = 262144 # time wait状态连接的最大数量 超出后直接关闭连接

11.lingering_close延迟关闭TCP连接

lingering close延迟关闭的意义

当Nginx处理完成调用close关闭连接后,若接收缓冲区仍然收到客户端发来的内容,则服务器会向客户端发送RST包关闭连接,导致客户端由于收到RST而忽略了http response

lingering配置指令

lingering_close on; 
# of:关闭功能
# on:由Nginx判断,当用户请求未接收完 (根据chunk或者Content-Length头部等)时启用功能,否则
# 及时关闭连接
# alwvays:无条件启用功能
lingering_time 30s; # 当功能启用时,最长的读取用户请求内容的时长,达到后立刻关闭连接
lingering_timeout 5s;   #当功能启用时,检测客户端是否仍然请求内容到达,若超时后仍没有数据到达,则立刻关闭连接

以RST代替正常的四次握手关闭连接

当其他读、写超时指令生效引发连接关闭时,通过发送RST立刻释放端口、内存等资源来关闭连接 reset_timedout_connection off;

12.应用层协议的优化

TLS/SSL优化握手性能

off # 不使用Session缓存,且Nginx在协议中明确告诉客户端Session缓存不被使用
none # 不使用Scssion缓存
builtin # 使用Openssl的Session缓存,由于在内存中使用,所以仅当同一客户端的两次连接都命中到同一个worker进程时,Session缓存才会生效shared;name:size

# 定义共享内存,为所有worker进程提供Session缓存服务。1MB大约可用于4000个Session

TLS/SSL中的会话票证tickets

Nginx将会话Session中的信息作为tickets加密发给客户端,当客户端下次发起TLS连接时带上tickets,由Nginx解密验证后复用会话Session。

会话票证虽然更易在Nginx集群中使用,但破坏了TLS/SSL的安全机制,有安全风险,必须频繁更换tickets家钥。

ssl_session_tickets on #是否开启会话票证服务:
ssl_session_ticket_key file; #使用会话票证时加密tickets的密钥文件:

HTTP长连接

优点:

  • 减少握手次数
  • 通过减少并发连接数减少了服务器资源的消耗
  • 降低TCP拥塞控制的影响
keepalive_requests 100;  

gzip压缩

  • 功能: 通过实时压缩http包体,提升网络传输效率
  • 模块: ngx_http_gzip_module,通过--without-http_gzip_module禁用模块

gzip on | off;

压缩哪些请求的响应?

Syntax: gzip_types mime-type ...;
Default: gzip_types text/html;

Syntax: gzip_min_length length;
Default: gzip_min_length 20;

Syntax: gzip_disable regex ...;

Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;

是否压缩上游的响应

gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag |
auth | any ...;

gzip_proxied off;

of #不压缩来自上游的响应
expired #如果上游响应中含有Expires头部,且其值中的时间与系统时间比较后确定不会缓存,则压缩响应
no-cache #如果上游响应中含有“Cache-Control”头部,目其值含有”no-cache”值,则压缩响应
nostorc #如果上游响应中含有“Cache-Control”头部,且其值含有”no-store"值,则压缩响应
nrivule #如果上游响应中含有“Cache-Control”头部,且其值含有”private”值,则压缩响应
no_last_modified #如果上游响应中没有“Last-Modified” 头部,则压缩响应
no_etag #如果上游响应中没有“ETag” 头部,则压缩响应
auth #如果客户端请求中含有“Authorization”头部,则压缩响应
any #压缩所有来自上游的响应

其他压缩参数

gzip_comp_level 1; 
gzip_buffers 32 4k|16 8k; 
gzip_vary on | off;

升级更高效的http2协议

  • 向前兼容http/1.x协议
  • 传输效率大幅度提升

13.磁盘IO的优化

磁盘介质

机械硬盘

  • 价格低
  • 存储量大
  • BPS较大:适用于顺序读写
  • IOPS较小
  • 寿命长

固态硬盘

  • 价格高
  • 存储量小
  • BPS大
  • IOPS大: 适用于随机读写
  • 写寿命短

减少磁盘IO

优化读取

  • Sendfile零拷贝
  • 内存盘、SSD盘

减少写入

  • AIO
  • 增大error_log级别
  • 关闭access_log
  • 压缩access_log
  • GVEETEDAS
  • 是否启用proxy_buffering?
  • syslog替代本地IO

线程池thread pool

直接IO绕开磁盘高速缓存

image.png

  • 从用户缓冲区 到 磁盘 中间会有个内核缓存区,每次读写都需要经过这个“内核缓冲区”,用于下次一样数据的时候提高读写速度。
  • 到时如果都是变化的数据,则效率很低。可以设置跳过高速缓冲区。也叫直接IO

适用于大文件:直接IO

当磁盘上的文件大小超过size后,启用directIo功能,避免Buffered IO模式下磁盘页缓存中的拷贝消耗

Syntax: directio size | off;
Default: directio off;

Syntax: directio_alignment size;
Default: directio_alignment 512; 

14.异步IO

image.png

Syntax: aio on | off | threads[=pool];
Default: aio off;

Syntax: aio_write on | off;
Default: aio_write off; 

异步读I0线程池

image.png 编译时加--with-threads

定义线程池

Syntax: thread_pool name threads=number [max_queue=number];
Default: thread_pool default threads=32 max_queue=65536;
Context: main

15.减少磁盘读写次数

empty_gif模块

模块: ngx http empty_gif module模块,通过--without-http empty gif module禁用模块

功能:

从前端页面做用户行为分析时,由于跨域等要求,前端打点的上报数据一般是GET请求,且考虑到浏览器解析DOM树的性能消耗,所以请求透明图片消耗最小,而1*1的gif图片体积最小(仅43字节),故通常请求gif图片,并在请求中把用户行为信息上报服务器。

Nginx可以在access日志中获取到请求参数,进而统计用户行为。但若在磁盘中读取Ixl的文件则有磁盘IO消耗,empty_gif模块将图片放在内存中,加快了处理速度

empty gif;

access日志的压缩

Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
Default: access_log logs/access.log combined;
# buffer默认64KB
# gzip默认级别为1
# 通过zcat解压查看

例子

server {
    server_name localhost;
    listen 8330;
    access_log logs/compressed.log main buffer-32k gzip-2 flush=5s;
    root html;
    location / {
        return 200;
    }
}

16.error_log日志输出内存

场景: 在开发环境下定位问题时,若需要打开dcbug级别日志,但对debug级别大量日志引发的性能问题不能容忍,可以将日志输出到内存中

# 测试
#nginx 配置语法:
error_log_memory:32m debug;
ps -ef | grep nginx # 找到 对应的work id
# 查看内存中日志的方法:
gdb -p [worker(!id] -ex "source nginx.gdb" --batch
# gdb -p 16327 -ex "source nginx.qdb" -batch
#nginx.gdb脚本内容
set $log = ngx_cycle->log
while $log->writer != ngx_log_memory_writer
set $log = $log->next
end
set $buf = (ngx_log_memory_buf_t *) $log->wdata
dump binary memory debug_log.txt $buf->start $buf->end 

syslog协议

nginx.org/en/docs/sys…

server # 定义syslog服务器地址.
facility # 参见RFC3164,取值:“kemn""user""daemon""auth""mail"uucp”,"clock""authpriv”,"ftp""intern”,"lpr""news“ntp”,"audit”,"alert” ,"cron” ,“local0” .. "local7"
# 默认locaI7
severity # 定义access.log日志的级别,默认info级别
tag # 定义日志的tag,默认为”nginx”
nohostname # 不向syslog中写入主机名hostname

rsyslog与nginx

# rsyslog配置:
vi /etc/rsyslog.conf

SModLoad imudp
SUDPServerRun 514
local6.*  /var/log/nginx.log 

# nginx配置 
server {
    server_name localhost;
    listen 8330; 
    # 127.0.0.1:514 为本地log服务
    access log syslog:server=127.0.0.1:514,facility-local6,nohostname,tag-nginx,severity=info main;
    root html;
    local / {
        return 200;
    }
} 
# 测试 
 tcpdump -i lo port 514 -A -s 0

17.零拷贝与 gzip_static模块

sendfile零拷贝提升性能

应用程序直接到 硬盘或网卡,不经过内核缓存。

  • 减少进程间切换
  • 减少内存拷贝次数

直接IO自动禁用sendfile

location /video/ {
    sendfile on;
    aio on;
    directio 8m;
} 

当文件大小超过8M时,启用AIO与directio

18.gzip _static模块

模块: ngx_http_gzip_static_module,通过--with-http_gzip_static_module启用模块 功能: 检测到同名.gz文件时,response中以gzip相关header返回.gz文件的内容

Syntax: gzip_static on | off | always;
Default: gzip_static off;

gunzip模块

模块: ngx_http_gunzip_module 当客户端不支持gzip时,且磁盘上仅有压缩文件,则实时解压缩并将其发送给客户端

gunzip on | off;
gunzip_buffers 32 4k|16 8k;  # gunzip_buffers number size;

19.用tcmalloc优化内存分配

tcmalloc

  • 更快的内存分配器.
  • 并发能力强于glibce
  • 并发线程数越多,性能越好
  • 减少内存碎片
  • 擅长管理小块内存

goog-perftools.sourceforge.net/doc/tcmallo…

使用方式


# 编译google_perf_tools,得到tcmalloc库
https://github.com/gperftools/gperftools/releases
编译nginx时,加入编译选项
C语言生成可执行文件的两个步骤通过configurc设定编译的额外参数--with-cc-opt-OPTIONS通过configurc设定链接的额外参数
set additional C compiler options
--with-ld-opt-OPTIONS
sct additional linker options
--with-ld-opt--ltmalloc --with-google_perftools_module

20.使用Google PerfTools分析Nginx

gperftools库:
https://github.com/gperftools/eperftools/releases

pprof--text # 。文本展示
pprof --pdf # 图形展示: 
依赖graphviz
依赖: https://github.com/libunwind/libunwind/releases
模块: ngx_google_perftoos module,通过--with-google_perftools_module启用

# nginx 配置 
google_perftools_profiles file;
# 如: google_perftools_profiles /tmp/tcmalloc/openresty_tcmalloc;

pprof --text  /tmp/tcmalloc/openresty_tcmalloc.9912 # 文字化显示
pprof --pdf  /tmp/tcmalloc/openresty_tcmalloc.9912 # 图形化显示


# 文本风格结果 
2 0.9% 51.3%166 73.5% ngx epoll process events
1 0.4% 96.5%2 0.9% ngx open and stat file
意义: 每统计周期是10毫秒
第1列:当前函数的执行总共花的统计周期数
第2列:当前函数执行时间的百分比
第3列:当前函数及其之前的函数调用执行时间的百分比
第4列:当前函数及其所调用函数消耗的统计周期数总和
第5列:当前函数及其所调用函数执行时间总和的百分比
第6列:函数名称

21.使用stub_status模块监控Nginx的状态

模块: ngx_http_stub_status_module,通过---with-http_stub_status_module启用模块 功能:通过HTTP接口,实时监测nginx的连接状态。统计数据存放于共享内存中,所以统计值包含所有worker进程,且执行reload不会导致数据清0,但热升级会导致数据清0

Syntax: stub_status;

stub_status 模块的监控项

# 输出内容
Active connections: 1
server accepts handled requests
2511 2511 4764
Reading: 0 Writing: 1 Waiting:0

# 字段说明
Active conneetions  # 当前客户端与Nginx间的TCP连接数,等于下面Reading、 Writing、 Waiting数量之和。 
accepts # 自Nginx启动起,与客户端建立过的连接总数
handled #自Nginx启动起,处理过的客户端连接总数。如果没有超出worker connections配置,该值与accepts相同
requests # 自Nginx启动起,处理过的客户端请求总数。由于存在HTTP Keep-Alive请求,故requests值会大于handled值
Reading # 正在读取HTTP请求头部的连接总数
Writing # 正在向客户端发送响应的连接总数
Waiting #当前空闲的HTTP Keep-Alive连接总数

例子

server {
    server_name localhost;
    listen 8331; 
    root html;
    location /stub_status {
        stub_status;
    }
}
# 测试 
curl localhost:8331/stub_status

参考

time.geekbang.org/course/intr…