79

使用 systemd 限制系统资源的使用

 5 years ago
source link: https://arstercz.com/使用-systemd-限制系统资源的使用/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

简单介绍

在基于 Linux-3.x 内核版本的很多发行版都提供了 Systemd 来管理系统和服务. 同时也将 cgroup 功能加到了 slice, scope 和 service 三个单元中, 详见 sec-Default_Cgroup_Hierarchies . 基于这些特性我们可以很方便的通过 systemd 来限制服务或者进程对系统资源的使用, 这在单主机多服务的场景下会很有用. 下面则以 MySQL 服务为例介绍如何使用 systemd 限制资源的使用, 其它服务的限制和此等同.

示例使用

以 Centos7 系统为例, 从 redhat-resource-control 的文档来看, 官方建议通过 service 来实现资源的限制, 所以这里我们增加可以带端口参数(如果单台主机有多个 MySQL 实例的话)启动的 mysql 服务:

# cat /usr/lib/systemd/system/[email protected]                                   
[Unit]
Description=MySQL Server node%i

[Service]
Type=forking
Environment="PORT_ARGS=%I"
PermissionsStartOnly=true
ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start
ExecStop=/usr/local/mysqlnode/bin/node ${PORT_ARGS} stop

[Install]
WantedBy=multi-user.target

上述服务以 fork 方式启动服务, @ 符号之后的端口号即为相应的端口参数, 启动后查看对应服务状态:

# systemctl start mysql@3327 
# systemctl status mysql@3327
● [email protected] - MySQL Server node3327
   Loaded: loaded (/usr/lib/systemd/system/[email protected]; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2018-12-07 21:31:32 CST; 4s ago
  Process: 58084 ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start (code=exited, status=0/SUCCESS)
 Main PID: 58159 (mysqld_safe)
   CGroup: /system.slice/system-mysql.slice/[email protected]
           ├─58159 /bin/sh /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101//bin/mysqld_safe --defaults-file=/export/mysql/node3327/my.node.cnf
           ├─59489 /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101/bin/mysqld --defaults-file=/export/mysql/node3327/my.node.cnf --basedir=/opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101 --datadir=/export/mysql/node3327/...
           └─59490 logger -t mysqld-3327 -p daemon.error

通过 systemd 增加 cgroup 限制,可以一次设置单项属性值, 也可以一次设置多项:

# systemctl set-property [email protected] MemoryLimit=5G       # 5G 内存
# systemctl set-property [email protected] CPUQuota=150%        # 150% cpu 使用率
# systemctl set-property [email protected] BlockIOWeight=1000   # IO 权重

# systemctl status mysql@3327
● [email protected] - MySQL Server node3327
   Loaded: loaded (/usr/lib/systemd/system/[email protected]; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/[email protected]
           └─50-MemoryLimit.conf
   Active: active (running) since Fri 2018-12-07 21:31:32 CST; 1min 18s ago
  Process: 58084 ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start (code=exited, status=0/SUCCESS)
 Main PID: 58159 (mysqld_safe)
   Memory: 1.3M (limit: 5G)            # 内存限制 5G
   CGroup: /system.slice/system-mysql.slice/[email protected]
           ├─58159 /bin/sh /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101//bin/mysqld_safe --defaults-file=/export/mysql/node3327/my.node.cnf
           ├─59489 /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101/bin/mysqld --defaults-file=/export/mysql/node3327/my.node.cnf --basedir=/opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101 --datadir=/export/mysql/node3327/...
           └─59490 logger -t mysqld-3327 -p daemon.error

更多属性参见 man systemd.resource-control , 不过一些参数没有对应的属性, 需要手动单独设置, 比如设置单独某个服务的 memory + swap 限制, 可以使用以下命令将限制的字节数写到对应的参数文件中:

echo xxxxxx > memory.memsw.limit_in_bytes

查看 MySQL 进程 cgroup 信息, 可以看到 memory, blkid, cpuacct 三个条目对应的信息:

# cat /proc/59489/cgroup 
11:memory:/system.slice/system-mysql.slice/[email protected]
10:devices:/system.slice/system-mysql.slice
9:cpuset:/
8:blkio:/system.slice/system-mysql.slice/[email protected]
7:perf_event:/
6:hugetlb:/
5:freezer:/
4:cpuacct,cpu:/system.slice/system-mysql.slice
3:pids:/system.slice/system-mysql.slice
2:net_prio,net_cls:/
1:name=systemd:/system.slice/system-mysql.slice/[email protected]

查看进程相关的限制值:

# cat /sys/fs/cgroup/memory/system.slice/system-mysql.slice/mysql\@3327.service/memory.limit_in_bytes 
5368709120

# cat /sys/fs/cgroup/blkio/system.slice/system-mysql.slice/mysql\@3327.service/blkio.weight
1000

# cat /sys/fs/cgroup/cpu/system.slice/system-mysql.slice/mysql\@3327.service/cpu.cfs_quota_us 
150000

简单验证

这里仅以不同的 CPUQuota 为例说明, 如下所示可以看到, MySQL 进程在不同 CPUQuota 限制下的不同表现, benchyou 的压测结果也相差较大.

限制进程 CPUQuota 为 150% 的情况下:

# top -p 59489
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                           
 59489 mysql     20   0 3412052 1.468g   8784 S 149.5  2.3   7:08.22 mysqld

# benchyou --oltp-tables-count=256 --read-threads=30 --update-threads 8 --write-threads 6 --delete-threads=5 --mysql-table-engine=innodb ..
time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[13s]        [r:30,w:6,u:8,d:5]  3323     304     3019    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         62.56      9.92         40765

time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[14s]        [r:30,w:6,u:8,d:5]  3319     325     2994    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         57.21      9.99         44084

限制进程 CPUQuota 为 400% 情况下:

# top -p 59489
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                           
 59489 mysql     20   0 3416472 1.474g   8796 S 400.0  2.4   7:47.42 mysqld 


# benchyou --oltp-tables-count=256 --read-threads=30 --update-threads 8 --write-threads 6 --delete-threads=5 --mysql-table-engine=innodb ..
time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[10s]        [r:30,w:6,u:8,d:5]  10547    967     9580    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         19.49      3.12         96270

time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[11s]        [r:30,w:6,u:8,d:5]  10829    1036    9793    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         18.23      3.04         107099

会话级别限制

如果没有以 service 启动, 可以按照 pid 查看会话级别的信息:

# systemctl status 303   # 303 为 mysql 进程 id
● session-31208.scope - Session 31208 of user root

session-31208.scope 即为会话级别的信息, 一个会话可能包含多个 MySQL 进程, 使用上述的 systemctl set-property session-31208.scope XXXX 即可对整个会话的进程进行相关的限制. 当然使用这种方式即是对多个进程总体使用情况的限制.

其它限制

如果要单独限制 1 个进程 id, 则需要借助 libcgroup 提供的工具, 具体的使用同 Centos6 的设置, 不过 Centos7 已经弃用了 libgcgroup-tools, 不再建议使用, 如果要对单独进程进行限制, 最好使用 service 进行启动. 另外从 systemd 提供的 ControlGroupInterface 来看, 其提供的控制选项还不够精细, 比如没有 memsw, cpuset 等设置的属性, 这种情况下如果有限制的需求, 还需要靠和以前一样的 libcgroup-tool 方式来设置, 比如以下设置, 限制 pid 为 59489 的进程仅使用 cpu 0 ~ 5, mem 可以是 cpu node0 或 node1, cgclassify 没有指定 --sticky 选项的话则 tasks 会包含指定进程的子进程信息:

# cgcreate -g  cpuset:[email protected]
# cgset -r cpuset.cpus=0-5 [email protected]
# cgset -r cpuset.mems=0-1 [email protected]
# cgclassify -g cpuset:[email protected] 59489

当然也可以使用红帽知识库的方式在启动进程的时候就限制相应的 cpuset 等选项, 详见 redhat-1445073

参考


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK