`
cloudeagle_bupt
  • 浏览: 533687 次
文章分类
社区版块
存档分类
最新评论

torque+openmpi+cgroup实现任务间资源隔离

 
阅读更多

转自: http://basiccoder.com/torque-openmpi-cgroup-isolate.html

从工作到现在就没再更新过博客,工作后忙了人也变懒了,为了对得起我每年要交的虚拟主机和域名费用,写下最近在干的事,要干什么标题写得已经很明白了,这个事情的难点到不在于openmpi和cgroup有多复杂,而是torque的代码写得实在是太乱了,无数次吐槽也改变不了我对它的印象,诡异的缩进风格(这个好像glibc也是这种风格)也就罢了,还在这种编码风格下写了无数上千行甚至几千行的函数,读起来着实痛苦,更不用说修改了。

openmpi需要了解的不多,只是简单的接口就OK了,同样cgroup对于用户态的使用来讲也不是多复杂的问题,还要感谢淘宝内核组的 @蕃茄me mm多次给我讲解了cgroup的原理和使用方法,嗯,我是真心感谢的!

大多数的时间都花在了torque的代码分析上了,具体的编码其实只用了差不多一天的时间,目前还是测试版本,估计后期还得改不少东西,需求总是不断变化的,还得去跟客户沟通。。。下面是相关的开发流程和测试数据

1. cgroup

资源隔离主要涉及到计算节点,与pbs_server无关,因此在torque/src/resmom/目录中添加mom_cgroup.c,用于处理cgroup创建删除和进程隔离的逻辑。

目前仅对cpu和memory进行隔离,计算节点需要做如下准备工作:

[root@vkvm050]# mkdir /dev/torque
[root@vkvm050]# mount -t cgroup -o cpuset,memory torque /dev/torque

资源隔离在job和job之间进行,同一个job之间的不同进程不做隔离,它们可以使用共享资源,比如,一个job指定ppn=2,pmem=60,则该job可以使用2个cpu,和120M的内存。

1.1 cpu隔离
cpu按cpu号来划分,如某节点有16个cpu,编号为0-15,假设全部空闲,则该job可占用0-1号cpu,这两个cpu由该job独占,若新任务到来后需要ppn=4,则为其分配2-5号cpu,以此类推。

在torque中根据cpu数量维护一个job-cpu的列表,用以提供cpu使用情况的信息。

1.2 memory隔离
不对job做numa node的隔离,因此从root cgroup中的cpuset.mems中读取所有的numa node信息,并写入具体job对应的cgroup cpuset.mems,即所有job可用所有numa node:

/dev/torque/cpuset.mems –>read –> write to -> /dev/torque/21.vkvm050/cpuset.mems

对于具体job内存使用量的隔离是使用/dev/torque/JOBID/memory.limit_in_bytes

2. torque与cgroup的结合

目前可使用qmgr来控制cgroup的开关:

qmgr -c ‘set server cgroup_enable = True’

2.1 开关控制逻辑的实现

通过qmgr设置pbs server全局属性,cgroup_enable = True, 对于计算节点无法获知该属性,因此对job添加一个属性JOB_ATR_cgroup_enable,在新任务创建时根据pbs server中cgroup的开关设置来初始化这个属性,在job传递到master节点或计算节点时该属性会同时被传递过去,在job执行前和执行后可通过判断job的该属性来判断该job是否需要使用cgroup隔离。

2.2 torque对job进程的调度

torque提供了一个用于task manager的工具pbsdsh,通过这个工具在不能的节点上对进程进行操作,启动关闭等等。

任务的执行分为master节点(torque中称为Mother Superior)和计算节点(Sister Nodes)

2.2.1 job在ms上的执行

qsub向pbs server提交job,pbs server中创建job对象,经过调度器调度可执行后向ms节点发送PBS_BATCH_Commit指令,ms收到后做些准备工作后调用start_exec(job *pjob)来执行job,这个函数是比较复杂的,但总结起来启动job的过程比较简单,主要干了两件事:

1. 向sister nodes发送IM_JOIN_JOB,告诉这些计算节点这个job将会在你们上面跑,做好准备。
2. 调用exec_job_on_ms()在本节点上开始执行job

exec_job_on_ms()主要在本地节点创建job,这个函数先启动一个shell,然后在这个shell中执行用户提交的job script,在这个job script中再去调mpirun,启动的这个shell进程是job进程的子进程,我们将该shell的pid写入/dev/torque/JOBID/tasks便可在ms节点上对该job进行隔离。

2.2.2 job在sisters上的执行

1. sister在收到ms发来的IM_JOIN_JOB指令后做job启动的准备工作,在这个阶段我们为这个job创建cgroup.
2. mpirun在ms上开始执行后调用pbsdsh向sisters发送IM_SWAWN_TASK指令,告诉sisters启动一个进程,并将该进程的arguments和envirments都发送给sisters,sister在收到这个指令后开始执行这个进程,这个进程实际上就是orted这个东西,具体的mpi进程就是由它启动的,也就是orted这个进程是mpi进程的父进程,我们把orted的pid写入/dev/torque/JOBID/tasks即可以该job实现隔离,orted的man如下:

The orted command is not intended to be manually invoked by end users. It is part of the Open MPI architecture and is invoked automatically as necessary. This man page is mainly intended for those adventerous end users and system administrators who have noticed an “orted” process and wondered what it is.

所以我们不需要关心orted干了些什么事是怎么用的,只需要知道它会负责启动MPI进程就可以了。

2.2.3 任务退出

任务执行完成后会进入Exiting状态,torque会遍历所有的job并对Exiting状态的Job进行清理,在清理过程中我们根据jobid来删除该job对应的cgroup,并将全局cpu占用表中占的位清掉。

3. torque + openmpi + cgroup测试数据

job script:

#!/bin/bash

#PBS -l nodes=11:ppn=1,pmem=60

/home/a/share/algo1/openmpi-1.4.4/bin/mpirun --hostfile $PBS_NODEFILE ./mpi

MPI程序,每个进程malloc(1024*1024*100),为保证这100M内存全部都被物理页填充,将这100M内存中填充100M字节数据。

cgroup开启前MPI进程的cpu和物理内存占用情况:

[root@vkvm050]# ps -e -o args,psr,rss
orted -mca ess env -mca ort   0  2292
./mpi                         1 106504
orted -mca ess env -mca ort   0  2292
./mpi                         0 106500

cgroup开启后MPI进程的cpu和物理内存战胜情况:

[root@vkvm050]# ps -e -o args,psr,rss
orted -mca ess env -mca ort   1  1860
./mpi                         1 46448
orted -mca ess env -mca ort   0  1860
./mpi                         0 59856
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics