同CPU使用率一样,内存使用率也是希望越低越好,但混沌工程需要注入内存耗尽的故障,我们今天研究下如何控制内存使用率持续100%。
混沌工程中为什么注入内存耗尽故障呢?系统中当然不期望内存耗尽,但期望内存耗尽后系统能否自动恢复,自动恢复的时长。
借用阿里混沌工程实践,内存耗尽如下:系统层-系统异常-内存耗尽。
脚本chaos-mem-001.sh
实现思想:借鉴虚拟内存的思想,创建虚拟内存文件系统,不断写入数据达到消耗内存的目的,需要清除内存时,删除创建的虚拟内存目录即可。
#!/bin/bash
#使用虚拟内存构造内存消耗
mkdir /tmp/memory
#tmpfs是一种虚拟内存文件系统,而不是块设备(tmpfs不具备持久性)。是基于内存的文件系统,创建时不需要使用mkfs等初始化,最大的特点是它的存储空间在VM(virtual memory),VM是由linux内核里面的vm子系统管理的。linux下面VM的大小由RM(Real Memory)和swap组成,RM的大小就是物理内存的大小,而Swap的大小是由自己决定的。Swap是通过硬盘虚拟出来的内存空间,因此它的读写速度相对RM(Real Memory)要慢许多,当一个进程申请一定数量的内存时,如内核的vm子系统发现没有足够的RM时,就会把RM里面的一些不常用的数据交换到Swap里面。VM由RM+Swap两部分组成,因此tmpfs最大的存储空间可达(The size of RM + The size of Swap)。 但是对于tmpfs本身而言,它并不知道自己使用的空间是RM还是Swap,这一切都是由内核的vm子系统管理的。tmpfs默认的大小是RM的一半。Tmpfs大小调整:/etc/fstab中看到tmpfs类型的挂载点中找到待修改的,先umount tmpfs(操作前先备份),在/etc/fstab修改挂载点的容量后再mount tmpfs。脚本中挂载一个待注入内存大小的内存系统。
mount -t tmpfs -o size=300M tmpfs /tmp/memory
dd if=/dev/zero of=/tmp/memory/block
sleep 3600s
#释放消耗的虚拟内存
rm /tmp/memory/block
umount /tmp/memory
rmdir /tmp/memory
脚本chaos-mem-002.sh:原理同001,易用性更好
#!/bin/bash
# mem used script
# eg. ./mem.sh 60G & to start testing
# eg. ./mem.sh stop to stop testing and clear env
# update: 2019-1-22 pansaky
num=$1
user=`whoami`
start()
{
if [ -d /tmp/memory ];then
echo "the dir "/tmp/memory" is already exist!, use it." >> mem.log
else
sudo mkdir /tmp/memory
mount -t tmpfs -o size=$num tmpfs /tmp/memory
fi
dd if=/dev/zero of=/tmp/memory/block >> mem.log 2>&1
}
stop()
{
rm -rf /tmp/memory/block
umount /tmp/memory
rmdir /tmp/memory
if [ -d /tmp/memory ];then
echo "Do not remove the dir \"/tmp/memory\", please check "
else
echo "clear env is done!"
fi
}
main()
{
if [ $num == 'stop' ];then
stop
elif [ $user != "root" ];then
echo "please use the \"root\" excute script!"
exit 1
else
start
fi
}
if [ $# = 2 -o $# = 1 ];then
main
else
echo 'Usage: <./mem.sh 60G &> to start or <./mem.sh stop> to clear env'
fi
C语言脚本chaos-mem-003
/*usage: gcc mem.c -o mem.out 编译出Linux下可执行的文件,使用./mem.out 100 & 消耗对应数字MB单位的内存,释放时杀掉对应进程即可,如果是内存耗尽,该进程会被操作系统oom杀掉*/
#include
#include
#include
#define UNIT (1024*1024)
# argc是外部输入的参数个数,argv[ ]是参数的字符串数组。
int main(int argc, char *argv[])
{
long long i = 0;
int size = 0;
if (argc != 2) {
printf(" === argc must 2\n");
return 1;
}
# strtoul函数:strtoul() 函数源自于“string to unsigned long”,用来将字符串转换成无符号长整型数(unsigned long)。strtol() 函数用来将字符串转换为长整型数(long)。
size = strtoul(argv[1], NULL, 10);
if (size == 0) {
printf(" argv[1]=%s not good\n", argv[1]);
return 1;
}
# malloc向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。malloc及其相关函数calloc,free,realloc,brk在表头文件#include
char *buff = (char *) malloc(size * UNIT);
if (buff)
printf(" we malloced %d Mb\n", size);
buff[0] = 1;
for (i = 1; i < (size * UNIT); i++) {
if (i%1024 == 0)
buff[i] = buff[i-1]/8;
else
buff[i] = i/2;
}
pause();
}
C语言脚本chaos-mem-004
#include
#include
using namespace std;
void main()
{
int i=0;
double *a=NULL;
while(true)
{
# 申请8k字节的空间(1000个double类型值,double类型为8个字节),并且把a指向该空间所在位置
a=(double*) malloc (sizeof(double) *1000);
# 在VC中Sleep()的单位是毫秒,如果函数滞留1秒的话,应该是Sleep(1000);在Linux下sleep()的单位是秒。
Sleep(1);
}
}
参考
Linux内存测试---构造消耗内存shell脚本
linux内存测试(占用)脚本