Skip to main content

利用ansible、stress-ng进行压力测试

压测利器-stress-ng

stress-ng是stress的加强版,完全兼容stress,并在此基础上增加了几百个参数,堪称压测工具中的瑞士军刀。

这里列举几个样例场景:

CPU密集型场景:

stress-ng --cpu 6 --timeout 300

该命令会尽量占满6个CPU核

IO密集型场景:

stress-ng  -i 6 --hdd 1 --timeout 300

该命令会开启1个worker不停的读写临时文件,同时启动6个workers不停的调用sync系统调用提交缓存,

进程密集型场景:

(( proc_cnt = `nproc`*10 )); stress-ng --cpu $proc_cnt --pthread 1 timeout 300

该命令会启动N*10个进程,在只有N个核的系统上,会产生大量的进程切换,模拟进程间竞争CPU的场景

线程密集型场景:

stress-ng --cpu `nproc` --pthread 1024 timeout 300

该命令会在N个CPU核的系统上,产生N个进程,每个进程1024个线程,模拟线程间竞争CPU的场景

其它常用样例:

        stress-ng --vm 8 --vm-bytes 80% -t 1h

run 8 virtual memory stressors that combined use 80% of the available memory for 1
hour. Thus each stressor uses 10% of the available memory.

stress-ng --cpu 4 --io 2 --vm 1 --vm-bytes 1G --timeout 60s

runs for 60 seconds with 4 cpu stressors, 2 io stressors and 1 vm stressor using
1GB of virtual memory.

stress-ng --iomix 2 --iomix-bytes 10% -t 10m

runs 2 instances of the mixed I/O stressors using a total of 10% of the available
file system space for 10 minutes. Each stressor will use 5% of the available file
system space.

stress-ng --cyclic 1 --cyclic-dist 2500 --cyclic-method clock_ns --cyclic-prio 100
--cyclic-sleep 10000 --hdd 0 -t 1m

measures real time scheduling latencies created by the hdd stressor. This uses the
high resolution nanosecond clock to measure latencies during sleeps of 10,000
nanoseconds. At the end of 1 minute of stressing, the latency distribution with
2500 ns intervals will be displayed. NOTE: this must be run with super user
privileges to enable the real time scheduling to get accurate measurements.

stress-ng --cpu 8 --cpu-ops 800000

runs 8 cpu stressors and stops after 800000 bogo operations.

stress-ng --sequential 2 --timeout 2m --metrics

run 2 simultaneous instances of all the stressors sequentially one by one, each for
2 minutes and summarise with performance metrics at the end.

stress-ng --cpu 4 --cpu-method fft --cpu-ops 10000 --metrics-brief

run 4 FFT cpu stressors, stop after 10000 bogo operations and produce a summary
just for the FFT results.

stress-ng --cpu 0 --cpu-method all -t 1h

run cpu stressors on all online CPUs working through all the available CPU
stressors for 1 hour.

stress-ng --all 4 --timeout 5m

run 4 instances of all the stressors for 5 minutes.

stress-ng --random 64

run 64 stressors that are randomly chosen from all the available stressors.

stress-ng --cpu 64 --cpu-method all --verify -t 10m --metrics-brief

run 64 instances of all the different cpu stressors and verify that the
computations are correct for 10 minutes with a bogo operations summary at the end.

stress-ng --sequential 0 -t 10m

run all the stressors one by one for 10 minutes, with the number of instances of
each stressor matching the number of online CPUs.

stress-ng --sequential 8 --class io -t 5m --times

run all the stressors in the io class one by one for 5 minutes each, with 8
instances of each stressor running concurrently and show overall time utilisation
statistics at the end of the run.

stress-ng --all 0 --maximize --aggressive

run all the stressors (1 instance of each per CPU) simultaneously, maximize the
settings (memory sizes, file allocations, etc.) and select the most
demanding/aggressive options.

stress-ng --random 32 -x numa,hdd,key

run 32 randomly selected stressors and exclude the numa, hdd and key stressors

stress-ng --sequential 4 --class vm --exclude bigheap,brk,stack

run 4 instances of the VM stressors one after each other, excluding the bigheap,
brk and stack stressors

stress-ng --taskset 0,2-3 --cpu 3

run 3 instances of the CPU stressor and pin them to CPUs 0, 2 and 3.

最简单的运维工具-ansible

在小规模的机器上执行命令,最简单非ansible莫属,因为ansible默认是不需要在待运维的机器上安装额外的服务, 只要开启了ssh服务就可以了。

一个简单的ansible使用样例,simple-example-of-ansible

如何管理压测进程-给压测进程找个爹

使用ansible进行加压时,如果执行stress-ng命令,然后马上退出,压测工具进程也就被杀死了,这是因为压测工具默认的父进程是ansible的ssh会话 这时候可以使用nohup、setsid命令让stress-ng命令后台执行。 在稍微复杂的场景模拟时,stress-ng可能会启动很多的进程,并且有些时候不仅有stress-ng,而且可能还需要sys-bench等工具, 当需要调整压力时,可能需要杀掉之前的压测进程,再启动新的压测,如果一个一个的找出来并杀掉进程,不仅操作复杂而且经常 会产生僵尸进程。

这时候就需要screen、tmux这样的会话管理工具了,通过screen来统一管理会话,所有的压测进程都被托管在screen里,这样如果需要 关掉所有的压力时,只需要杀掉screen进程就可以了。

例:

screen -S stress -d -m stress-ng -c 1 --timeout 300

负载场景剧本设计-playbook

在云计算场景下,经常会需要用压测工具来模拟一些业务场景,stress-ng是最常用到的工具之一,通常ansible+stress-ng就能应付绝大多数的压测场景。 如果需要模拟的CPU、MEM、磁盘IO模型比较多,用命令行就显得不是那么方便了,这时候就可以用playbook。

github上已经有人写好了一个playbook,ansible-role-stress

项目已经在CenstOS 7上测试过了,在Ubuntu上应该也是可以正常工作的。

playbook支持如下角色变量:

  • test_duration: stress-ng 超时时间
  • 不同类型压测资源的worker数量:
    • cpu_workers
    • vm_workers
    • hdd_workers
  • 每个worker的磁盘或内存使用量
    • bytes_per_hdd_worker
    • bytes_per_vm_worker

自动重试-ansile经常不靠谱

使用playbook操作大量机器时,经常会出现机器执行命令失败,比如网络不通、网络闪断等,这时候需要对失败的机器重新执行命令,playbook可以如下命令进行重试

ansible-playbook -i host stress.yml --extra-vars "host=all" --limit @$playbook_retry

其中playbook_retry文件里保存的是需要重试的IP列表,可以从执行回显中分析执行结果,通过awk找出执行失败 的IP列表,通过ansible-playbook进行重试。

#!/bin/sh

hosts=(
"host1"
"host2"
"host3"
)

cpu_load=(15 15 15 15 15 15)
mem_load=(5 5 5 5 5 5)

mkdir -p tmp

host_file="./hosts"

total_result="./tmp/total_result.log"
playbook_result="./tmp/playbook_result.log"
playbook_retry="./tmp/playbook_retry.txt"

echo "" > $total_result

parse_playbook_result()
{
sed '1,/PLAY RECAP/d' $playbook_result | awk -F" *|=|\t" '
/unreachable/{
ip=$1
ok_cnt=$4
changed_cnt=$6
unreachable_cnt=$8
failed_cnt=$10
if(unreachable_cnt!=0 || failed_cnt!=0 || rescued_cnt!=0){
print ip
}
}' > $playbook_retry
}

ansible_playbook()
{
echo "playbook Vars: $2"
ansible-playbook -i $host_file $1 --extra-vars "$2" >$playbook_result 2>&1

cat $playbook_result > $total_result

while true
do
parse_playbook_result
RETRY_CNT=$(wc -l $playbook_retry | awk '{print $1}')

if [[ $RETRY_CNT != 0 ]]; then
echo "Some host will retry:"
cat $playbook_retry
ansible-playbook -i $host_file stress_stop.yml --extra-vars "$2" --limit @$playbook_retry >/dev/null 2>&1
ansible-playbook -i $host_file $1 --extra-vars "$2" --limit @$playbook_retry >$playbook_result 2>&1
cat $playbook_result > $total_result
else
return
fi
done
}

for(( i=0; i<${#hosts[@]}; i++ ))
do
echo "Stress" ${hosts[i]}
ansible_playbook "stress_start.yml" "host=${hosts[i]} cpu_load=${cpu_load[i]} mem_load=${mem_load[i]}"
done


echo "Over zzz"