linux线程cpu亲和性,再谈系统调优关于CPU亲和性的处理

CPU亲和性

cpu亲和性,通俗来讲,就是程序长时间固定运行在特定cpu上的倾向性,所以也作cpu pinning,即程序钉在cpu上的特性;cpu亲和性在许多特定场合使用会收到意想不到的性能提升效果,一般来说,针对以下几种场景的程序,应该使用cpu亲和性把程序固定在特定cpu上运行

计算密集型

诸如编译大型程序(例如内核)、进行科学计算等cpu密集型任务,这类任务通常要运行比较长的时间,且cpu占用都会很高,将程序钉在特定的cpu上运行,尽可能地减少进程切换,使得cpu资源能够最大化地用于计算

业务敏感型

业务敏感主要是指诸如数据库和前端http网关这类应用,此类进程通常对延时敏感,而影响延时的因素,除了网络延时外,在处理请求的速度上也有更高的要求,及时响应并处理完请求,就能更好地提高并发能力,另外,某些特定的应用可能对cpu亲和性做了特殊优化,也能够更好地提高性能

如何使用CPU亲和性

cpu亲和性是要将程序钉在指定的cpu core上运行,不希望该程序发生迁移,这也就是程序独占cpu资源,需要做到以下两点:

1、进程绑定到指定的cpu

2、其他进程不会被调度到这些cpu

要实现1中的进程绑定到指定的cpu,普遍有4种方法:

1、cgroup

2、taskset

3、numactl

4、systemd cpuaffinity

这些方法在之前的调优系统篇已经作了叙述,这里就numactl和systemctl cpuaffinity进行深入分析

numactl

numactl的使用基于服务器的numa架构,关于numa架构,网上有非常多的资料可以参考,弄懂numa架构之后,确认服务器的numa架构,就可以使用numactl提供的绑定功能,将特定的服务绑定到指定的cpu上面运行了;numactl实现的绑定是非常可靠的,一旦绑定了进程到特定cpu,该进程就不会被调度到其他的cpu,但是在使用numactl命令的时候,发现一个问题

首先,为了最大化使用cpu,我在/etc/default/grub文件中编辑这一行:

1GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet rd.driver.blacklist=nouveau nouveau.modeset=0 net.ifnames=0 isolcpu=8-55"

即我希望将8-55号cpu从系统程序调度器中去除,这样系统就不会将其他任务调度到这些cpu上面,然后使用numactl启动服务,启动方法就是编辑服务对应的systemctl服务文件,在启动行里加入需要的命令和参数,例如:

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[tanweijie@ceph-c204 ~]$ systemctl cat ceph-osd@1.service

# /etc/systemd/system/ceph-osd@1.service

[Unit]

Description=Ceph object storage daemon osd.1

After=network-online.target local-fs.target time-sync.target ceph-mon.target

Wants=network-online.target local-fs.target time-sync.target

PartOf=ceph-osd.target

[Service]

LimitNOFILE=1048576

LimitNPROC=1048576

EnvironmentFile=-/etc/sysconfig/ceph

Environment=CLUSTER=ceph

ExecStart=/usr/bin/numactl -C 8-9 -m 0 /usr/bin/ceph-osd -f --cluster ${CLUSTER} --id 1 --setuser ceph --setgroup ceph

ExecStartPre=/usr/lib/ceph/ceph-osd-prestart.sh --cluster ${CLUSTER} --id 1

ExecReload=/bin/kill -HUP $MAINPID

ProtectHome=true

ProtectSystem=full

PrivateTmp=true

TasksMax=infinity

Restart=on-failure

StartLimitInterval=30min

StartLimitBurst=30

RestartSec=20s

[Install]

WantedBy=ceph-osd.target

主要就是在ExecStart这个参数里进行修改,指定cpu和内存的分配node,然后start服务。

实测发现,被isolcpu参数隔离的cpu,是不能通过上述方式启动的,原因是隔离出去的cpu没有在系统程序调度器中,解决办法就是加入 -a 参数,即选择cpu的时候检测所有的cpu,而不仅仅是检测系统可用的cpu

但是,新的问题出现了,即使使用了 -a 参数,服务也正常起来了,但服务的运行有些奇怪,所有绑定了多个cpu的程序,都只使用了第一个指定的cpu,其他的cpu则全部处于空闲状态,例如:

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[tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service

# /etc/systemd/system/ceph-radosgw@rgw.ceph-c204.service

[Unit]

Description=Ceph rados gateway

After=network-online.target local-fs.target time-sync.target

Wants=network-online.target local-fs.target time-sync.target

PartOf=ceph-radosgw.target

[Service]

LimitNOFILE=1048576

LimitNPROC=1048576

EnvironmentFile=-/etc/sysconfig/ceph

Environment=CLUSTER=ceph

ExecStart=/usr/bin/numactl -a -C 42-55 -m 1 /usr/bin/radosgw -f --cluster ${CLUSTER} --name client.%i --setuser ceph --setgroup ceph

PrivateDevices=yes

ProtectHome=true

ProtectSystem=full

PrivateTmp=true

TasksMax=infinity

Restart=on-failure

StartLimitInterval=30s

StartLimitBurst=5

[Install]

WantedBy=ceph-radosgw.target

绑定了42-55号cpu,理应这些cpu都会被使用上,但是结果是

single_cpu.png

因而,在使用ioslcpu之后的cpu选择上,numactl似乎处理地有些问题,我将该问题反馈给了intel的linux相关开发人员,希望他们可以抽空修复;

总结numactl的方法,如果绑定的是单个core,还是很不错的,它可以指定内存的分配,在numa架构的处理器上,这点是十分重要的

systemd cpuaffinity

systemd是最新的centos 7使用的服务管理程序,它替代了原来的SysV服务,成为了系统的第一个进程,进程pid为1,此后,所有进程都是从systemd fork出来,使用它能够非常方便地管理服务。

systemctl就是管理服务的命令,它有许多子命令,这里就不详细赘述,只讲跟cpu亲和性有关的内容了;systemctl编辑管理服务最常用的是下面几个:

1、systemctl cat 服务名 - 这个命令可以查看到对应服务的启动的详细配置文件

2、systemctl start 服务名 - 启动服务

3、systemctl stop 服务名 - 停止服务

4、systemctl restart 服务名 - 重启服务

5、systemctl edit 服务名 –full - 编辑服务启动配置文件,注意要加–full,否则打开的就是空配置文件

使用systemctl edit命令打开配置文件进行编辑时,可以看到有几个配置域,例如rgw服务的配置文件:

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[tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service

# /etc/systemd/system/ceph-radosgw@rgw.ceph-c204.service

[Unit]

Description=Ceph rados gateway

After=network-online.target local-fs.target time-sync.target

Wants=network-online.target local-fs.target time-sync.target

PartOf=ceph-radosgw.target

[Service]

LimitNOFILE=1048576

LimitNPROC=1048576

EnvironmentFile=-/etc/sysconfig/ceph

Environment=CLUSTER=ceph

ExecStart=/usr/bin/radosgw -f --cluster ${CLUSTER} --name client.%i --setuser ceph --setgroup ceph

PrivateDevices=yes

ProtectHome=true

ProtectSystem=full

PrivateTmp=true

TasksMax=infinity

Restart=on-failure

StartLimitInterval=30s

StartLimitBurst=5

[Install]

WantedBy=ceph-radosgw.target

这里只关注[Service]域的配置,可以看到有很多个参数,最重要的就是ExecStart,它指定了进程的启动方式,详细的参数的说明,可以参考systemd.directives,讲的很详细了。我们这里最关注的是两个参数:

1

2

3

4

5

6

7

8

9CPUAffinity=

Controls the CPU affinity of the executed processes. Takes a list

of CPU indices or ranges separated by either whitespace or

commas. CPU ranges are specified by the lower and upper CPU

indices separated by a dash. This option may be specified more

than once, in which case the specified CPU affinity masks are

merged. If the empty string is assigned, the mask is reset, all

assignments prior to this will have no effect. See

sched_setaffinity(2) for details.

这里CPUAffinity就可以指定服务在启动的时候,使用哪种cpu亲和性,一旦配置,就可以使服务绑定运行在指定的cpu上,也就达到了我们的目的。另外我们可能还需要关注另外一个参数:

1

2

3

4Nice=

Sets the default nice level (scheduling priority) for executed

processes. Takes an integer between -20 (highest priority) and 19

(lowest priority). See setpriority(2) for details.

Nice参数指定了服务启动时的优先级情况,我们的想法就是让进程持久地运行在指定的cpu上,设置其优先级最高级别,也能防止进程的切换;进行了参数设置之后的配置例如:

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[tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service

# /etc/systemd/system/ceph-radosgw@rgw.ceph-c204.service

[Unit]

Description=Ceph rados gateway

After=network-online.target local-fs.target time-sync.target

Wants=network-online.target local-fs.target time-sync.target

PartOf=ceph-radosgw.target

[Service]

LimitNOFILE=1048576

LimitNPROC=1048576

EnvironmentFile=-/etc/sysconfig/ceph

Environment=CLUSTER=ceph

ExecStart=/usr/bin/radosgw -f --cluster ${CLUSTER} --name client.%i --setuser ceph --setgroup ceph

PrivateDevices=yes

ProtectHome=true

ProtectSystem=full

PrivateTmp=true

TasksMax=infinity

Restart=on-failure

StartLimitInterval=30s

StartLimitBurst=5

Nice=-20

CPUAffinity=14 15 16 17 18 19 20 21 22 23 24 25 26 27

[Install]

WantedBy=ceph-radosgw.target

这样进行配置后,htop可以看到效果:

1524801837944.jpg

这里设置的0-2号cpu绑定到了其他进程上,系统所有的进程绑定到了42-55号cpu上,其余cpu没有被绑定,因此不会被使用

避免进程调度到已被绑定的cpu

要阻止系统将进程调度到已被绑定的cpu上,有两种思路:

1、不让系统程序调度器看到那些cpu,方法就是使用内核参数isolcpu,这样无论如何,系统都无法在这些cpu进行程序的调度(中断除外)

2、即使程序调度器可以看到所有cpu,但可以设置cpu亲和性来强迫系统进程运行在特定的cpu上,这样就可以避免调度到未指定的cpu上

未被使用的cpu并不是使用了isolcpu进行隔离的,而是在/etc/systemd/system.conf中对systemd进行了全局的cpu亲和性绑定,这样可以做到,就算所有的cpu都被系统程序调度器看到,除非在服务中指定了cpuaffinity,否则默认是不会调度到未绑定的cpu上,与isolcpu的功能基本一致;这里多说一句,isolcpu开始逐步被redhat抛弃,并且redhat在systemd中可以配置cpuaffinity,也有逐步摆脱numactl的意向

最后要关注的点

关于cpu的优化,了解numa架构并合理利用,理解cpu亲和性并实现绑定,关于处理器的优化基本上就完成了,在某些场合,如果发现业务运行时有较大的波动,排除是链路引起的问题之后,可以考虑在中断这块入手,将中断手动实现绑定,说不定能得到更稳定的性能

本文作者:奋斗的松鼠 - tanweijie_2012@163.com

本文链接:

http://www.strugglesquirrel.com/2018/04/26/再谈系统调优关于CPU亲和性的处理/

版权声明:

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!

特别说明:

本博客的第一手更新发布在微信公众号"奋斗的cepher",那里有更多干货等着你,如果喜欢我的文章,就请关注我的公众号吧

本文浏览次数:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值