分类 Linux运维 下的文章

几年前在深信服工作时整理出来的一篇文章,突然需要找了好久才找到,归档记录一下。

一、负载高的原因

通常,我们说的负载高是指CPU高,因为负载的直接体现是CPU。CPU在某个时刻要处理的任务多了,处理不过来,就会出现负载高的情况。

导致负载高的问题主要有以下几个:

  • CPU自身性能不够,系统和任务多,无法处理这么多任务。
  • 内存不足,会频繁触cache回收,有时会杀掉很多进程,导致CPU高。
  • IO高,进程持续高IO读写,导致CPU大部分时间都用来处理系统IO了。

排查负载的的主要思路:uptime ==> mpstat ==> free ==> dmesg ==> tcpdump。

二、分析CPU占用

2.1 分析uptime

uptime命令可以看到系统的运行时间,和当前系统负载:

12:46:32 up 148 days, 19:18, 2 users, load average: 0.00, 0.01, 0.05 

后面的load average表示系统的负载,三个数值分别表示1分钟、5分钟以及15分钟的平均负载。“负载”可以简单理解成当前CPU需要执行的任务数量,如果同一时刻CPU只用处理1个或者1个不到的任务,那么基本上是没有问题的,可以认为CPU不是那么繁忙。如果同一时刻负载需要处理2个、3个甚至更高,CPU可能就比较繁忙了。

一般来说,当单核CPU负载超过3时,就可以认为负载较高了。注意这里说的是单核CPU,如果是多核,对应的负载也要乘以核数。如当前系统核数等于4,那么负载超出12就是比较高的。当然,这个3也不是严格固定的,只是一个大概的范围,负载高低可以根据这个因子大概推断。例如4核的设备,负载在10左右也属于偏高了。

这个3是根据历史数据分析大概得到的,并非完全的界定值。具体是否高还需要分析mpstat数据,两者结合来看。在多核CPU场景(特别是CPU数量较多的时候,如56核、96核的设备),可能某些CPU已经跑满了,但是实际的负载就被平均下来了。

查看CPU核数的办法:

cat /proc/cpuinfo | grep name | wc -l

设备的负载状态可以使用uptime分析工具来辅助分析,把黑匣子中整天的uptime数据直接复制进去就可以画出负载图形:

image.png

根据趋势图很容易就能看到负载高的时间点,然后根据时间点去看mpstat记录,定位具体导致负载高的原因。

2.2 mpstat分析

mpstat是对CPU的抽样,基本的用法:

mpstat -P ALL 1 3

参数-P ALL表示打印出所有CPU的采样数据,ALL也可以改成对应的CPU号表示显示指定CPU抽样数据。如果不加这个参数,命令只会打出所有CPU的平均值,不会打印出详细的每个CPU数据。后面的1 3表示每1秒打印1次,一共打印3次,3也可以省略,命令会一直持续打。输出的内容:

Linux 3.10.0-957.21.3.el7.x86_64 (vm2019)     04/14/2020     _x86_64_    (2 CPU)

11:33:26 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
11:33:27 PM  all    0.00    0.00    0.51    0.00    0.00    0.00    0.00    0.00    0.00   99.49
11:33:27 PM    0    0.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   99.00
11:33:27 PM    1    0.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00   99.00

每一列的数之表示当前模块占用的CPU百分比,最后一列idle表示空闲比例。其他常见列的含义:

  • usr: CPU花费在用户态调用的时间
  • nice: CPU花费在程序调度上时间
  • sys: CPU花费在系统调用上的时间
  • iowait: CPU花费在IO上的时间
  • irq: CPU花费在硬件中断上的时间
  • soft: CPU花费在软件中断上的时间

usr/sys/nice高

usr和sys和nice高比较少见,它们高基本上是应用层程序占用导致,如果是他们高,下一步思路是定位到具体的应用程序。常见的办法是通过top命令跟踪看到底是哪个程序占用的CPU:

执行top命令后,会展示出当前系统环境下进程的资源消耗,默认每秒会统计一次并刷新。同时,这个界面是一个交互式的界面,还可以继续输入参数进去,可以用来对进程排序等A座。例如判断CPU占用的场景,可以输入P来对进程CPU使用排序。因此很容易能找到占用CPU高的程序,然后根据进程功能和工作场景判断,或者使用第三方profile工具来对程序抽样。

iowait高

iowait高有两种常见的场景:

  1. 进程在进行大量IO操作
  2. 内存不足,释放系统在回收cache资源

低端平台下的大部分场景,都是内存不足导致的,内存不足触发cache回收,把缓存的IO数据瞬间刷到磁盘,导致iowait高。

这一点在下面的内存分析中会再详细说明。

soft高

soft高表示设备软中断多,这种情况下,多半是网络环境中存在异常流量,要针对LAN或者WAN抓包分析数据。

抓包主要分析的要素:

  1. SYN/FIN等包的比例是否正常,如果比例超过总抓包数量的10,就很异常了。
  2. 数据包内容是否有问题,这里经常出现问题的就是代理环境,经常有客户端的包都是错误的。
  3. 流量流速是否正常,是否有突发流量。

异常流量可以参考上面的案例来抓包排查,异常流量一般都是很难定位的,需要大量的抓包和分析才行。

三、分析内存

查看系统当前内存状态的命令是free,输出内容为:

[maqianos@vm2019:~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:           3789        1408         367           0        2013        2070
Swap:             0           0           0

这里需要重点关注的是free和cache两列,free表示的是剩余内存,cache表示的是缓存下来的IO数据。linux为了提升系统性能,会把一部分IO数据缓存在内存里面,内存不足或者触发了回收的阈值时,会自动清理cache,把数据写到磁盘。很多时候,cache会突然下降了几百兆,造成IO高,CPU瞬间跑满。

这些cache也是可以执行命令手动释放的:

echo 3 > /proc/sys/vm/drop_caches

除了free以外,top命令也可以统计进程占用的内存大小,执行完top后输入M可以对进程占用的内存排序。这样很容易定位到内存的使用者,如果能发现内存在持续增长,说明可能存在内存泄漏,需要调试进程的内存泄露。

四、流量分析

流量是负载分析中最重要的一环,很多场景负载高都是因为流量导致的。分析流量就是要抓包,流量异常的场景,抓包很容易就能看出来。对流量而言,一个非常重要的信息就是dmesg,流量异常dmesg中会打印很多很明显的日志信息。

例如:

  • Out of socket memory
  • TCP: too many of orphaned sockets
  • TCP: time wait bucket table overflow
  • possible SYN flooding on port 9090. Sending cookies.

这些都是典型的异常日志,属于非业务层面的日志,一旦出现这种问题,就需要重视了。

这种场景就要抓包了,抓包主要需要观察的几个点:

  • 各种数据包比例是否正常,比如SYN/FIN这些特殊包的发包频次,是否特别高。

单用户统计,是否存在单个IP发包特别多的情况。

  • 代理场景下关注代理的数据包是否有问题,腾讯系的产品经常会出现这种问题。

五、参考

alpine无法安装imagemagick问题

使用alpine的docker镜像安装imagemagick时报错:

bash-5.1# apk add imagemagick
fetch https://mirrors.tencent.com/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
ERROR: unable to select packages:
  imagemagick (no such package):
    required by: world[imagemagick]

问题原因:imagemagick属于community包,仓库源中没有配置community的源。

解决方案:在/etc/apk/repositories中添加community源,如:

https://mirrors.tencent.com/alpine/v3.14/community/

使用虚拟机安装CentOS5后,系统没有自动识别网口信息,导致无法配置IP远程登陆。

问题原因:

安装系统的时候,如果选择了系统是CentOS5或者更老的版本,虚拟机会将虚拟网卡设备设置为vmxnet3系列,该系列的网卡为AMD PCNet型号。但当前虚拟机的网卡实际为Intel的网卡,需要使用e1000系列网卡。两者驱动不匹配,系统识别不出来。

解决方案:

先关闭虚拟机。然后虚拟机磁盘的同目录下,找到一个名字为“虚拟机名字.vmx”的文件,是一个1kb左右的文本文件。下载下来修改其中的内容为:

ethernet0.virtualDev = "e1000"

然后再重启虚拟机即可。

centos5已停止了维护,国内大部分的源也停止维护,找了很久都没有找到可用的源。最后才发现,centos早期的源都已经vault.centos.org网站下,国内的镜像源也都改成了centos-vault,不能直接使用centos目录下的源。

腾讯云源:

[base]
name=CentOS-5.8 - Base
#mirrorlist=http://mirrorlist.centos.org/?release=5.8&arch=$basearch&repo=os
baseurl=http://mirrors.cloud.tencent.com/centos-vault/5.8/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

#released updates 
[updates]
name=CentOS-5.8 - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=5.8&arch=$basearch&repo=updates
baseurl=http://mirrors.cloud.tencent.com/centos-vault/5.8/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

#additional packages that may be useful
[extras]
name=CentOS-5.8 - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=5.8&arch=$basearch&repo=extras
baseurl=http://mirrors.cloud.tencent.com/centos-vault/5.8/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-5.8 - Plus
#mirrorlist=http://mirrorlist.centos.org/?release=5.8&arch=$basearch&repo=centosplus
baseurl=http://mirrors.cloud.tencent.com/centos-vault/5.8/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

#contrib - packages by Centos Users
[contrib]
name=CentOS-5.8 - Contrib
#mirrorlist=http://mirrorlist.centos.org/?release=5.8&arch=$basearch&repo=contrib
baseurl=http://mirrors.cloud.tencent.com/centos-vault/5.8/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5

openssl是目前使用最广泛的ssl库之一,除了提供全面的ssl加密库以外,还提供了一些基础的命令行工具用于测试,目前绝大多数的软件都是使用openssl库来进行ssl交互,很多系统默认都自带了openssl相关的库和工具。

在我的工作中,最常用到的就是利用它来进行漏洞检测(如SSL重协商漏洞)以及连接测试等,使用普通的浏览器构造出特定的数据包实际上是很难的,但是通过openssl命令却相当简单。

一、查看证书相关信息的命令

打印证书的完整内容:

openssl x509 -in cert.pem -noout -text

打印出证书的序列号:

openssl x509 -in cert.pem -noout -serial

查看der格式的证书内容:

openssl x509 -in cert.pem -inform der -noout -text

把PEM格式的证书转化成DER格式

openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER

二、s_clinet用法

s_clinet是openssl命令中的一个客户端,可以用来进行openssl相关的连接测试,漏洞检测的时候经常会用到。

本周使用s_client做了两件事,一个是完成了ssl重协商漏洞的测试,另外一个是通过它重现了一个代码BUG。

发起一个连接请求:

openssl s_clinet -connect www.baidu.com:443 -ssl3
-ssl3表示使用SSLv3版本的协议去连接服务端,也可以换成tls1_3/tls1_2/tls1_1等。

指定发送的srever_name扩展:

openssl s_client -connect www.baidu.com:443 -server_name WWW.BAIDU.COM

linux下的命令,大多不支持PAC形式代理,只支持http/socks代理形式。因此为了使用PAC文件做代理,必须要通过三方软件来转发这部分代理的流量。privoxy是一个支持PAC代理的程序,可以根据不同规则选择代理线路,我们可以使用它来作为代理软件转发客户端流量。privoxy官方网站:www.privoxy.org

测试环境:centos6 + centos7。

一、安装privoxy

安装privoxy的方式有以下几种:

  1. rpm包方式安装或源码包下载编译安装
  2. 使用yum命令一键安装

方式1可以在官方网站找到源码包和安装包,安装相对麻烦一些,centos系统推荐使用原生的包管理工具yum来安装,前提是要安装epel源,国内epel源可以选择阿里云的源,下载速度快(使用方式参考Epel 镜像帮助)。

使用yum安装privoxy的:

yum install privoxy

安装好后,启动进程:

# centos 6
service privoxy start
# centos 7
systemctl start privoxy

添加到开机启动:

# centos 6
chkconfig --add privoxy
chkconfig privoxy on
# centos 7
systemctl enable privoxy

二、配置privoxy以支持PAC

privoxy的配置文件目录是/etc/privoxy/,在目录下添加文件pac.action,内容:

{{alias}}
default    = +forward-override{forward .} 
pac     = +forward-override{forward 10.66.83.23:8080}

{default}
/

{pac}
.baidu.com
.qq.com

配置简单说明:

  • alias段:定义转发规则,目前是定义了两种。default表示默认规则,后面的forward .表示默认走本机。pac表示自定义的pac规则,后面的forward 10.66.83.23:8080表示通过10.66.83.23:8080的HTTP代理出去。
  • default段:匹配默认规则的地址,/表示默认的,如果没有匹配其他规则就匹配这个规则。
  • pac段:需要进行代理转发的域名,下面的地址会通过上面定义的代理地址转发出去。

以上配置的意思就是,*.baidu.com和*.qq.com域名通过10.66.83.23:8080代理,其他的默认走本机代理。其他需要代理的地址也可以加在下面。

然后在主配置文件中config添加修改:

# 添加我们自定义的PAC规则
actionsfile pac.action
# 下面这几行是系统预定义的转发规则,注释掉
# actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
# actionsfile default.action   # Main actions file
# actionsfile user.action      # User customizations

# 下面这几行是系统预定义的过滤规则,注释掉
# filterfile default.filter
# filterfile user.filter      # User customizations

程序默认监听端口是8118,默认只支持本地的代理,如果需要更改的话改以下配置:

listen-address  127.0.0.1:8118

没有特殊要求的话可以使用默认配置,改完后启动privoxy进程就可以了。

注意:进程启动后,如果修改了pac规则,需要重新启动进程才能生效。

三、配置系统

给本机设置代理环境变量:

export http_proxy=http://127.0.0.1:8118
export https_proxy=http://127.0.0.1:8118

然后使用wget或者curl命令测试即可!要注意的是环境变量只对当前终端生效,退出当前会话后就没有了。如果希望每次登录都生效,则需要把这两个命令放到~/.bashrc或者/etc/profile中。

四、原理说明

开启privoxy代理后,流量会全部发到privoxy,然后privoxy来决定流量走哪。配置了PAC规则的走指定线路,没有配置的走本机。

反向代理配置:

server {
    listen 80;
    server_name mirrors.maqian.work;

    location / {
        proxy_pass http://mirrors.aliyun.com;
        proxy_redirect off;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

在浏览器访问mirrors.maqian.work时:

  • $host: mirrors.maqian.work
  • $proxy_host: mirrors.aliyun.com

一、问题现象

调用命令的时候,出现报错:

cannot create temp file for here-document: No space left on device

从错误的日志来看,应该是磁盘空间不足了。但是执行df -h看磁盘都是有剩余的:

上次遇到过一个类似的现象是,文件删除,但是容量没有归还。怀疑可能是同样的问题,但是执行lsof | grep delete看并没有被删除但没有归还空间的文件。

经过询问大佬后,说可能是inode节点满了导致的,于是执行df -i看了一下还真是:

可以看到,磁盘总共26w个inode节点全部使用完了。再通过find查找所有文件,确实是看到了26w个文件:

二、结论

经过下一步分析,发现是设备在进行profile抽样,大量的抽样文件打到了/var目录下,导致磁盘占满。

因此判断,问题原因是磁盘文件数量太多,占满了inode节点导致的。

一、slowhttp攻击

slowhttp攻击的意思是客户端使用非常慢的速度发送数据到服务端,例如每秒发送1个字节头部或body,导致服务端连接长时间占用连接,当这种连接多了之后,服务端资源就会耗尽。

以下就是一个慢攻击测试案例,当1000个客户端连接缓慢发送HTTP头部到服务端后,服务器已经变成了不可用状态:

前端提示资源无法访问:

如何测试服务是否存在慢攻击漏洞

下载测试工具slowhttptest:https://github.com/shekyan/slowhttptest,根据文档编译安装。

然后执行:

slowhttptest -c 1000 -H -i 10 -r 200 -t GET -u https://服务器地址/页面 -x 24 -p 3

控制台会每5秒打印一次连接状态,可以持续监控,如果隔了几十秒后,连接还一直没有断开,说明服务端是存在漏洞的。

二、apache环境下修复

我们的web服务器是使用的apache,根据网上提供的方法,安装mod_reqtimeout模块,再添加以下配置:

<IfModule reqtimeout_module>
    RequestReadTimeout header=5-40,MinRate=500 body=20,MinRate=500
</IfModule>

重启apache,问题就解决了。再次使用测试工具测试,连接在建立后5秒左右会被断开。

三、参考

SlowHTTPTest-慢速DoS攻击