一、内存不够了怎么办
1.1 操作系统内存不够怎么办
1.2 什么是交换分区Swap
1.3 swap配置参数:swappiness
1.4 应用场景
二、Linux内存扩容-swap配置
三、Linux的free top命令
free命令(宏观命令 mpstat 、 vmstat )
free列和available列的区别
top命令( 全局 + 局部 )
四、消失的进程怎么排查
4.1 生产环境问题描述
4.2 Demo + 基础知识
4.3 原因分析
4.4 如何发现问题
五、操作系统的OOM评分机制和进程雪崩
什么是oom_score
回收内存: 把不常用的内存 算法淘汰,比如LRU回收内存
内存置换:把不常用的内存通过交换分区直接写到磁盘中,置换一部分空间使用
杀死进程:内存紧张时系统还会通过 OOM(Out of Memory),会选择杀掉一些进程释放掉一些内存
进程占用内存很大,会导致内存消耗完,为解决该问题操作系统中运用Swap技术,拿部分硬盘空间来充当内存使用,作用是在物理内存使用完之后,将磁盘空间(也就是SWAP分区)虚拟成内存来使用
换页机制
操作系统把物理内存中放不下的数据临时放到磁盘上,等到需要的时候再放回到物理内存中,提供超过物理内存容量的空间
访问数据被swap换出
物理内存是有限资源,运行多进程时并不是每个进程都活跃,系统会启动 内存页面置换 (操作系统的页面置换算法)
将长时间未使用的物理内存页帧放到swap分区,让出资源给其他进程
当存在于swap分区的页面被访问时就会触发Page Fault 缺页异常,从而再置换回物理内存
预取机制
换页过程涉及的磁盘IO操作,读取耗时比较多,因此操作系统会引入预取机制进行优化
当发生换入操作时,预测还有哪些页会被访问,提前将它们一并换入物理页内存,减少发生缺页异常的次数
参数可以从0-100进行设置,默认值swappiness=60,表示内存使用率超过100-60=40%时开始使用交换分区
swappiness=0的时候表示最大限度使用物理内存,尽量不用 swap空间,有些云服务器厂商直接设置为0
注意:把swappiness设置成0不会禁止swap, 是最大限度不用, 不是一定不用,想要禁止,就不要开启swap
swappiness=100的时候表示积极的使用swap分区,把内存上的数据及时的搬运到swap空间
命令
查看 cat /proc/sys/vm/swappiness
临时修改 echo 10 > /proc/sys/vm/swappiness
永久调整 vim /etc/sysctl.conf 加上. vm.swappiness=10
配置建议根据不同的应用,有不同的配置,比如有些性能要求高中间件,由于硬盘io较慢,会要求禁用 swap, 分配太多的Swap空间会浪费磁盘空间,而Swap空间太少,则系统内存不够就会发生错误
kubernetes集群一般要关闭swap
Java 的应用一般也是要关闭swap,像Rocketmq、ElasticSearch 等
Java应用会用到堆,开启了swap就会部分存储到磁盘上
程序在 GC 的时候会遍历所有堆的内存,如果这部分内存是被 swap 到磁盘上,GC遍历的时候就会有磁盘IO影响性能
查看是否有开启swap free -m
如果说0,则说明没开启
Linux 支持两种类型的 Swap:Swap分区 和 Swap文件(本次使用文件方式)
命令
dd:用指定大小的块 拷贝一个文件,并在拷贝的同时进行指定的转换,下面是参数
if = 文件名:输入文件名,缺省为标准输入,即指定源文件。< if = input file >
of = 文件名:输出文件名,缺省为标准输出,即指定目的文件。 < of = output file >
bs = bytes:同时设置读入/输出的块大小为bytes个字节, 可代替 ibs 和 obs
count = blocks:仅拷贝blocks个块,块大小等于指定的字节数
bs是每次读或写的大小,即一个块的大小,count是读写块的数量
Demo:
增加swap分区文件大小,创建一个大小为256M的文件(256 * 1024kb =262144)
dd if=/dev/zero of=/swapfile bs=1024 count=262144#/dev/zero是一个输入设备,用它来初始化文件
# if -> input_file输入文件 of -> output_file输出文件 bs -> block_size块大小 count -> 计数
把创建的文件变成swap文件
mkswap /swapfile
启用这个swap文件
swapon /swapfile
【可选】编辑 /etc/fstab 文件,末行添加下面命令,每次开机时自动加载swap文件
vim /etc/fstab
/swapfile swap swap default 0 0
【可选】如果不需要了,也可以卸载
swapoff /swapfile
【可选】查看swap文件位置
显示Linux系统中空闲的、已用的物理内存、swap内存 和 被内核使用的buffer
格式 free [参数]
显示结果说明:
free 是真正未被使用的物理内存数量
available 是应用程序的角度看到的可用内存数量
Linux 为了提升读写性能,会消耗一部分内存资源缓存磁盘数据,就是buffer 和 cache(下面篇幅有介绍)
没有足够的 free 内存可以用,内核就会从 buffer 和 cache 中回收内存
大概计算:available = free + buff/ cache total = used + free + buff/cache
能够实时显示系统中各个进程的资源占用状况,包括进程ID、内存占用率、CPU占用率等
格式 top [参数] ,按1后 显示各个cpu明细情况
全局信息:
# 当前时间 系统启动到现在的时间,当前用户数 ,CPU的 1 5 15分钟负载
top - 15:05:58 up 27 days, 20:43, 1 user, load average: 0.00, 0.04, 0.05#共计96个进程 ,2个在运行,94个在睡眠 ,0个停止,0个僵尸进程
Tasks: 96 total, 2 running, 94 sleeping, 0 stopped, 0 zombie#us用户态占用CPU的百分比,sy内核态占用CPU的百分比, id — 空闲CPU百分比
#wa等待IO占用CPU的百分比, hi硬中断(Hardware IRQ)占用CPU的百分比, si软中断(Software Interrupts)占用CPU百分比
%Cpu(s): 1.0 us, 0.7 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st#内存状态 total物理内存总量,free空闲内存总量, used使用中的内存总量, buff/cache缓存的内存量
KiB Mem : 7733316 total, 3722316 free, 1047632 used, 2963368 buff/cache#swap交换分区信息 total交换区总量, free空闲交换区总量, used使用的交换区总量, avail进程可用内存空间
KiB Swap: 262140 total, 262140 free, 0 used. 6380096 avail Mem局部进行详细信息:
# 进程的状态信息 PID 进程id,USER进程所有者,PR进程优先级 是动态优先级 ;NI nice负值表示高优先级,静态优先级一般不变
# VIRT 进程使用的虚拟内存总量 VIRT=SWAP+RES,申请过的内存没有真正分配物理内存也会计算在内,进程的虚拟内存比常驻内存大得多
# RES 进程实际使用的、未被换出的物理内存大小,即不包括 Swap 和共享内存,单位kb
# SHR共享内存大小,单位kb
# S进程状态,D=不可中断的睡眠状态 R=运行 S=睡眠 T=停止 Z=僵尸进程了;%CPU上次更新到现在的CPU时间占用百分比
# %MEM 进程使用的物理内存百分比;TIME+ 进程使用的CPU时间总计,单位1/100秒; COMMAND 进程名称(命令名/命令行)
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
16122 101 20 0 6600532 348952 77932 S 2.0 4.5 567:45.61 clickhouse-serv
11691 root 10 -10 151540 34696 10368 S 1.0 0.4 376:50.51 AliYunDunMonito
11681 root 10 -10 100436 8056 6524 S 0.3 0.1 101:38.64 AliYunDun
1 root 20 0 43656 3796 2404 S 0.0 0.0 0:25.80 systemd
一台机器线上的某个进程直接就消失了,别的机器上的服务都正常跑着,怎么排查原因?
举一反三:java进程、mysql、redis、mq 也是一样的情况
基础知识:
gcc 是一个编译器,没有界面,在命令行模式下使用,通过 gcc 命令可以将源文件编译成可执行文件。
gcc 命令如果不指定目标文件名时默认生成的可执行文件名为 a.out(linux) 或 a.exe(windows)。
可用 gcc [源文件名] -o [目标文件名] 来指定目标文件路径及文件名
C语言中,malloc函数的作用是动态分配内存,不能自动释放,申请的内存单位是字节
安装 gcc yum install gcc -y
服务准备: 一般普通C语言代码 user_service_oom.zip
编译程序: gcc user_service.c -o user_service.out
运行程序 ./user_service.out
服务运行中:
服务消失:
查看刚才的那个运行的代码:
c语言中的malloc函数是不断申请内存的
进程消失重现分析:
# 释放所有缓存
echo 3 > /proc/sys/vm/drop_caches
# 动态查看机器内存
free -h -s 1
终端一
# 释放所有缓存
echo 3 > /proc/sys/vm/drop_caches
# 动态查看机器内存
free -h -s 1终端二
# 实时查看top,进程的内存、CPU运行情况
top终端三
# 编译程序
gcc user_service.c -o user_service.out
# 运行程序
./user_service.out
Linux服务器上有多个应用进程运行,应用压力突增情况下容易出现各种问题,在多应用部署时需要注意对内存分配和资源隔离
比如 :
Linux系统在内存不足等条件下会主动干预进程(OOM-Killer机制)
OOM killer 给进程打分,把 oom_score 最大的进程先杀死, 打分主要有两部分组成
一种系统根据该进程的内存占用情况打分,进程的内存开销是变化的,所以该值也会动态变化
另一种用户可以设置的 oom_score_adj,范围是 -1000到 1000
当然,另外一个常见情况,就是某个同事重启了机器,导致程序没开机自启动运行
通过执行last reboot 查看机器都什么时间是否重启过
或者top查看系统运行了多久
/var/log/messages 日志
是核心系统日志文件,包括整体系统信息、系统启动时的引导消息、系统运行时的其他状态消息
在做故障诊断时可以首先查看该文件内容,比如IO 错误、网络错误和其他系统错误都会记录到这个文件中
#查看最新的10行
tail -10 /var/log/messages#过滤kill进程相关的日志
cat /var/log/messages | grep Kill
/var/log/dmesg
用dmesg查看,包含内核缓冲信息,在系统启动时,会在屏幕上显示许多与硬件有关的信息
#egrep 详细: -i 忽略大小写 -C n key 输出匹配key关键字及关键字上下的n行#过滤出 killed process 上下10行日志
dmesg | egrep -i -C10 'killed process'#增加人类可读的时间戳
dmesg -T #常用完整命令
dmesg -T | egrep -i -C10 'killed process'
对某一个task进程进行打分(oom_score),实际得分需要考虑两方面,然后把 oom_score 最大的进程先杀死
一部分是系统打分,主要是根据该task的内存使用情况,进程的内存开销是变化的,所以该值也会动态变化
另一部分是用户打分,也就是oom_score_adj,默认是0,取值范围是-1000~1000
0表示用户不调整oom_score,负值表示要在实际打分值上减去一个折扣
正值表示要惩罚对应的进程,也就是增加该进程的oom_score
如果用户将该进程的 oom_score_adj 设定成 -1000,表示禁止OOM killer 杀死该进程,特别重要的服务可以配置
proc 文件系统是虚拟文件系统, 某个进程被杀掉, 则 /proc/pid/ 目录也就被销毁
查看系统本身对进程的评分,内存是变化的,所以该值也会动态变化
#执行这个程序,调用多次
cat /proc/$(pidof user_service.out)/oom_score
程序再运行中的时候,才会有对应的目录产生
用户手工修改进程的评分(大量申请内存,操作的时候会卡顿)
#先查看系统的评分
cat /proc/$(pidof user_service.out)/oom_score
#先查看用户默认的评分
cat /proc/$(pidof user_service.out)/oom_score_adj#手工修改评分
sudo sh -c "echo -500 > /proc/$(pidof user_service.out)/oom_score_adj"#查看修改后的评分
cat /proc/$(pidof user_service.out)/oom_score_adj
#再查看系统的评分
cat /proc/$(pidof user_service.out)/oom_score
注意:
把一个一直申请内存的进程的 oom_score_adj 设置为-1000,会导致大量的都进程被kill
因为使用了bash所以这个bash挂了,user_service.out也停止了,如果是后端运行,则更多进程都会被kill
#进程的 oom_score_adj 设置为-1000
sudo sh -c "echo -1000 > /proc/$(pidof user_service.out)/oom_score_adj"#过滤kill进程相关的日志
cat /var/log/messages | grep Kill#常用完整命令, 可能损坏查询不到信息
dmesg -T| grep "Out of memory"
下一篇:pikachu靶场-暴力破解