0

0

linux模拟资源占用 你会吗

霞舞

霞舞

发布时间:2025-01-02 19:18:02

|

489人浏览过

|

来源于良许Linux教程网

转载

公司拥有一批云服务器,这些服务器托管在华为云上,然而,很多云服务器的资源利用率并不高,处于空闲状态。我开始担心领导会察觉到这些空闲资源,要求我们降低配置,并可能削减云服务器的采购预算。因此,我计划编写一个 shell 脚本,用于模拟资源占用的情况。

实施思路

  • 使用 stress 工具对内存进行压力测试,占用剩余内存的80%,以模拟CPU和内存的消耗情况。
  • 使用 dd 命令生成大文件,占用第二块硬盘剩余空间的80%,以模拟硬盘空间的消耗和IO操作。
  • 让脚本运行持续20分钟,一旦检测到内存占用超过80%,则停止压力测试。
  • 避免对CPU进行压力测试,因为过高的CPU占用率可能导致应用异常或服务器重启的风险。

相关工具

stress

stress 命令主要用来模拟系统负载较高时的场景,本文介绍其基本用法。文中 demo 的演示环境为 ubuntu 18.04。

可选参数

-c, –cpu N 产生 N 个进程,每个进程都反复不停的计算随机数的平方根

-i, –io N 产生 N 个进程,每个进程反复调用 sync() 将内存上的内容写到硬盘上

-m, –vm N 产生 N 个进程,每个进程不断分配和释放内存 –vm-bytes B 指定分配内存的大小

–vm-stride B 不断的给部分内存赋值,让 COW(Copy On Write)发生 –vm-hang N 指示每个消耗内存的进程在分配到内存后转入睡眠状态 N 秒,然后释放内存,一直重复执行这个过程

–vm-keep 一直占用内存,区别于不断的释放和重新分配(默认是不断释放并重新分配内存)

-d, –hadd N 产生 N 个不断执行 write 和 unlink 函数的进程(创建文件,写入内容,删除文件)

–hadd-bytes B 指定文件大小

-t, –timeout N 在 N 秒后结束程序 –backoff N 等待N微妙后开始运行

-q, –quiet 程序在运行的过程中不输出信息

-n, –dry-run 输出程序会做什么而并不实际执行相关的操作

–version 显示版本号

-v, –verbose 显示详细的信息

消耗 CPU 资源

stress 消耗 CPU 资源是通过调用 sqrt 函数计算由 rand 函数产生的随机数的平方根实现。下面的命令会产生 4 个这样的进程不断计算:

$ stress -c 

使用 top 命令查看 CPU 的状态如下(CPU 在用户态满负荷运转):

消耗内存资源

下面的命令产生两个子进程,每个进程分配 300M 内存:

$ stress --vm 2 --vm-bytes 300M --vm-keep

父进程处于睡眠状态,两个子进程负责资源消耗。

–vm-keep 一直占用内存,区别于不断的释放和重新分配(默认是不断释放并重新分配内存)。 –vm-hang N 指示每个消耗内存的进程在分配到内存后转入睡眠状态 N 秒,然后释放内存,一直重复执行这个过程。

–vm-keep 和 –vm-hang 都可以用来模拟只有少量内存的机器,但是指定它们时 CPU 的使用情况是不一样的。

$stress --vm 2 --vm-bytes 500M --vm-keep

一直在进行默认的 stride 操作,user 非常高(cpu 在用户态忙碌)。

$ stress --vm 2 --vm-bytes 500M --vm-hang 5

上面这两种状态不断切换,但整体上看 CPU 的负载并不高。

–vm-stride B 不断的给部分内存赋值,让 COW(Copy On Write)发生。只要指定了内存相关的选项,这个操作就会执行,只是大小为默认的 4096。赋值内存的比例由参数决定:

for (i = 0; i

$ stress --vm 2 --vm-bytes 500M --vm-stride 64
$ stress --vm 2 --vm-bytes 500M --vm-stride 1M

为什么会产生这样的结果?原因是单独的赋值和对比操作可以让 CPU 在用户态的负载占到 99% 以上。–vm-stride 值增大就意味着减少赋值和对比操作,这样就增加了内存的释放和分配次数(cpu在内核空间的负载)。 不指定 –vm-stride 选项就使用默认值是 4096,CPU 负载情况居于前两者之间:

$ stress --vm 2 --vm-bytes 500M

消耗 IO 资源 下面的命令产生 4 个进程,每个进程都反复调用 sync 函数将内存上的内容写到硬盘上:

LOGO.com
LOGO.com

在线生成Logo,100%免费

下载
$ stress -i 4

使用 top 命令查看 CPU 的状态如下:

sy 升高,wa(iowait) 非常高。

压测磁盘及 IO 下面的命令创建一个进程不断的在磁盘上创建 10M 大小的文件并写入内容:

$ stress -d 1 --hdd-bytes 10M

使用 top 命令查看 CPU 的状态如下(此时的 CPU 主要消耗在内核态):

下面是 iostat 2 的输出(同样是高 iowait,瓶颈是写磁盘):

其它选项

–verbose 显示 stress 程序运行过程中的详细信息:

–timeout N 在 N 秒后结束程序。

–quiet stress 程序运行的过程中不输出信息。

-n, –dry-run 输出程序会做什么而并不实际执行相关的操作:

–backoff N 让新 fork 出来的进程 sleep N 微秒再开始运行。

除了单独指定某一类的选项,还可以同时执行多个类型的任务,比如产生 3 个 CPU 进程、3 个 IO 进程、2 个10M 的 vm 进程,并且每个 vm 进程中不循环分配释放内存:

$ stress --cpu 3 --io 3 --vm 2 --vm-bytes 10M --vm-keep

dd

dd 命令 用于复制文件并对原文件的内容进行转换和格式化处理。dd 命令功能很强大的,对于一些比较底层的问题,使用 dd 命令往往可以得到出人意料的效果。用的比较多的还是用 dd 来备份裸设备。但是不推荐,如果需要备份 oracle 裸设备,可以使用 rman 备份,或使用第三方软件备份,使用 dd 的话,管理起来不太方便。需要的时候使用 dd 对物理磁盘操作,如果是文件系统的话还是使用 tar backup cpio 等其他命令更加方便。另外,使用 dd 对磁盘操作时,最好使用块设备文件。

语法

dd (选项)

命令选项

bs=:将ibs(输入)与obs(输出)设成指定的字节数;
cbs=:转换时,每次只转换指定的字节数;
conv=:指定文件转换的方式;
count=:仅读取指定的区块数;
ibs=:每次读取的字节数;
obs=:每次输出的字节数;
of=:输出到文件;
seek=:一开始输出时,跳过指定的区块数;
skip=:一开始读取时,跳过指定的区块数;
--help:帮助;
--version:显示版本信息。

实例

> dd if=/dev/zero of=sun.txt bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.006107 seconds, 172 MB/s

[root@localhost text]
1.1M    sun.txt

该命令创建了一个 1M 大小的文件 sun.txt,其中参数解释:

  • if 代表输入文件。如果不指定 if,默认就会从 stdin 中读取输入。
  • of 代表输出文件。如果不指定 of,默认就会将 stdout 作为默认输出。
  • bs 代表字节为单位的块大小。
  • count 代表被复制的块数。
  • /dev/zero 是一个字符设备,会不断返回 0 值字节(\0)。

块大小可以使用的计量单位表

单元大小 代码
字节(1B) c
字节(2B) w
块(512B) b
千字节(1024B) k
兆字节(1024KB) M
吉字节(1024MB) G

以上命令可以看出 dd 命令来测试内存操作速度:

> 1048576 bytes (1.0 MB) copied, 0.006107 seconds, 172 MB/s

生成随机字符串

我们甚至可以使用 /dev/urandom 设备配合 dd 命令 来获取随机字符串

> dd if=/dev/urandom bs=1 count=15|base64 -w 0
15+0 records in
15+0 records out
15 bytes (15 B) copied, 0.000111993 s, 134 kB/s
wFRAnlkXeBXmWs1MyGEs

常用案例汇总

1.将本地的/dev/hdb整盘备份到/dev/hdd
#dd if=/dev/hdb of=/dev/hdd
2.将/dev/hdb全盘数据备份到指定路径的image文件
#dd if=/dev/hdb of=/root/image
3.将备份文件恢复到指定盘
#dd if=/root/image of=/dev/hdb
4.备份/dev/hdb全盘数据,并利用gzip工具进行压缩,保存到指定路径
#dd if=/dev/hdb | gzip > /root/image.gz
5.将压缩的备份文件恢复到指定盘
#gzip -dc /root/image.gz | dd of=/dev/hdb
6.备份与恢复MBR
备份磁盘开始的512个字节大小的MBR信息到指定文件:
#dd if=/dev/hda of=/root/image count=1 bs=512
   count=1指仅拷贝一个块;bs=512指块大小为512个字节。
恢复:
#dd if=/root/image of=/dev/had
将备份的MBR信息写到磁盘开始部分
7.备份软盘
#dd if=/dev/fd0 of=disk.img count=1 bs=1440k (即块大小为1.44M)
8.拷贝内存内容到硬盘
#dd if=/dev/mem of=/root/mem.bin bs=1024 (指定块大小为1k)  
9.拷贝光盘内容到指定文件夹,并保存为cd.iso文件
#dd if=/dev/cdrom(hdc) of=/root/cd.iso
10.增加swap分区文件大小
第一步:创建一个大小为256M的文件:
#dd if=/dev/zero of=/swapfile bs=1024 count=262144
第二步:把这个文件变成swap文件:
#mkswap /swapfile
第三步:启用这个swap文件:
#swapon /swapfile
第四步:编辑/etc/fstab文件,使在每次开机时自动加载swap文件:
/swapfile    swap    swap    default   0 0
11.销毁磁盘数据
#dd if=/dev/urandom of=/dev/hda1
注意:利用随机的数据填充硬盘,在某些必要的场合可以用来销毁数据。
12.测试硬盘的读写速度
#dd if=/dev/zero bs=1024 count=1000000 of=/root/1Gb.file
#dd if=/root/1Gb.file bs=64k | dd of=/dev/null
通过以上两个命令输出的命令执行时间,可以计算出硬盘的读、写速度。
13.确定硬盘的最佳块大小:
#dd if=/dev/zero bs=1024 count=1000000 of=/root/1Gb.file
#dd if=/dev/zero bs=2048 count=500000 of=/root/1Gb.file
#dd if=/dev/zero bs=4096 count=250000 of=/root/1Gb.file
#dd if=/dev/zero bs=8192 count=125000 of=/root/1Gb.file
通过比较以上命令输出中所显示的命令执行时间,即可确定系统最佳的块大小。
14.修复硬盘:
#dd if=/dev/sda of=/dev/sda 或dd if=/dev/hda of=/dev/hda
当硬盘较长时间(一年以上)放置不使用后,磁盘上会产生magnetic flux point,当磁头读到这些区域时会遇到困难,并可能导致I/O错误。当这种情况影响到硬盘的第一个扇区时,可能导致硬盘报废。上边的命令有可能使这些数 据起死回生。并且这个过程是安全、高效的。
15.利用netcat远程备份
#dd if=/dev/hda bs=16065b | netcat  1234
在源主机上执行此命令备份/dev/hda
#netcat -l -p 1234 | dd of=/dev/hdc bs=16065b
在目的主机上执行此命令来接收数据并写入/dev/hdc
#netcat -l -p 1234 | bzip2 > partition.img
#netcat -l -p 1234 | gzip > partition.img
以上两条指令是目的主机指令的变化分别采用bzip2、gzip对数据进行压缩,并将备份文件保存在当前目录。
将一个很大的视频文件中的第i个字节的值改成0x41(也就是大写字母A的ASCII值)
echo A | dd of=bigfile seek=$i bs=1 count=1 conv=notrunc

脚本

编写的shell脚本如下:

#!/bin/bash
#模拟cpu,IO,内存使用
#ver 1.0
#每天凌晨1:00执行
#持续20分钟

#记录执行日志
script_log="script_log.log"
mem_info=$(free -m | grep Mem)
used_mem=$(echo $mem_info | awk '{print $3}')
total_mem=$(echo $mem_info | awk '{print $2}')
# 计算内存利用率
mem_util=$(echo "scale=2; $used_mem / $total_mem * 100" | bc)
#内存利用率取整数
mem_utilization=$(printf "%.0f" "$mem_util")

if [ ! -f "$script_log" ]; then
  touch "$script_log"
fi


# 模拟内存占用
function simulate_memory() {

  #安装stress压测工具
  INSTALLED=$(rpm -qa | grep stress)
  if [ $? -eq 0 ];then
    echo "$(date +%Y-%m-%d-%H:%M) 已经安装了stress" >> $script_log
  else
    yum install stress -y
    sleep 5
  fi
  #执行内存
  if [ $mem_utilization -lt 80 ];then
    stress --io 1 --vm 1 --vm-bytes "$(awk '/MemFree/{printf "%d\n", 0.7*$2}' /proc/meminfo)k" --vm-keep &
    echo "$(date +%Y-%m-%d-%H:%M) 执行内存压测命令 " >> $script_log
  fi

}

#模拟file占用
function simulate_file() {
  #判断第二硬盘是否存在
  second_disk=$(lsblk | grep -w "vd[b-z]")
  if [ $? -eq 0 ];then
    echo "$(date +%Y-%m-%d-%H:%M) 第二块硬盘存在" >> $script_log
    if [ -d "/data" ];then
      if [ -d "/data/second_disk_data_tmp" ];then
        echo "$(date +%Y-%m-%d-%H:%M) 临时目录/data/second_disk_data_tmp已存在" >> $script_log
      else
        mkdir -p /data/second_disk_data_tmp
        echo "$(date +%Y-%m-%d-%H:%M) 临时目录/data/second_disk_data_tmp不存在,已创建" >> $script_log
      fi
    fi
  else
    echo "$(date +%Y-%m-%d-%H:%M) 第二块硬盘不存在" >> $script_log
  fi
  #执行前先删除临时文件

  if [ -f "/data/second_disk_data_tmp/data_tmp.txt" ];then
    rm -f /data/second_disk_data_tmp/data_tmp.txt
    echo "$(date +%Y-%m-%d-%H:%M) /data/second_disk_data_tmp/data_tmp.txt 文件存在,已删除"
  else 
    touch /data/second_disk_data_tmp/data_tmp.txt
  fi

  #第二块盘磁盘利用率
  second_disk_usage=$(df -h | egrep  "vd[b-z]" | awk '{ print $5 }' | tr -d "%")
  #需要占用的磁盘空间大小
  file_size=$(df -h | egrep  "vd[b-z]" | awk '{ print $4*0.8 }' | tr -d "G"|bc)
  #去整数
  size_file=$(printf "%.0f" "$file_size")
  #计算需要生成的文件大小
  #如果第二盘的空间小于80
  if [ $second_disk_usage -lt 80 ];then 
  #dd命令生成文件
    time1=$(date +%s)
    echo "$(date +%Y-%m-%d-%H:%M) 开始执行生成临时文件" >> $script_log
    dd if=/dev/zero  of=/data/second_disk_data_tmp/data_tmp.txt bs=1G count=$size_file
    time2=$(date +%s)
    time3=$((time2-time1))
    echo "$(date +%Y-%m-%d-%H:%M) 生成了临时文件,路径为/data/second_disk_data_tmp/data_tmp.txt,花费时间$time3 秒" >> $script_log
    if  [ $second_disk_usage -ge 80 ];then 
      if [ -f "/data/second_disk_data_tmp/data_tmp.txt" ];then
        rm -rf /data/second_disk_data_tmp/data_tmp.txt
        echo "$(date +%Y-%m-%d-%H:%M) 第二盘硬盘利用率大于80%,已删除临时文件" >> $script_log
      fi
    fi
  fi
}
start_time=$(date +%s)
simulate_memory
simulate_file
start_time=$(date +%s)
#此刻的内存利用率

while true;do
  #计算此时内存利用率
  mem_info_now=$(free -m | grep Mem)
  used_mem_now=$(echo $mem_info_now | awk '{print $3}')
  total_mem_now=$(echo $mem_info_now | awk '{print $2}')
  # 计算内存利用率
  mem_util_now=$(echo "scale=2; $used_mem_now / $total_mem_now * 100" | bc)
  mem_utilization_now=$(printf "%.0f" "$mem_util_now")
  current_time=$(date +%s)
  elapsed_time=$((current_time - start_time))

  if [ $mem_utilization_now -ge 80 ];then
     for i in $(ps aux | grep "stress --io" | awk '{ print $2}');do kill -9 $i;done
     echo "$(date +%Y-%m-%d-%H:%M) 内存利用率大于80%停止stress命令 " >> $script_log
     sleep 10
     simulate_memory
     sleep 10
  fi
  if [ $elapsed_time -ge 1200 ]; then
    break
  fi
  sleep 10
done
for i in $(ps aux | grep "stress --io" | awk '{ print $2}');do kill -9 $i;done
echo "$(date +%Y-%m-%d-%H:%M) 结束内存压测" >> $script_log
end_time=$(date +%s)
cost_time=$((end_time - start_time))
echo "$(date +%Y-%m-%d-%H:%M) 程序已经运行:$cost_time 秒 并结束" >> $script_log
exit 0

执行效果

cpu

linux模拟资源占用 你会吗

内存

linux模拟资源占用 你会吗

IO

linux模拟资源占用 你会吗

相关问题

1 dd命令执行时间过长,持续将近十几分钟

2 dd执行过程中磁盘IO基本上被占满

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

776

2023.08.22

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1500

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

613

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

588

2024.04.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.9万人学习

Git 教程
Git 教程

共21课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号