前言
😨不好啦❗ 天塌了❗ 系统崩了❗
😨今天下午,突然一半的系统瘫痪了
无法分配内存:
js
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00007f1f2adf6000, 12288, 0) failed; error='无法分配内存' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 12288 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /data/online-activity/hs_err_pid2482011.log
遇到这种大面积瘫痪,肯定是立马执行重启大法😁
排查过程
查看内存占用率
ps aux --sort=-%mem
按照内存使用率降序,查看内存占用情况:
js
USER PID %CPU %MEM(占用率%) VSZ(虚拟内存KB) RSS(物理内存KB) TTY STAT START TIME COMMAND
root 1 0.0 0.0 172328 9520 ? Ss 2317 28:27 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
root 1351641 0.1 0.0 32660 9496 ? Ss 15:12 0:05 sshd: root [priv]
root 1348874 0.0 0.0 32660 9472 ? Ss 14:48 0:00 sshd: root [priv]
root 1348945 0.0 0.0 26400 9468 ? Ss 14:49 0:00 sshd: root [priv]
root 1557164 0.0 0.0 26400 9460 ? Ss 16:05 0:00 sshd: root [priv]
root 1348599 0.0 0.0 26400 9452 ? Ss 14:47 0:00 sshd: root [priv]
root 1419738 0.0 0.0 32660 9428 ? Ss 15:29 0:00 sshd: root [priv]
root 1420875 0.0 0.0 26400 9412 ? Ss 15:30 0:00 sshd: root [priv]
root 1641846 0.6 0.0 22140 8676 pts/9 S+ 16:26 0:00 vim logger.out
上面的情况是事后模拟随便复制的一个中间信息
发现 vim logger.out
这个命令的进程占了好几个G的内存。
然后我们第一时间,就杀掉进程:kill -9 1641846
然后重启所有服务。
📕 第一个日志生产策略有很大问题!太大了!同时不知道是谁居然用 vim 命令查看了日志
整体分析系统内存情况
恢复所有服务之后,需要对内存整体的情况做一个分析以及剩余大小做一个分析。 执行free -m
:
‼ 生产环境数据不适合展示,所有随便调整了一下
js
total used free shared buff/cache available
Mem: 61551 58489 4910 137 3175 7527
Swap: 0 0 0
下面这个可以方便大家更直观的了解
内存类型 | 总量(total) | 已使用(used) | 空闲(free) | 可分配给应用(available) |
---|---|---|---|---|
物理内存(Mem) | 61551 | 58489 | 4231 | 6497 |
交换分区(Swap) | 0 | 0 | 0 | 0 |
我们的总体内存在几十个G,剩余内存在几个G,因为有些日志好几个G了。使用VIM 编辑日志就直接把日志加载到内存导致内存占满。
为什么会存在大日志
❓排查logback-spring.xml 滚动策略,大小限制 看一下日志的滚动策略,是按月配置了的
xml
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件输出的文件名,按月分割,文件名带起始日期 -->
<FileNamePattern>${LOG_HOME}/${spring.application.name}-%d{yyyy-MM}.log</FileNamePattern>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
</encoder>
</appender>
❗发现名称规则和生产环境的logger.out 也对不上,并且路径也没对上。 看了一下启动命令,才发现问题,所有的日志都会一直定向的输入到logger.out中 >>/app/xx/logger.out &
✔所以不能这么搞啊,使用logback-spring.xml 配置的策略即可!同时需要排查logback的策略是否有文件大小限制,如下:
xml
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/${spring.application.name}-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
</appender>
总结
启动命令存在严重的问题,导致把日志定向输出到logger.out
文件中。导致日志文件日积月累到大几个G😨 再加上老铁查看日志用了不规范的命令,导致大日志文件加载到内存中,导致内存不足,jvm崩溃。
推荐阅读:上午系统崩溃(OOM),下午就喜提大礼包