我看远山,远山悲悯
写在前面
+
我看远山,远山悲悯
持续分享技术干货,感兴趣小伙伴可以关注下 ^_^
限制内存使用量 在 systemd
的 drop-in
文件文件[Service]
段里面定义 MemoryLimit
参考就可以限制你的程序所使用的内存,单位可以是K,M,G或T。
这里看一个以临时服务的方式运行 /bin/bash
命令的Demo , 并将其标准输入、标准输出、标准错误连接到当前的 TTY 设备上:
1 2 3 4 ┌──[root@liruilongs.github.io]-[~] └─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=bash-limit --slice=bash-test -t /bin/bash Running as unit bash-limit.service. Press ^] three times within 1s to disconnect TTY.
在生成的 bash Service
中我们可以运行交互命令,查看当前 Service 的单元文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ┌──[root@liruilongs.github.io]-[/] └─$ systemctl cat bash-limit.service [Service] CPUShares=100 [Unit] Description=/bin/bash [Service] Environment="TERM=xterm-256color" [Service] ExecStart= ExecStart=@/bin/bash "/bin/bash" [Service] MemoryLimit=5242880 。。。。。。。。。。。。。。。。。。。。。。。。
通过 systemctl status bash-limit.service
我们可以看到cgroup
的相关信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ┌──[root@liruilongs.github.io]-[/] └─$ systemctl status bash-limit.service ● bash-limit.service - /bin/bash Loaded: loaded (/run/systemd/system/bash-limit.service; static; vendor preset: disabled) Drop-In: /run/systemd/system/bash-limit.service.d └─50-CPUShares.conf, 50-Description.conf, 50-Environment.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf, 50-StandardError.conf, 50-StandardInput.conf, 50-StandardOutput.conf, 50-TTYPath.conf Active: active (running) since 六 2022-10-29 13:40:19 CST; 31s ago Main PID: 136529 (bash) Memory: 1.7M (limit : 5.0M) CGroup: /bash.slice/bash-test.slice/bash-limit.service ├─136529 /bin/bash └─136607 systemctl status bash-limit.service 10月 29 13:40:19 liruilongs.github.io systemd[1]: Started /bin/bash. ┌──[root@liruilongs.github.io]-[/] └─$ bash ┌──[root@liruilongs.github.io]-[/] └─$ bash
当然上面的配置方式实际上是基于 Cgroup
来实现的,Cgroup V1 版本和 V2 版本有些区别,当前机器环境的问题,我们只看一下 V1 的版本,MemoryLimit 参数可以控制Cgroup 内存控制器的 memory.limit_in_bytes Cgroup参数
。
下面为 system.slice
这个 Cgroup
分组下面 tuned Cgroup
内存相关资源限制,可以看到默认的情况下没有限制(memory.limit_in_bytes
),使用的最大值,这里的内存限制是物理内存,不是虚拟内存,配置虚拟内存可以通过 ulimit
进行会话基本的虚拟内存设置,下面是一个 Demo
仅对 当前 Shell 及其子进程 生效 as 虚拟地址空间限制
,以 KB 为单位
1 2 3 4 5 ┌──[root@liruilongs.github.io]-[~] └─$ulimit -v 8186 ┌──[root@liruilongs.github.io]-[~] └─$ls ls: error while loading shared libraries: libc.so.6: failed to map segment from shared object
修改 as 的大小之后,提示 ls
命令无法加载共享库 libc.so.6,并且无法从共享对象映射段
永久配置(全局或用户级)需要修改 /etc/security/limits.conf
, 感兴趣小伙伴可以看看我之前的博文,生效条件:用户重新登录后生效。
1 2 3 liruilong hard as 819200 liruilong soft as 409600
也可以通过 systemd
服务配置,修改服务的 systemd
单元文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$prlimit RESOURCE DESCRIPTION SOFT HARD UNITS AS 地址空间限制 无限制 无限制 字节 CORE 最大核心文件尺寸 无限制 无限制 字节 CPU CPU 时间 无限制 无限制 秒数 DATA 最大数据尺寸 无限制 无限制 字节 FSIZE 最大文件尺寸 无限制 无限制 字节 LOCKS 最大文件锁保持数量 无限制 无限制 锁 MEMLOCK 最大内存锁定(locked-in-memory)地址空间 65536 65536 字节 MSGQUEUE POSIX 消息队列中的最大字节数 819200 819200 字节 NICE 允许提升的最大 nice 优先级 0 0 NOFILE 打开文件的最大数量 65535 65535 文件 NPROC 最大进程数 29616 29616 进程 RSS 最大驻留集尺寸 无限制 无限制 字节 RTPRIO 最大实时优先级 0 0 RTTIME 实时任务超时 无限制 无限制 毫秒数 SIGPENDING 挂起(pending)信号的最大数量 29616 29616 信号 STACK 最大栈(stack)尺寸 8388608 无限制 字节 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$prlimit --pid=1 --as RESOURCE DESCRIPTION SOFT HARD UNITS AS 地址空间限制 无限制 无限制 字节 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$
1 2 [Service] LimitAS=819200
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$prlimit RESOURCE DESCRIPTION SOFT HARD UNITS AS 地址空间限制 无限制 无限制 字节 CORE 最大核心文件尺寸 无限制 无限制 字节 CPU CPU 时间 无限制 无限制 秒数 DATA 最大数据尺寸 无限制 无限制 字节 FSIZE 最大文件尺寸 无限制 无限制 字节 LOCKS 最大文件锁保持数量 无限制 无限制 锁 MEMLOCK 最大内存锁定(locked-in-memory)地址空间 65536 65536 字节 MSGQUEUE POSIX 消息队列中的最大字节数 819200 819200 字节 NICE 允许提升的最大 nice 优先级 0 0 NOFILE 打开文件的最大数量 65535 65535 文件 NPROC 最大进程数 29616 29616 进程 RSS 最大驻留集尺寸 无限制 无限制 字节 RTPRIO 最大实时优先级 0 0 RTTIME 实时任务超时 无限制 无限制 毫秒数 SIGPENDING 挂起(pending)信号的最大数量 29616 29616 信号 STACK 最大栈(stack)尺寸 8388608 无限制 字节 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$prlimit --pid=1 --as RESOURCE DESCRIPTION SOFT HARD UNITS AS 地址空间限制 无限制 无限制 字节 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$# 查看 PID=1234 的虚拟内存限制 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$cat /proc/1/limits | grep "Max address space" Max address space unlimited unlimited bytes ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl cat tuned.service [Unit] Description=Dynamic System Tuning Daemon After=systemd-sysctl.service network.target dbus.service Requires=dbus.service polkit.service Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8) [Service] Type=dbus PIDFile=/run/tuned/tuned.pid BusName=com.redhat.tuned ExecStart=/usr/sbin/tuned -l -P Restart=on-failure [Install] WantedBy=multi-user.target [Service] MemoryLimit=1G ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$vim /usr/lib/systemd/system/tuned.service.d/limit-as-800.conf ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl daemon-reload ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl restart tuned.service ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$pgrep tuned 4677 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$prlimit --pid=4677 --as RESOURCE DESCRIPTION SOFT HARD UNITS AS 地址空间限制 无限制 无限制 字节 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl cat tuned.service [Unit] Description=Dynamic System Tuning Daemon After=systemd-sysctl.service network.target dbus.service Requires=dbus.service polkit.service Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8) [Service] Type=dbus PIDFile=/run/tuned/tuned.pid BusName=com.redhat.tuned ExecStart=/usr/sbin/tuned -l -P Restart=on-failure [Install] WantedBy=multi-user.target [Service] MemoryLimit=1G [Service] LimitAS=819200 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$cat /proc/1/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size unlimited unlimited bytes Max resident set unlimited unlimited bytes Max processes 29616 29616 processes Max open files 1073741816 1073741816 files Max locked memory 974647296 974647296 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 29616 29616 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$
tuned 小伙伴们应该不陌生,一个开源新的系统性能优化的服务,用于一些内核参数限制
1 2 3 4 5 6 7 8 9 10 11 ┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice] └─$cat tuned.service/memory. memory.events memory.kmem.tcp.failcnt memory.memsw.failcnt memory.qos_level memory.events.local memory.kmem.tcp.limit_in_bytes memory.memsw.limit_in_bytes memory.soft_limit_in_bytes memory.failcnt memory.kmem.tcp.max_usage_in_bytes memory.memsw.max_usage_in_bytes memory.stat memory.force_empty memory.kmem.tcp.usage_in_bytes memory.memsw.usage_in_bytes memory.swappiness memory.high memory.kmem.usage_in_bytes memory.min memory.usage_in_bytes memory.kmem.failcnt memory.limit_in_bytes memory.move_charge_at_immigrate memory.use_hierarchy memory.kmem.limit_in_bytes memory.low memory.numa_stat memory.kmem.max_usage_in_bytes memory.max_usage_in_bytes memory.oom_control memory.kmem.slabinfo memory.memfs_files_info memory.pressure_level
默认情况下,没有限制会显示最大值
1 2 3 ┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice] └─$cat tuned.service/memory.limit_in_bytes 9223372036854771712
配置方式我们可以通过上面的方式配置,通过 service unit 文件进行限制
限定最大可用内存为 1GB,添加 MemoryLimit 设定
1 2 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$vim tuned.service
确认配置,加载配置文件,重启
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl cat tuned.service [Unit] Description=Dynamic System Tuning Daemon After=systemd-sysctl.service network.target dbus.service Requires=dbus.service polkit.service Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8) [Service] Type=dbus MemoryLimit=1G PIDFile=/run/tuned/tuned.pid BusName=com.redhat.tuned ExecStart=/usr/sbin/tuned -l -P Restart=on-failure [Install] WantedBy=multi-user.target ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl daemon-reload ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl restart tuned.service
再次查看 Cgroup 内存相关限制参数
1 2 3 4 5 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.limit_in_bytes 1073741824 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$
生产环境,更多的是通过 drop-in
的方式定义文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$vim tuned.service.d/50-MemoryLimit.conf ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl daemon-reload ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl restart tuned.service ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$systemctl cat tuned.service [Unit] Description=Dynamic System Tuning Daemon After=systemd-sysctl.service network.target dbus.service Requires=dbus.service polkit.service Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8) [Service] Type=dbus PIDFile=/run/tuned/tuned.pid BusName=com.redhat.tuned ExecStart=/usr/sbin/tuned -l -P Restart=on-failure [Install] WantedBy=multi-user.target [Service] MemoryLimit=1G ┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] └─$
这里我们简单看一下,其他的 Cgroup 参数限制,部分参数在 Cgroup V2 中作了调整,感兴趣小伙伴可以看看去
核心内存限制
参数
作用
memory.limit_in_bytes
物理内存硬限制 (单位:字节),超出会触发 OOM Killer。
memory.memsw.limit_in_bytes
物理内存 + swap 总限制 (需内核启用 swapaccount=1
)。
memory.soft_limit_in_bytes
内存软限制 ,系统优先回收超过此值的内存,但不会强制杀死进程。
内核内存控制
参数
作用
memory.kmem.limit_in_bytes
内核内存(如 slab、dentry 缓存)的硬限制 。
memory.kmem.tcp.limit_in_bytes
TCP 缓冲区内存的硬限制 (如 TCP socket 发送/接收缓冲区)。
内存回收与行为控制
参数
作用
memory.force_empty
强制释放内存缓存 (写入 0
触发)。
memory.swappiness
调整内存回收策略 (值越高,系统越积极使用 swap)。
memory.oom_control
控制 OOM Killer 行为 (0
表示启用 OOM Killer,1
表示禁用)。
memory.move_charge_at_immigrate
进程迁移时是否转移内存占用 (1
表示转移)。
高级功能
参数
作用
memory.high
内存使用软限制 (v1 中较少使用,v2 中更常见)。
memory.low
内存保护阈值 ,系统尽量避免回收低于此值的内存。
memory.pressure_level
内存压力事件通知 (需配合 cgroup.event_control
使用)。
缺页异常监控 当进程访问系统没有映射物理页的虚拟内存页时,内核就会产生一个 page fault
事件。
当进程缺页事件发生在第一次访问虚拟内存时,内核会产生一个 minor page fualt
,并分配新的物理内存页。minor page fault
产生的开销比较小。但是,当物理内存页丢失,并需要从硬盘中加载内存的数据信息时,内核就会产生一个 majorpage fault
.
这种情况发生在,比如内核通过交互分区,将内存中的数据交换出去放到了硬盘,她就需要从硬盘中重新加载程序或库文件的代码到内存。
由于内核必须从磁盘加载页面,因此一个major fault
对性能影响比较大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ┌──[root@liruilongs.github.io]-[~] └─$ps -eo pid,minflt,majflt,comm | awk '$2 > 0 && $3 > 0 {print}' PID MINFLT MAJFLT COMMAND 1 55646 189 systemd 704 959 7 systemd-journal 719 1912 2 systemd-udevd 892 80 3 auditd 913 553 12 dbus-broker-lau 915 281 4 dbus-broker 918 15617 206 firewalld 919 325 6 irqbalance 921 740 5 systemd-logind 925 166 5 chronyd 955 1243 100 NetworkManager 991 26090 281 /usr/sbin/httpd 998 2683 260 php-fpm 999 923 17 sshd 1002 9775 7 tuned 1006 862 3 crond 1121 6976 225 mariadbd 1150 2060 125 polkitd 1213 731 24 rsyslogd 1498 390 7 pmcd 1518 516 11 pmdaroot 1535 470 4 pmdaproc 1544 410 2 pmdaxfs 1551 447 4 pmdalinux 1558 409 2 pmdakvm 1872 2109 1 /usr/sbin/httpd 1874 3701 9 /usr/sbin/httpd 2201 2654 2 bash 2245 678 6 sudo 2246 3300 1 bash 4085 541 10 htop ┌──[root@liruilongs.github.io]-[~] └─$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ┌──[root@liruilongs.github.io]-[~] └─$perf stat -e minor-faults,major-faults hostnamectl Static hostname: liruilongs.github.io Icon name: computer-vm Chassis: vm � Machine ID: 7deac2815b304f9795f9e0a8b0ae7765 Boot ID: 5041b68a4d574df2b59289e33e85bdd5 Virtualization: vmware Operating System: Rocky Linux 9.4 (Blue Onyx) CPE OS Name: cpe:/o:rocky:rocky:9::baseos Kernel: Linux 5.14.0-427.20.1.el9_4.x86_64 Architecture: x86-64 Hardware Vendor: VMware, Inc. Hardware Model: VMware Virtual Platform Firmware Version: 6.00 Performance counter stats for 'hostnamectl' : 463 minor-faults 0 major-faults 0.132397887 seconds time elapsed 0.009642000 seconds user 0.004471000 seconds sys ┌──[root@liruilongs.github.io]-[~] └─$
博文部分内容参考 © 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)
© 2018-至今 liruilonger@gmail.com , 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)