一、系统性能分析工具:sysstat之sar命令
服务器维护常用的管理命令有很多:top、ps,、pstree、vmstat、iostat、iotop等,但好像都不全面,这里有一个比较系统全面的性能分析工具sar(System Activity Reporter系统活动情况报告)。
sar可以从多方面对系统的活动进行报告,包括文件的读写、系统调用、磁盘I/O、CPU效率、内存状况、进程活动及IPC有关的活动等。sar和iotop、iostat在一起,林戈技术笔记 8408.cn___一名IT人员的在线技术笔记 ,
通过yum安装sysstat来实现功能:yum install -y sysstat
sar命令常用格式 sar [options] [-A] [-o file] t [n]
t为采样间隔,n为采样次数,默认值是1;
-o file表示将命令结果以二进制格式存放在文件中,file 是文件名。
options 为命令行选项
1. sar命令常用选项如下:
[hello@07 ~]# sar --help
Usage: sar [ options ] [ <interval> [ <count> ] ]
Options are:
[ -A ] [ -b ] [ -B ] [ -C ] [ -d ] [ -h ] [ -m ] [ -p ] [ -q ] [ -r ] [ -R ]
[ -S ] [ -t ] [ -u [ ALL ] ] [ -v ] [ -V ] [ -w ] [ -W ] [ -y ]
[ -I { <int> [,...] | SUM | ALL | XALL } ] [ -P { <cpu> [,...] | ALL } ]
[ -j { ID | LABEL | PATH | UUID | ... } ] [ -n { <keyword> [,...] | ALL } ]
[ -o [ <filename> ] | -f [ <filename> ] ] [ --legacy ]
[ -i <interval> ] [ -s [ <hh:mm:ss> ] ] [ -e [ <hh:mm:ss> ] ]
2. sar命令的选项意义如下:
-A:所有报告的总和
-u:输出CPU使用情况的统计信息
-v:输出inode、文件和其他内核表的统计信息
-d:输出每一个块设备的活动信息
-r:输出内存和交换空间的统计信息
-b:显示I/O和传送速率的统计信息
-a:文件读写情况
-c:输出进程统计信息,每秒创建的进程数
-R:输出内存页面的统计信息
-y:终端设备活动情况
-w:输出系统交换活动信息
3. CPU资源监控
[hello@007 ~]# sar -u 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
03:57:10 PM CPU %user %nice %system %iowait %steal %idle
03:57:11 PM all 0.00 0.00 0.00 0.00 0.00 100.00
03:57:12 PM all 0.99 0.00 0.99 0.00 0.00 98.02
03:57:13 PM all 0.00 0.00 0.00 1.01 0.00 98.99
Average: all 0.33 0.00 0.33 0.33 0.00 99.00
%iowait:显示用于等待I/O操作占用 CPU 总时间的百分比。
%steal:管理程序(hypervisor)为另一个虚拟进程提供服务而等待虚拟 CPU 的百分比。
%idle:显示 CPU 空闲时间占用 CPU 总时间的百分比。
1. 若 %iowait 的值过高,表示硬盘存在I/O瓶颈
2. 若 %idle 的值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量
3. 若 %idle 的值持续低于1,则系统的 CPU 处理能力相对较低,表明系统中最需要解决的资源是CPU
4. inode、文件和其他内核表监控
[hello@007 ~]# sar -v 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
03:57:38 PM dentunusd file-nr inode-nr pty-nr
03:57:39 PM 20890 1408 26456 2
03:57:40 PM 20899 1408 26465 2
03:57:41 PM 20907 1408 26473 2
Average: 20899 1408 26465 2
dentunusd:目录高速缓存中未被使用的条目数量
file-nr:文件句柄(file handle)的使用数量
inode-nr:索引节点句柄(inode handle)的使用数量
pty-nr:使用的pty数量
5. 内存和交换空间监控
[hello@007 ~]# sar -r 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
04:00:53 PM kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit
04:00:54 PM 71736 948272 92.97 50888 371260 1183812 116.06
04:00:55 PM 71736 948272 92.97 50888 371260 1183812 116.06
04:00:56 PM 71736 948272 92.97 50896 371260 1183812 116.06
Average: 71736 948272 92.97 50891 371260 1183812 116.06
%memused:这个值是kbmemused和内存总量(不包括swap)的一个百分比.
kbcommit:保证当前系统所需要的内存,即为了确保不溢出而需要的内存(RAM+swap).
%commit:这个值是kbcommit与内存总量(包括swap)的一个百分比.
6. 内存分页监控
[hello@007 ~]# sar -B 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
03:58:32 PM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
03:58:33 PM 0.00 432.65 32.65 0.00 56.12 0.00 0.00 0.00 0.00
03:58:34 PM 0.00 0.00 35.00 0.00 59.00 0.00 0.00 0.00 0.00
03:58:35 PM 0.00 0.00 667.00 0.00 922.00 0.00 0.00 0.00 0.00
Average: 0.00 142.28 246.31 0.00 347.65 0.00 0.00 0.00 0.00
pgpgin/s:表示每秒从磁盘或SWAP置换到内存的字节数(KB)
pgpgout/s:表示每秒从内存置换到磁盘或SWAP的字节数(KB)
fault/s:每秒钟系统产生的缺页数,即主缺页与次缺页之和(major + minor)
majflt/s:每秒钟产生的主缺页数.
pgfree/s:每秒被放入空闲队列中的页个数
pgscank/s:每秒被kswapd扫描的页个数
pgscand/s:每秒直接被扫描的页个数
pgsteal/s:每秒钟从cache中被清除来满足内存需要的页个数
%vmeff:每秒清除的页(pgsteal)占总扫描页(pgscank+pgscand)的百分比
7. I/O和传送速率监控
[hello@007 ~]# sar -b 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
04:01:32 PM tps rtps wtps bread/s bwrtn/s
04:01:33 PM 0.00 0.00 0.00 0.00 0.00
04:01:34 PM 0.00 0.00 0.00 0.00 0.00
04:01:35 PM 0.00 0.00 0.00 0.00 0.00
Average: 0.00 0.00 0.00 0.00 0.00
tps:每秒钟物理设备的 I/O 传输总量
rtps:每秒钟从物理设备读入的数据总量
wtps:每秒钟向物理设备写入的数据总量
bread/s:每秒钟从物理设备读入的数据量,单位为 块/s
bwrtn/s:每秒钟向物理设备写入的数据量,单位为 块/s
8. 进程队列长度和平均负载状态监控
[hello@007 ~]# sar -q 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
04:01:59 PM runq-sz plist-sz ldavg-1 ldavg-5 ldavg-15
04:02:00 PM 0 277 0.00 0.00 0.00
04:02:01 PM 1 279 0.00 0.00 0.00
04:02:02 PM 0 278 0.00 0.00 0.00
Average: 0 278 0.00 0.00 0.00
runq-sz:运行队列的长度(等待运行的进程数)
plist-sz:进程列表中进程(processes)和线程(threads)的数量
ldavg-1:最后1分钟的系统平均负载(System load average)
ldavg-5:过去5分钟的系统平均负载
ldavg-15:过去15分钟的系统平均负载
9. 系统交换活动信息监控
[hello@007 ~]# sar -W 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
04:02:29 PM pswpin/s pswpout/s
04:02:30 PM 0.00 0.00
04:02:31 PM 0.00 0.00
04:02:32 PM 0.00 0.00
Average: 0.00 0.00
pswpin/s:每秒系统换入的交换页面(swap page)数量
pswpout/s:每秒系统换出的交换页面(swap page)数量
10. 网卡流量监控
[hello@007 ~]# sar -n DEV 1 3
Linux 2.6.32-642.6.2.el6.x86_64 (04007.cn) 08/09/2019 _x86_64_ (1 CPU)
04:27:53 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
04:27:54 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:54 PM eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:54 PM eth1 2.02 1.01 0.12 0.12 0.00 0.00 0.00
04:27:54 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
04:27:55 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:55 PM eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:55 PM eth1 1.00 1.00 0.06 0.18 0.00 0.00 0.00
04:27:55 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
04:27:56 PM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:56 PM eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:27:56 PM eth1 1.01 1.01 0.07 0.48 0.00 0.00 0.00
Average: IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
Average: lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: eth0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Average: eth1 1.34 1.01 0.08 0.26 0.00 0.00 0.00
IFACE:表示设备名称
rxpck/s:表示每秒进入收取包的数量
txpck/s:每秒发送出去的包的数量
rxKB/s:每秒收取的数据量(单位KByte)
txKB/s:每秒发送的数据量
如果服务器丢包严重,就要查看一下网卡流量
如果rxpck/s数值大于4000,或者rxKB/大于5000,很有可能被×××了。
查看时时网卡流量 sar -n DEV 1 5
查看某一天的网卡流量历史 sar -n DEV -f /var/log/sa/文件名
在/var/log/sa/中有两种文件,sa开头加日期不能直接cat查看,只能用sar -f,sar加日期的文件可以直接cat
11. 系统瓶颈判断,有时需几个 sar 命令选项结合起来
怀疑CPU存在瓶颈,可用 sar -u 和 sar -q 等来查看
怀疑内存存在瓶颈,可用 sar -B、sar -r 和 sar -W 等来查看
怀疑I/O存在瓶颈,可用 sar -b、sar -u 和 sar -d 等来查看
二、nginx中打开gzip使用配置gzip_http_version值为1.0和1.1时遇到的结果乱码问题
在进行一套老业务服务器迁移的时候遇到了一个很奇怪的问题,因为发现配置大多一样,因此我将两套原来不一样的业务放到了一起,在所有nginx,php环境及业务代码部署好了之后,开始调试,但发现有一个接口的返回数据就是乱码。这乱码初看起来就是哪里压缩了一样,就想莫不是程序哪里有压缩处理,先对业务的调用进行了一翻梳理,因为是老业务,我之前也基本没有看过,在大致看了一下之后对其调用逻辑了解大致是请求nginx时会去执行lua程序,lua程序中会执行http请求本机,本机rewrite之后会再去调用php取得结果。调试之后得到了请求本机php结果时的URL,但在浏览器中发现请求这个URL返回的结果也是正常的,而就是在lua中请求了这个结果之后才出现了乱码,想来想去是不是在nginx的配置上的问题导致。
对比两个配置文件发现差异:
1. 老服务器配置
gzip on;
gzip_min_length 0k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text/plain text/css text/xml application/x-javascript;
gzip_vary on;
#新服务器配置
gzip on;
gzip_disable "MSIE [1-6]\.";
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 9;
gzip_types text/plain application/json text/javascript application/x-javascript text/css application/xml;
gzip_vary on;
发现有gzip_http_version,gzip_min_length,gzip_types的差异,gzip_types和gzip_min_length应该不会导致问题,那是gzip_http_version导致?于是修改了此项配置改成gzip_http_version 1.1,然后重启nginx发现果真问题出在这里。那是什么原因导致的这个问题呢?
为什么这样呢?我的理解是因为浏览器请求服务端基本都是http/1.1协议通信,而nginx和后端的upstream server之间默认是用HTTP/1.0协议通信的。
上述新服务器配置:nginx的gzip_http_version 配置是1.0,则使用浏览器直接请求服务器是不会被压缩的,因为在这一层上,是没有开启gzip的(1.0不是1。1)。但在后端lua中请求upstream时的通信结果被压缩了,被压缩的结果直接在lua程序中执行返回。所以看到前端返回的数据中callback是正常的字符,而后面的内容是压缩后的乱码。
2. 解决方法:
修改gzip_http_version的值为1.1当然可以解决,这样可以让后端的所有通信结果都不再gzip,从而不会导致被压缩的问题。但我想也应该有其它的办法,比如在lua请求的时候如何能支持gzip的处理。也很简单,可以安装lua_zlib让openresty或nginx可以接收gzip请求并处理解压缩即可。大致的方法如下:
#下载和安装lua_zlib,安装lua_zlib需要lua或luajit的支持,所以在cmake时需要指定lua的路径。
wget https://github.com/brimworks/lua-zlib/archive/master.zip
unzip master.zip
cd lua-zlib-master
cmake -DLUA_INCLUDE_DIR=/usr/local/openresty/luajit/include/luajit-2.1
make
cp zlib.so /usr/local/openresty/lualib/zlib.so
#然后在lua程序中就可以使用lua_zlib来接收gzip请求
local zlib = require "zlib"
local encoding = ngx.req.get_headers()["Content-Encoding"]
ngx.req.read_body();
#判断结果是否被压缩
if encoding == "gzip" then
local body = ngx.req.get_body_data()
if body then
local stream = zlib.inflate()
ngx.req.set_body_data(stream(body))
end
end
另外上述配置中有一项:gzip_vary on;,使用这项配置可以在http响应头中返回Vary: Accept-Encoding标头,如下:
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Fri, 26 Jul 2019 06:16:13 GMT
Server: nginx/1.6.2
Transfer-Encoding: chunked
Vary: Accept-Encoding
指定Vary: Accept-Encoding标头有什么作用呢?它就是告诉代理服务器缓存两种版本的资源:压缩和非压缩,这有助于避免一些公共代理不能正确地检测Content-Encoding标头的问题。有一些网站速度诊断性能优化里项里还有这项,即需要服务器端返回Vary:Accept-Encoding标头,可以把它简单理解成这样,设想有两个客户,一个使用的旧浏览器不支持压缩,一个使用新的浏览器支持压缩,如果他们都请求同一个网页,那么取决于谁先请求,压缩或非压缩版本便存储在CDN上。这样问题就出现了,旧浏览器请求常规网页但获得缓存的压缩版本,而新浏览器会获得缓存的非压缩版本但尝试去“解压”它。无论哪种方式都是坏消息。解决方法是,源服务器回送Vary: Accept-Encoding。