一、初识Nginx
Nginx的三个主要应用场景
1.静态资源服务
2.反向代理服务
3.API服务
Nginx为什么会出现
- 互联网的数据量快速增长
- 摩尔定律:性能提升
- 低效的Apache
Nginx的优点
- 高并发,高性能
- 主流服务器 32核 64G 轻松达到数千万并发连接
- 静态文件 百万级 RPS
- 可扩展性好
- 高可靠性
- 热部署
- BSD许可证
Nginx的组成
- Nginx二进制可执行文件
- Nginx.conf配置文件
- access.log访问日志
- error.log错误日志
Nginx版本发布(mainline)
版本选择
编译nginx
按模块需要编译安装
access log分析
使用GoAccess工具 https://goaccess.io/
安装
1
2
3
4
5
6
7
|
$ wget http://tar.goaccess.io/goaccess-1.2.tar.gz
$ tar -xzvf goaccess-1.2.tar.gz
$ cd goaccess-1.2/
# ./configure --help 查看选项
$ ./configure --enable-utf8 --enable-geoip=legacy
$ make
# make install
|
校对nginx和goaccess日志格式
- 配置nginx.conf中
http{}
log_format
中的日志格式(改完记得重启nginx服务),如:
1
2
3
4
5
6
7
8
9
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$connection $upstream_addr '
'$upstream_response_time $request_time';
|
- 使用
nginx2goaccess.sh
脚本将nginx日志格式格式化为goaccess能识别的日志格式,nginx2goaccess.sh
脚本内容在 https://github.com/stockrt/nginx2goaccess.git
1
2
3
4
|
# log_format为你nginx.conf中配置的日志格式
# sh nginx2goaccess.sh '<log_format>'
# 示例:
$ sh nginx2goaccess.sh '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $connection $upstream_addr $upstream_response_time $request_time'
|
- 得到三个格式 追加到
/usr/local/etc/goaccess.conf
文件末尾中
1
2
3
|
time-format %T
date-format %d/%b/%Y
log_format %h - %^ [%d:%t %^] "%r" %s %b "%R" "%u" "%^" %^ %^ %^ %T
|
生成统计页面
上面三行分别是时间、日期、日志格式,将三行输出保存到任意文件,然后就可以开始生成html可视化文件
- 每天生成
1
|
00 00 * * * /usr/local/bin/goaccess /home/wwwlogs/www.stormwan.com.log -o /home/www/goaccess-html/index.html -p /usr/local/etc/goaccess.conf
|
选项说明:
- -f 指定nginx日志文件
- -p 指定日志格式文件
- -o 输出到指定html文件
- –real-time-html 实时刷新
- –ws-url 绑定一个域名
- html可视化文件的实时更新方法
1
|
nohup /usr/local/bin/goaccess -f /home/wwwlogs/www.stormwan.com.log -p /usr/local/etc/goaccess.conf -o /home/www/goaccess-html/index.html --real-time-html --ws-url=xxx.xxx.com &
|
- nginx日志切割后,后续再补充统计页面
awk 日志统计
Nginx Access Log日志统计分析常用命令
IP相关统计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# 统计IP访问量
$ awk '{print $1}' www.stormwan.com.log | sort -n | uniq | wc -l
1024
# 查看某一时间段的IP访问量(4-5点)
$ grep "30/May/2020:0[4-5]" www.stormwan.com.log | awk '{print $1}' | sort | uniq -c| sort -nr | wc -l
$ grep "30/May/2020:0[4-5]" www.stormwan.com.log | awk '{print $1}' | sort | wc -l
4
# 查看访问最频繁的前100个IP
$ awk '{print $1}' www.stormwan.com.log | sort -n | uniq -c | sort -rn | head -n 100
396 180.76.170.52
215 87.233.164.92
196 91.121.106.106
140 113.89.238.19
137 47.107.232.133
...
# 查询某个IP的详细访问情况,按访问频率排序
$ grep '180.76.170.52' www.stormwan.com.log |awk '{print $7}'|sort |uniq -c |sort -rn |head -n 100
33 /
4 /categories/
4 /about/
3 /tags/vagrant/
3 /tags/seo/
3 /tags/redis/
3 /tags/php/
|
页面访问统计
1
2
3
4
5
6
7
8
9
10
11
|
# 查看访问最频的页面(TOP100)
$ awk '{print $7}' www.stormwan.com.log | sort |uniq -c | sort -rn | head -n 100
# 查看访问最频的页面([排除php页面】(TOP100)
$ grep -v ".php" www.stormwan.com.log | awk '{print $7}' | sort |uniq -c | sort -rn | head -n 100
# 查看页面访问次数超过100次的页面
$ cat www.stormwan.com.log | cut -d ' ' -f 7 | sort |uniq -c | awk '{if ($1 > 100) print$0}' | less
# 查看最近1000条记录,访问量最高的页面
$ tail -1000 www.stormwan.com.log |awk '{print $7}'|sort|uniq -c|sort -nr|less
|
每秒请求量统计
1
2
3
4
5
6
7
8
|
# 统计每秒的请求数,top100的时间点(精确到秒)
awk '{print $4}' www.stormwan.com.log |cut -c14-21|sort|uniq -c|sort -nr|head -n 100
# 统计每分钟的请求数,top100的时间点(精确到分钟)
awk '{print $4}' www.stormwan.com.log |cut -c14-18|sort|uniq -c|sort -nr|head -n 100
# 统计每小时的请求数,top100的时间点(精确到小时)
awk '{print $4}' www.stormwan.com.log |cut -c14-15|sort|uniq -c|sort -nr|head -n 100
|
性能分析
1
2
3
4
5
6
7
8
9
|
# 在nginx log中最后一个字段加入$request_time 列出传输时间超过 3 秒的页面,显示前20条
$ cat www.stormwan.com.log|awk '($NF > 3){print$7}'|sort -n|uniq -c|sort -nr|head -20
# 打印时间 非php页面
$ grep -v '.php' www.stormwan.com.log|awk '($NF > 3){print$NF,$7}'|sort -n|uniq -c|sort -nr|head -20
$ grep -v '.php' www.stormwan.com.log|awk '($NF > 3){print$7,$NF}'|sort -n|uniq -c|sort -nr|head -20
# 列出php页面请求时间超过3秒的页面,并统计其出现的次数,显示前100条
$ cat www.stormwan.com.log|awk '($NF > 3 && $7~/\.php/){print$7}'|sort -n|uniq -c|sort -nr|head -100
|
接下来就可以针对慢接口进行性能优化
蜘蛛抓取统计
1
2
3
4
5
|
# 统计蜘蛛抓取次数
grep 'Baiduspider' www.stormwan.com.log |wc -l
# 统计蜘蛛抓取404的次数
grep 'Baiduspider' www.stormwan.com.log |grep '404' | wc -l
|
404统计
1
2
3
|
# 统计2020-05-29 404 前后加个空格 日志中文本包含404 影响状态码
$ grep '29/May/2020' www.stormwan.com.log |grep ' 404 ' | wc -l
$ awk '/29\/May\/2020/ {if ($9 == 404) print$9}' www.stormwan.com.log | wc -l
|
本站访问分析
二、Nginx架构基础
三、详解HTTP模块
四、反向代理与负载均衡
五、Nginx的系统层性能优化
优化方法论
- 从软件层面提升硬件使用效率
- 增大CPU的利用率
- 增大内存利用率
- 增大磁盘IO利用率
- 增大网络带宽的利用率
- 提升硬件规格
- 网卡:万兆网卡,例如10G、25G、40G等
- 磁盘:固态硬盘,关注IOPS和BPS指标
- CPU:更快的主频,更多的核心,更大的缓存,更优的架构
- 内存:更快的访问速度
- 超出硬件性能上限后使用DNS
增大Nginx使用CPU的有效时长
- 能够使用全部CPU资源
- Nginx进程间不做无用功浪费CPU
- 不被其他进程争抢资源
设置worker进程的数量
1
2
3
4
|
# 可配置为 auto
Syntax: worker_processes number | auto;
Default: worker_processes 1;
Context: main
|
一个CPU同时运行多个进程
- 宏观上并行,微观上串行
- 阻塞API引发的时间片主动让出CPU
让Nginx进程在运行状态
- R运行:正在运行或在运行队列中等待
- S中断
- D不可中断
- Z僵死
- T停止
减少进程间切换
- Nginx worker尽可能处于R状态
- R状态的进程数量大于cpu核心时,负载急速增高
uptime
- 尽可能的减少进程间切换
- 类别:
- Cost:<5us 但是百万连接算下来时间就长了
- 减少主动切换
- 减少被动切换
- 绑定CPU
延迟处理新连接
1
2
3
4
|
# 使用 TCP_DEFER_ACCEPT 延迟处理新连接
Syntax: listen address[:port] [deferred];
Default: listen *:80 | *:8000;
Context: server
|
上下文切换次数
vmstat
system 列 cs 值
dstat
system 列 csw 值
pidstat -w
cswch/s 列值
调整CPU时间片大小
top
命令 PR
和NI
列值
- nice 静态优先级:
-20 ~ 19
- priority 动态优先级:
0 ~ 139
O1调度算法(CFS)
- 优先级动态调整
- 分时:时间片
5ms ~ 800ms
尽量让Nginx用到800
设置worker进程的静态优先级
1
2
3
|
Syntax: worker_priority number;
Default: worker_priority 0;
Context: main
|
worker进程间负载均衡
多队列网卡对多核CPU的优化
- RSS:硬件中断负载均衡
- RPS:软中断负载均衡
- RFS
提升CPU缓存命中率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
Syntax: worker_cpu_affinity cpumask ...;
worker_cpu_affinity auto [cpumask];
Default: —
Context: main
# 示例
# 2核cpu,开启2个进程
worker_processes 2;
worker_cpu_affinity 01 10;
# 2核cpu,开启4个进程
worker_processes 4;
worker_cpu_affinity 01 10 01 10;
# 4核cpu,开启4个进程 0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
# 4核cpu,开启2个进程
worker_processes 2;
worker_cpu_affinity 0101 1010;
# 8核cpu,开启8个进程 worker_processes最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
|
六、从源码视角深入使用Nginx与OpenResty