作者:付祥
现居珠海,主要负责 Oracle、MySQL、mongoDB 和 Redis 维护工作。
本文来源:原创投稿
*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
现象
监控告警某台机器空闲内存低于10%,执行top命令,按内存降序排序,部分输出如下:
[root@mysql-slaver ~]# top top - 13:45:43 up 1835 days, 20:52, 2 users, load average: 0.02, 0.03, 0.05 Tasks: 210 total, 1 running, 208 sleeping, 1 stopped, 0 zombie %Cpu(s): 0.5 us, 0.6 sy, 0.0 ni, 98.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 32780028 total, 905684 free, 19957900 used, 11916444 buff/cache KiB Swap: 0 total, 0 free, 0 used. 3448260 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2677 mysql 20 0 20.1g 15.1g 3392 S 0.0 48.2 430:17.58 mysqld 10549 polkitd 20 0 3277476 3.1g 632 S 0.3 9.9 146:47.24 redis-server 18183 root 20 0 877308 215868 1892 T 2.7 0.7 2736:45 xxxxxx 442 root 20 0 160244 93016 88552 S 0.3 0.3 314:14.86 systemd-journal 32537 root 20 0 731620 58360 54588 S 0.3 0.2 29:09.61 rsyslogd
total=32G,used=19G,buff/cache=11G,available=3G,最耗内存进程为 MySQL、Redis,总计约18.2G,其他进程占用内存都比较低,buff/cache 内存中只有3G是有效的,剩余8G内存去哪里?
分析
执行 free 命令进一步查看:
[root@MySQL-slaver ~]# free -m total used free shared buff/cache available Mem: 32011 19490 881 8762 11639 3366 Swap: 0 0 0
其中shared占用竟然占用了8G内存,通过man查看帮助:
shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo, available on kernels 2.6.32, displayed as zero if not avail‐ able)
shared Memory来源于/proc/meminfo中Shmem,被tmpfs使用,df -h查看:
[root@MySQL-slaver ~]# df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 16G 0 16G 0% /dev tmpfs 16G 16K 16G 1% /dev/shm tmpfs 16G 8.6G 7.1G 55% /run tmpfs 16G 0 16G 0% /sys/fs/cgroup
目录/run使用了8.6G内存,和shared占用内存一致,内存都消耗到哪些子目录了?
[root@MySQL-slaver ~]# du -am /run|sort -rn -k1|head -10 8761 /run 7137 /run/systemd 7126 /run/systemd/users 1624 /run/log/journal/89308070e0c04c6a86bf577f4064efca 1624 /run/log/journal 1624 /run/log
内存主要消耗在/run/systemd/users和/run/log/journal目录,占用内存分别为7126M、1624M,较为异常的是/run/systemd/users占用内存过高,继续分析这个目录下有哪些文件
[root@MySQL-slaver ~]# ls -l /run/systemd/users total 44 -rw-r--r-- 1 root root 41056 Mar 23 14:14 0
乍一看,只有一个文件占用约40k,这和du统计的差异也太大了吧,是不是有隐藏文件:
[root@MySQL-slaver ~]# find /run/systemd/users|less /run/systemd/users /run/systmd/users/0 /run/systemd/users/.#0kRUlqC /run/systemd/users/.#0Qxvu5J /run/systemd/users/.#03DvfrF ...... [root@MySQL-slaver ~]# find /run/systemd/users|wc -l 337632 [root@MySQL-slaver ~]# ls -l /run/systemd/users/.#00009iJ -rw-r--r-- 1 root root 20480 Sep 26 2018 /run/systemd/users/.#00009iJ [root@MySQL-slaver ~]# ll /run/systemd/users/.#0SEEqoi -rw-r--r-- 1 root root 20480 Mar 23 14:34 /run/systemd/users/.#0SEEqoi [root@MySQL-slaver ~]# uptime 14:45:13 up 1835 days, 21:51, 2 users, load average: 0.02, 0.08, 0.12
不看不知道,一看吓一跳,隐藏文件数高达30w+,最早的文件有2018年的,最新的文件今天产生的,随便打开一个文件看看:
[root@MySQL-slaver ~]# less /run/systemd/users/.#03DvfrF # This is private data. Do not parse. NAME=root STATE=active RUNTIME=/run/user/0 SLICE=user-0.slice DISPLAY=4231719 REALTIME=1521010223727718 MONOTONIC=79029110787 SESSIONS=4232100 4232099 4232098 ......
保存的是root用户session信息,loginctl查看session信息:
[root@MySQL-slaver ~]# loginctl list-sessions SESSION UID USER SEAT 24597 0 root 146401 0 root 133160 0 root 82494 0 root 82514 0 root 106049 0 root ...... [root@MySQL-slaver ~]# loginctl list-sessions|awk '{print $3}'|sort|uniq -c 1 1 listed. 2131 root 1 USER
root用户session数竟然高达2131个,随便拿一个session看看:
[root@MySQL-slaver ~]# loginctl session-status 24597 24597 - root (0) Since: Tue 2018-03-27 08:35:01 CST; 4 years 11 months ago Leader: 25599 Service: crond; type unspecified; class background State: active Unit: session-24597.scope [root@MySQL-slaver ~]#
crond产生的session,这些session都没有分配相关进程,当前状态为active,按session排序后,挑选最近的session查看,都是2018年产生的:
[root@MySQL-slaver ~]# loginctl session-status 243335 243335 - root (0) Since: Sat 2018-07-14 03:29:01 CST; 4 years 8 months ago Leader: 28376 Service: crond; type unspecified; class background State: active Unit: session-243335.scope [root@MySQL-slaver ~]#
做了一个定时任务测试,session能正常分配进程,任务完成后session关闭:
Mar 23 15:20:01 [localhost] CROND[12334]: (root) CMD (sleep 1200) [root@MySQL-slaver ~]# loginctl session-status 4232206 4232206 - root (0) Since: Thu 2023-03-23 15:20:01 CST; 19min ago Leader: 12330 (crond) Service: crond; type unspecified; class background State: opening Unit: session-4232206.scope ├─12330 /usr/sbin/CROND -n └─12334 sleep 1200 [root@MySQL-slaver ~]# loginctl session-status 4232206 Failed to get session: No session '4232206' known [root@MySQL-slaver ~]# lsof -p `pidof dbus-daemon`|grep sessions|wc -l 2126 [root@MySQL-slaver ~]# lsof -p `pidof dbus-daemon`|tail -5 dbus-daem 560 dbus 2139w FIFO 0,18 0t0 416861417 /run/systemd/sessions/156582.ref dbus-daem 560 dbus 2140w FIFO 0,18 0t0 417383549 /run/systemd/sessions/156774.ref dbus-daem 560 dbus 2141w FIFO 0,18 0t0 417291412 /run/systemd/sessions/156740.ref dbus-daem 560 dbus 2142w FIFO 0,18 0t0 620267085 /run/systemd/sessions/242902.ref dbus-daem 560 dbus 2143w FIFO 0,18 0t0 621086290 /run/systemd/sessions/243335.ref [root@MySQL-slaver ~]#
解决
个人觉得可选解决方案如下:
1、服务器上主要服务为MySQL和Redis,MySQL作为从库使用,未承载业务读流量,Redis近期将会迁移,/run/systemd/users目录占用内存虽然在增长,5年了也只占用8G,增量很缓慢,故可以在线收缩MySQL innodb_buffer_pool_size使用内存,释放一部分内存给操作系统,等Redis迁移了再做机器重启处理。
2、假设主机不可以重启,通过lsof可知这些隐藏文件当前未被使用,故可以迁移到其他磁盘目录,看看是否能达到释放内存目的,且这些session都是crond 2018年产生的,并未分配相关进程,故通过loginctl kill-session ID干掉。
目前采取方案1处理。