CPU亲和性
cpu亲和性,通俗来讲,就是程序长时间固定运行在特定cpu上的倾向性,所以也作cpu pinning,即程序钉在cpu上的特性;cpu亲和性在许多特定场合使用会收到意想不到的性能提升效果,一般来说,针对以下几种场景的程序,应该使用cpu亲和性把程序固定在特定cpu上运行
写在前面
松鼠哥的ceph专业课程上线啦!
面向新手同学,从0实战,全面入门ceph安装部署与运维,有需要的同学赶紧扫码订购吧:
对于osd来说,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文件中编辑这一行:
1 | GRUB_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 | [tanweijie@ceph-c204 ~]$ systemctl cat ceph-osd@1.service |
主要就是在ExecStart这个参数里进行修改,指定cpu和内存的分配node,然后start服务。
实测发现,被isolcpu参数隔离的cpu,是不能通过上述方式启动的,原因是隔离出去的cpu没有在系统程序调度器中,解决办法就是加入 -a 参数,即选择cpu的时候检测所有的cpu,而不仅仅是检测系统可用的cpu
但是,新的问题出现了,即使使用了 -a 参数,服务也正常起来了,但服务的运行有些奇怪,所有绑定了多个cpu的程序,都只使用了第一个指定的cpu,其他的cpu则全部处于空闲状态,例如:
1 | [tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service |
绑定了42-55号cpu,理应这些cpu都会被使用上,但是结果是
因而,在使用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 | [tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service |
这里只关注[Service]域的配置,可以看到有很多个参数,最重要的就是ExecStart,它指定了进程的启动方式,详细的参数的说明,可以参考systemd.directives,讲的很详细了。我们这里最关注的是两个参数:
1 | CPUAffinity= |
这里CPUAffinity就可以指定服务在启动的时候,使用哪种cpu亲和性,一旦配置,就可以使服务绑定运行在指定的cpu上,也就达到了我们的目的。另外我们可能还需要关注另外一个参数:
1 | Nice= |
Nice参数指定了服务启动时的优先级情况,我们的想法就是让进程持久地运行在指定的cpu上,设置其优先级最高级别,也能防止进程的切换;进行了参数设置之后的配置例如:
1 | [tanweijie@ceph-c204 ~]$ sudo systemctl cat ceph-radosgw@rgw.ceph-c204.service |
这样进行配置后,htop可以看到效果:
这里设置的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亲和性并实现绑定,关于处理器的优化基本上就完成了,在某些场合,如果发现业务运行时有较大的波动,排除是链路引起的问题之后,可以考虑在中断这块入手,将中断手动实现绑定,说不定能得到更稳定的性能
- 本文作者: 奋斗的松鼠
- 本文链接: http://www.strugglesquirrel.com/2018/04/26/再谈系统调优关于CPU亲和性的处理/
- 版权声明: 本博客所有文章除特别声明外,创作版权均为作者个人所有,未经允许禁止转载!