|
|
[color="Red"]by soloforce@linuxsir.cn 2007.12.25
欢迎转载,但请务必保留作者署名及版权信息
本文介绍了在一台装有Gentoo Linux的PC上构建虚拟集群HPC环境的方法。没有物理集群条件的同学可以在此虚拟环境下进行有限的仿真练习,如MPI编程。注意,除非你的PC拥有4CPU甚至更多,虚拟集群下的并行程序的效率可能比单机下的串行程序效率还低,原因是显而易见的。
[color="Red"]一、准备工作
[color="Blue"]1、硬件配置
虽然是PC,但配置不能太差。推荐07年主流CPU、1G以上内存,或者更好的硬件如笔者的机器(AMD Athlon x2 3600+ OC 2.5G, 4G DDR2 667)可以让一个拥有5节点虚拟环境运行得很流畅。 另外,至少准备20G的硬盘空间用来安装vmware虚拟机。
[color="Blue"]
2、软件配置
在 gentoo linux 下,需要的软件包括vmware-workstation,torque,mpich,openssh,这些都可以在portage中直接emerge,非常方便。我们称物理主机为host(对应集群中的head-node),虚拟机为guest(对应集群中的execution-node)。为了快速构建集群,host和guest都统一用gentoo linux,这不是必须的,因为集群结点完全可以异构。
torque是基于OpenPBS的资源管理、作业分派调度的套件。像OpenPBS一样,包含四个组件:PBS命令解析、pbs_server、pbs_sched、pbs_mom,作用分别是解析PBS作业脚本、创建维护作业、调度作业、创建和维护执行进程。
mpich则是遵循MPI规范的一套最重要的MPI库实现,应用非常广泛,在诸多平台下均得到良好支持。gentoo linux的portage中有mpich version 1和mpich version 2,对应MPI规范的不同版本,本文采用前者。
[color="Red"]二、安装软件
[color="Blue"]1、先介绍host下的软件安装:
a、安装 vmware-workstation
- # emerge -av vmware-workstation
复制代码
b、安装torque
- # echo "sys-cluster/torque server" >> /etc/portage/package.use
- # emerge -av torque
复制代码
c、安装mpich version 1
d、安装openssh并启用ssh服务
- # emerge -av openssh
- # /etc/init.d/sshd start
复制代码
[color="Blue"]2、然后是guest下的软件安装:
如何在vmware-workstation中安装gentoo linux不在本文赘述,唯一建议是用gentoo-minimal.iso进行最小化安装,然后升级(虚拟机也要与时俱进,尽管过程是痛苦的),最后来个clone**──vmware对这个很在行,于是就有了3个或者更多的虚拟gentoo(或称为虚拟结点),欢畅地运行着──注意,虚拟机超过PC处理器节点数越多就越会降低集群的效率!在你的忍受极限与集群结点个数间做个权衡折中吧。
a、安装torque
b、安装mpich version 1
c、安装openssh并启用ssh服务
- # emerge -av openssh
- # /etc/init.d/sshd start
复制代码
[color="Red"]三、集群外围环境配置
[color="Blue"]1、机器名字的设置
torque的各节点通信时,采用各节点的域名(完整的或者简化的)作为节点代号,而mpich则采用FQDN(Fully Qualified Domain Name)对节点进行标识。我们要注意的torque对节点代号的使用,如 "headnode.mycluster.org" 与 "headnode" 尽管是标识同一个节点,但在通信方面则会有不同结果,这主要是因为ssh的密钥验证机制。
笔者构建了5个虚拟gentoo(虚拟节点),分别命名为 gentoo1.mycluster.org ... gentoo5.mycluster.org; 物理主机host则命名为 server.mycluster.org。为描述方便,各节点分别为简称server、gentoox。若因构建一个虚拟集群而架设一台DNS显得不太明智,最好的办法是把各节点的域名写入 /etc/hosts 文件,如:
在server上有:
# cat /etc/hosts
...
127.0.0.1 server.mycluster.org server
10.0.1.11 gentoo1.mycluster.org gentoo1
10.0.1.12 gentoo2.mycluster.org gentoo2
10.0.1.13 gentoo3.mycluster.org gentoo3
10.0.1.14 gentoo4.mycluster.org gentoo4
10.0.1.15 gentoo5.mycluster.org gentoo5
...
在gentoo1上有:
# cat /etc/hosts
...
127.0.0.1 gentoo1.mycluster.org gentoo1
10.0.1.1 server.mycluster.org server
10.0.1.12 gentoo2.mycluster.org gentoo2
10.0.1.13 gentoo3.mycluster.org gentoo3
10.0.1.14 gentoo4.mycluster.org gentoo4
10.0.1.15 gentoo5.mycluster.org gentoo5
...
其他虚拟节点与gentoo1类似。最后,可以用ping来测试全部节点的互联情况,确保全部节点均彼此连同。
[color="Blue"]
2、ssh 无密码验证配置
torque的采用无须密码验证的ssh会话来传送文件、返回结果等。因此可以采用RSA、DSA密钥简化ssh验证。另外,要注意的是,对不同的用户账号,都要重新设定ssh密钥。
以普通用户cluster-user身份在server和全部gentoox节点下执行:
- cluster-user@server$ ssh-key
- Generating public/private rsa key pair.
- Enter file in which to save the key (/home/cluster-user/.ssh/id_rsa): <直接按回车>
- Enter passphrase (empty for no passphrase): <直接按回车>
- Enter same passphrase again: <直接按回车>
- Your identification has been saved in /home/cluster-user/.ssh/id_rsa.
- Your public key has been saved in /home/cluster-user/.ssh/id_rsa.pub.
- The key fingerprint is:
- 34:82:91:78:c1:cd:ef:a2:49:da:3a:f3:92:d9:21:c7 cluster-user@server
复制代码
然后把生成的RSA公钥拷贝到所有其他节点上,包括server和gentoox,这很重要。下面是把server的RSA公钥通过scp传送到gentoox节点的过程。
- cluster-user@server$ scp .ssh/id_rsa.pub gentoo1:<注意此处用的是简称>
- <要输入密码>
- cluster-user@server$ scp .ssh/id_rsa.pub gentoo2:<注意此处用的是简称>
- ...
- cluster-user@server$ scp .ssh/id_rsa.pub gentoo5:<注意此处用的是简称>
- <要输入密码>
复制代码
然后在gentoox下执行:
- cluster-users@gentoo1$ cat id_rsa.pub >> .ssh/authorized_keys
复制代码
这样,server就能够无密码ssh登录到gentoox上了,但gentoox则还不能如此登录到server,故还要反向再做一次类似动作。这是一个简单而枯燥的过程,任意两个节点包括server,都必须彼此实现无密码ssh登录。
[color="Red"]四、集群核心配置
emerge好torque后,就可以配置torque了,所有的配置文件默认在 /var/spool/torque/ 下面。
[color="Blue"]1、gentoox上的torque配置
很简单,只有一个文件需要修改:
- gentoo1# cat /var/spool/torque/mom_priv/config
- arch x86
- opsys Gentoo Linux 2007.0
- $pbsserver server.mycluster.org <pbs_server的名字,很重要>
- $logevent 255
复制代码
然后就可以启动 pbs_mom了:
- gentoo1# /etc/init.d/pbs_mom start
复制代码
[color="Blue"]
2、server上的torque配置
我们先查看pbs_server的名字:
- server# cat /var/spool/torque/server_name
- server.mycluster.org
复制代码
首次执行pbs_server,并创建第一个作业队列:
- server# pbs_server -t create <首次执行时才需要 -t create>
- server# qmgr
- Max open servers: 4
- Qmgr:set server operators = root@server.mycluster.org <添加管理员>
- Qmgr:set server operators += cluster-user@server.mycluster.org
- Qmgr:create queue batch <创建第一个作业队列>
- Qmgr:set queue batch queue_type = Execution <设置作业队列类型>
- Qmgr:set queue batch started = True <启用作业队列>
- Qmgr:set queue batch enabled = True
- Qmgr:set server default_queue = batch
- Qmgr:set server resources_default.nodes = 1
- Qmgr:set server scheduling = True
复制代码
把execution nodes全部加入到pbs_server的节点列表中:
- server# cat /var/spool/torque/server_priv/nodes
- gentoo1 <注意此处用的是简称,与上面创建ssh RSA密钥时一致>
- gentoo2
- gentoo3
- gentoo4
- gentoo5
复制代码
接着可以重启 pbs_server 和 pbs_sched 了:
- server# qterm -t quick
- server# /etc/init.d/pbs_server start
- server# /etc/init.d/pbs_sched start
复制代码
然后可以查看全部节点的运行状态:
- $ pbsnodes
- gentoo1
- state = free
- np = 1
- ntype = cluster
- status = arch=x86,opsys=Gentoo Linux 2007.0,uname=Linux gentoo1 2.6.23-gentoo-r4 #7 SMP Sat Dec 22 06:36:46 CST 2007 i686,sessions=5986 6702,nsessions=2,nusers=1,idletime=18439,totmem=1012952kb,availmem=999868kb,physmem=125136kb,ncpus=1,loadave=0.00,netload=51290737,state=free,jobs=,varattr=,rectime=1198513228
- gentoo2
- state = free
- np = 1
- ntype = cluster
- status = arch=x86,opsys=Gentoo Linux 2007.0,uname=Linux gentoo2 2.6.23-gentoo-r4 #7 SMP Sat Dec 22 06:36:46 CST 2007 i686,sessions=3987 9062 9394,nsessions=3,nusers=1,idletime=28617,totmem=1012952kb,availmem=998484kb,physmem=125136kb,ncpus=1,loadave=0.00,netload=50520768,state=free,jobs=,varattr=,rectime=1198513270
- ...
复制代码
查看队列则可以用qstat命令,还可以执行qmgr后再执行交互式命令对torque进行设置,具体命令参数请查看相关文档,此处不再赘述。至此,虚拟集群已经构建完毕。
[color="Red"]
五、虚拟环境中的HPC
因为是单台PC上的虚拟集群,那么所谓HPC就名不副实了。不要太贪心,事情总要一步一步地做,先在虚拟集群上练练手,等熟悉后就可以在物理集群上大展身手搞HPC了。因为篇幅和版面讨论内容限制,本文仅仅简单介绍集群下的PBS+MPI并行编程的一个示例,其他事项请自行查阅相关资料,也欢迎与笔者共同探讨。
[color="Blue"]1、编写MPI程序
我们假定需要编写一个程序,求下面的积分:
f(x)=\int_0^1{\frac{4}{1+x^2}dx} <tex脚本>
编写mpich程序如下:
- /*
- description: integral sample in mpich
- file name: integral.c
- */
- #include "mpi.h"
- #include <stdio.h>
- #include <string.h>
- double integral(int id, double stride)
- {
- double dx=0.0000000001;
- double result=0;
- double x;
- for(x=id*stride;x<(id+1)*stride;x+=dx)
- {
- result+=dx/(1+x*x);
- }
- return result;
- }
- int main(int argc, char* argv[])
- {
- double sum0,sum1,sum2,sum3,sum4;
- MPI_Status status;
- int myid,numprocs;
- double stride=1.0/5;
- char processor_name[MPI_MAX_PROCESSOR_NAME];
- int namelen;
-
- MPI_Init(&argc, &argv);
- MPI_Comm_rank(MPI_COMM_WORLD,&myid);
-
- MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
- if(myid==0)
- {
- sum0=integral(myid,stride);
- MPI_Send(&sum0,1,MPI_DOUBLE,1,99,MPI_COMM_WORLD);
- MPI_Get_processor_name(processor_name,&namelen);
- printf("Process %d of %d on %s finished\n",myid,numprocs,processor_name);
- }
- else if(myid==1)
- {
- sum1=integral(myid,stride);
- MPI_Recv(&sum0,1,MPI_DOUBLE,0,99,MPI_COMM_WORLD,&status);
- sum1+=sum0;
- MPI_Send(&sum1,1,MPI_DOUBLE,2,99,MPI_COMM_WORLD);
- MPI_Get_processor_name(processor_name,&namelen);
- printf("Process %d of %d on %s finished\n",myid,numprocs,processor_name);
- }
- else if(myid==2)
- {
- sum2=integral(myid,stride);
- MPI_Recv(&sum1,1,MPI_DOUBLE,1,99,MPI_COMM_WORLD,&status);
- sum2+=sum1;
- MPI_Send(&sum2,1,MPI_DOUBLE,3,99,MPI_COMM_WORLD);
- MPI_Get_processor_name(processor_name,&namelen);
- printf("Process %d of %d on %s finished\n",myid,numprocs,processor_name);
- }
- else if(myid==3)
- {
- sum3=integral(myid,stride);
- MPI_Recv(&sum2,1,MPI_DOUBLE,2,99,MPI_COMM_WORLD,&status);
- sum3+=sum2;
- MPI_Send(&sum3,1,MPI_DOUBLE,4,99,MPI_COMM_WORLD);
- MPI_Get_processor_name(processor_name,&namelen);
- printf("Process %d of %d on %s finished\n",myid,numprocs,processor_name);
-
- }
- else if(myid==4)
- {
- sum4=integral(myid,stride);
- MPI_Recv(&sum3,1,MPI_DOUBLE,3,99,MPI_COMM_WORLD,&status);
- sum4+=sum3;
- sum4=sum4*4;
- MPI_Get_processor_name(processor_name,&namelen);
- printf("Process %d of %d on %s finished\n",myid,numprocs,processor_name);
- printf("result is %.6lf\n",sum4);
- }
- MPI_Finalize();
- }
复制代码
编译、链接,生成可执行文件a.out:
- cluster-user@server ~/jobs$ gcc integral.c -lmpich
复制代码
[color="Blue"]2、编写PBS脚本
上述MPI程序使用了5个节点,故编写PBS脚本myjob如下:
- #PBS -N myjob
- #PBS -l nodes=5,walltime=10:00
- #PBS -S /bin/bash
- #PBS -q batch
- nodes=$(cat $PBS_NODEFILE)
- echo "Nodes allocated in job $PBS_JOBID"
- echo "------------------------------------------"
- echo "$nodes"
- echo
- ## copy a.out to every nodes
- for node in $nodes ;do
- scp server.mycluster.org:~/jobs/a.out $node:~/jobs/a.out
- done
- echo "Starting job $PBS_JOBID on $(hostname)"
- echo "---------------------------------------------"
- cd ~/jobs/
- mpirun -machinefile $PBS_NODEFILE -np 5 a.out
复制代码
[color="Blue"]3、提交作业
cluster-user@server$ qsub myjob
[color="Blue"]4、查看结果
- ~/jobs $ cat myjob.o31
- Nodes allocated in job 31.server.mycluster.org
- ------------------------------------------
- gentoo5
- gentoo4
- gentoo3
- gentoo2
- gentoo1
- Starting job 31.server.mycluster.org on gentoo5
- ---------------------------------------------
- Process 1 of 5 on gentoo4.mycluster.org finished
- Process 2 of 5 on gentoo3.mycluster.org finished
- Process 4 of 5 on gentoo1.mycluster.org finished
- result is 3.141592
- Process 3 of 5 on gentoo2.mycluster.org finished
- Process 0 of 5 on gentoo5.mycluster.org finished
复制代码
结果是f(x)=3.141592,即为所求积分答案。
[color="Red"]六、结语
本文简要介绍了在gentoo linux下实现虚拟集群的外围环境、配置方法和步骤,并简要给出PBS+MPI的编程实例,希望对爱好集群和HPC的初学者有所帮助。本文也是目前在集群构建方面的初级读物中较为详细和全面的一篇文章。
参考链接:
http://www.clusterresources.com/ ... =torque:torque_wiki
[color="Red"]by soloforce@linuxsir.cn 2007.12.25 临晨
|
|