一、初识Nginx

Nginx的三个主要应用场景

1.静态资源服务

  • 通过本地文件系统提供服务

2.反向代理服务

  • Nginx的强大性能
  • 缓存
  • 负载均衡

3.API服务

  • OpenResty

Nginx为什么会出现

  • 互联网的数据量快速增长
    • 互联网的快速普及
    • 全球化
    • 物联网
  • 摩尔定律:性能提升
  • 低效的Apache
    • 一个连接对应一个进程

Nginx的优点

  • 高并发,高性能
    • 主流服务器 32核 64G 轻松达到数千万并发连接
    • 静态文件 百万级 RPS
  • 可扩展性好
  • 高可靠性
  • 热部署
  • BSD许可证

Nginx的组成

  • Nginx二进制可执行文件
    • 由各模块源码编译出的一个文件
  • Nginx.conf配置文件
    • 控制Nginx的行为
  • access.log访问日志
    • 记录每一条http请求信息
  • 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. 每天生成
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 绑定一个域名
  1. 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 &
  1. 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
    • 速度不一致引发阻塞API
      • 硬件执行熟读不一致
    • 业务场景产生阻塞API
      • 例如同步读网络报文
让Nginx进程在运行状态
  • R运行:正在运行或在运行队列中等待
  • S中断
  • D不可中断
  • Z僵死
  • T停止
减少进程间切换
  • Nginx worker尽可能处于R状态
    • R状态的进程数量大于cpu核心时,负载急速增高 uptime
  • 尽可能的减少进程间切换
    • 类别:
      • 主动切换
      • 被动切换:时间片耗尽
    • Cost:<5us 但是百万连接算下来时间就长了
    • 减少主动切换
    • 减少被动切换
      • 增大进程优先级 nice,值越小
  • 绑定CPU
    • 可以利用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命令 PRNI列值

  • nice 静态优先级:-20 ~ 19
  • priority 动态优先级:0 ~ 139
O1调度算法(CFS)
  • 优先级动态调整
    • 幅度 +-5
    • 依据
      • cpu消耗型进程
      • io消耗性进程
  • 分时:时间片
    • 5ms ~ 800ms 尽量让Nginx用到800
设置worker进程的静态优先级
1
2
3
Syntax: worker_priority number;
Default: worker_priority 0;
Context: main
worker进程间负载均衡
  • 使用 reuseport
多队列网卡对多核CPU的优化
  • RSS:硬件中断负载均衡
  • RPS:软中断负载均衡
  • RFS
提升CPU缓存命中率
  • 绑定worker到指定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