更新日志 2007年9月8日 本文发布
前言 并行计算一直算是比较专业的领域,当然在Linux下依据现有的开源软件搭建一个并行计算的集群还是相对容易的,通常在Linux下使用PVM/MPI的方式来实现并行计算集群的,网络上有许多关于PVM和MPICH搭建计算集群的方法,但似乎还没有针对OpenMPI的搭建方式,至少中文的介绍比较少,所以这里我采用最新的OpenMPI来搭建一个基于LFS平台的集群系统。
本文的目的是为了说明一个简单的并行计算平台搭建的过程 ,作为真正运用的计算集群应该要比这个复杂许多,但通过本文的方法也能体会一下并行计算的感觉。同时,很多人对于LFS的实用性表示怀疑,认为只是一个作为研究的东西,而不能真正的使用到实际的应用中去,所以我希望通过本系列的文章来表明原代码打造的系统所带来的好处:精简,高效。
更新 由于篇幅比较长所以难免出现一些错误或者笔误,也有可能加入新内容,因此难免会进行修正或增删一些内容,如果本文被转载可以在本人的Blog中查看最新版本。
我的Blog:http://youbest.cublog.cn
如须转载请注明作者为孙海勇,并提供转载出处。
OpenMPI,写本文时最新的版本为1.2.2,你可以尝试下载目前最新的版本来使用。
下载
注意: OpenMPI所搭建的集群,是利用了特定的通讯方式/协议(当然也可以用TCP协议)来进行各个节点间的协作完成计算的,应此节点间应尽量保证网络通讯的流畅,以避免因网络线路上的问题而导致的性能下降。
本文采用标准的LFS做为基本系统,因此省略了LFS的制作过程。
预期目标: 用两台以上的个人电脑组成一个可以进行并行计算的计算集群,为了说明的方便,本文采用两个计算节点作为例子,两个以上的机器的做法和两台机器基本是一样的,重复制作就可以完成N个计算机组成的集群,当然这里建立的计算集群是比较简单的,真正的计算集群应该会更加的复杂。
每台计算机我们都可以称为节点,在本例子中有三类节点:控制节点、计算节点、共享存储节点,这三类节点可以相互合并,甚至可以把三类节点放在一个节点上,这里为了说明方便,我们将三类节点分开来,这里共享存储节点不是必须的,但有了这个节点对于计算任务的发布将变的非常容易,所以本文也将对其进行讲解。
我们先来看一副即将构建的计算集群的逻辑结构图。
逻辑结构图:
(黄色区域代表相同的共享存储空间)
为了实现这种逻辑可以有多种网络的架设方法,这里选择一个比较简单的架设为例子。
网络结构图:
这里需要注意的事,最好节点都在同一个网段中,而不要通过网关之类的设备,这样不但可以减少问题的发生而且也可以提高计算过程中的通讯性能。
节点的命名和IP分配控制节点: 192.168.0.1 nfs-node
存储节点: 192.168.0.2 control-node
计算节点: 192.168.0.11 mpi-node1
192.168.0.12 mpi-node2
192.168.0.13 mpi-node3
注:计算节点可以继续增加,这里以三个节点为例子。
前期准备(所有节点) LFS基本系统
内核需要nfs文件系统支持
建立共享存储节点 设置系统的IP为192.168.0.1
设置系统的机器名为nfs-node
编译软件包
Tcp_wrapper-7.6
Portmap-5beta
NFS Utilities-1.0.10
Blfs-bootscript-20070620
配置NFS(共享存储节点)
mkdir /opt/shared
echo “/opt/shared 192.168.0.0/255.255.255.0(rw,subtree_check,anonuid=99,anongid=99)” >> /etc/exports
启动nfs服务
/etc/rc.d/init.d/nfs-server restart
建立控制节点: 设置系统的IP为192.168.0.2
使节点支持nfs,并挂载存储节点上的共享空间
安装软件包:
Tcp_wrapper-7.6
Portmap-5beta
Blfs-bootscript-20070729
make install-portmap
make install-netfs
挂载共享空间
groupadd -g 99 nogroup
useradd -c "Unprivileged Nobody" -d /dev/null -g nogroup -s /bin/false -u 99 nobody
mkdir /opt/share
chmod 0777 /opt/share
echo “192.168.0.1:/opt/share /opt/share nfs rw,_netdev,rsize=8192,wsize=8192 0 0” >> /etc/fstab
/etc/rc.d/init.d/portmap restart
/etc/rc.d/init.d/netfs start
建立主机名文件
cat > /etc/hosts << “EOF”
127.0.0.1 localhost
192.168.0.1 nfs-node
192.168.0.2 control-node
192.168.0.11 mpi-node1
192.168.0.12 mpi-node2
192.168.0.13 mpi-node3
为编译OpenMPI做准备 提示:由于软件包编译时间较长应此,对于节点的硬件结构相同的机器应当在一台机器上编译完成后,直接把编译好的东西复制到其它结点上,以加速集群的建设,同时对于今后加入新的节点提供了方便。
在控制节点上(当然其它节点也可以,不过这里为了简化说明,我就在控制节点上进行)
1)创建计算用户(同时“兼职”编译用户)
useradd -s /bin/bash -m -k /dev/null youbest
su - youbest
mkdir ~/sources
2)将需要的软件包复制到~/sources/目录下。
3)设置编译安装用的环境变量
export DEST_DIR=~/packages
4)编译Openssh,以支持节点间的相互通讯。
OpenSSL-0.9.8e
patch -Np1 -i ../openssl-0.9.8e-fix_manpages-1.patch
./config --openssldir=/etc/ssl --prefix=/usr shared
make MANDIR=/usr/share/man
make test(这里应该正常通过测试,如果进行测试建议先安装bc软件包)
su root
make MANDIR=/usr/share/man install
make MANDIR=/usr/share/man INSTALL_PREFIX=${DEST_DIR} install
cp -v -r certs /etc/ssl
cp -v -r certs ${DEST_DIR}/etc/ssl
exit
OpenSSH-4.6p1
su root
install -v -m700 -d /var/lib/sshd
install -v -m700 -d ${DEST_DIR}/var/lib/sshd
chown -v root:sys /var/lib/sshd
chown -v root:sys ${DEST_DIR}/var/lib/sshd
/usr/sbin/groupadd -g 50 sshd
/usr/sbin/useradd -c 'sshd PrivSep' -d /var/lib/sshd -g sshd -s /bin/false -u 50 sshd
exit
sed -i "s:-lcrypto:/usr/lib/libcrypto.a -ldl:g" configure
sed -i "s/lkrb5 -ldes/lkrb5/" configure
./configure --prefix=/usr --sysconfdir=/etc/ssh \
--libexecdir=/usr/lib/openssh --with-md5-passwords \
--with-privsep-path=/var/lib/sshd
make
su root
make install
make DESTDIR=${DEST_DIR} install
echo "PermitRootLogin no" >> /etc/ssh/sshd_config
echo “PermitRootLogin no” >> ${DEST_DIR}/etc/ssh/sshd_config
exit
blfs-bootscripts-20070620
su root
make install-sshd
make DESTDIR=${DEST_DIR} install-sshd
exit
5)编译OpenMPI及其依赖包(推荐)
1、由于OpenMPI目前支持几种语言,所以如果你还是比较标准的LFS基本系统建议重新编译GCC以加入fortran语言的支持,如果你只想让OpenMPI支持C,那么可以跳过这段gcc的重新编译
1)gmp-4.2.1
./configure --prefix=/usr --enable-cxx --enable-mpbsd
make
make check (这里的测试应该正常通过)
su root
make install
make DESTDIR=${DEST_DIR} install
exit
2)mpfr-2.2.1
./configure --prefix=/usr --enable-shared
make
make check(这里的测试应该正常通过)
su root
make install
make DESTDIR=${DEST_DIR} install
exit
3)gcc-4.1.2
sed -i 's/install_to_$(INSTALL_DEST) //' libiberty/Makefile.in
sed -i 's@\./fixinc\.sh@-c true@' gcc/Makefile.in
sed -i 's/@have_mktemp_command@/yes/' gcc/gccbug.in
mkdir ../gcc-build
cd ../gcc-build
../gcc-4.1.2/configure \
--prefix=/usr \
--libexecdir=/usr/lib \
--enable-shared \
--enable-threads=posix \
--enable-__cxa_atexit \
--enable-clocale=gnu \
--enable-languages=c,c++,fortran
make bootstrap
su root
make install
make DESTDIR=${DEST_DIR} install
ln -sfv ../usr/bin/cpp /lib
mkdir -p ${DEST_DIR}/lib
ln -sfv ../usr/bin/cpp ${DEST_DIR}/lib
ln -sfv gcc /usr/bin/cc
ln -sfv gcc ${DEST_DIR}/usr/bin/cc
chown -Rv root:root /usr/lib/gcc/$(gcc -dumpmachine)/4.1.1/include
chown -Rv root:root ${DEST_DIR}/usr/lib/gcc/$(gcc -dumpmachine)/4.1.1/include
exit
编译OpenMPI tar xvf openmpi-1.2.3.tar.bz2
mkdir openmpi-build
cd openmpi-build
../openmpi-1.2.3/configure --prefix=/usr --sysconfdir=/etc/openmpi
make
make check (这里测试应该正常通过)
su root
make install
make DESTDIR=${DEST_DIR} install
exit
将之前编译的软件包一起打包,便于其它节点直接安装
su root
pushd ${DEST_DIR}
(压缩前可以先进行去除调试符的操作以减少空间占用,不过如果对空间不是很敏感的话不去除调试符也可以)
tar -cjf mpi-packages.tar.bz2 *
mkdir /opt/share/packages/
mv mpi-packages.tar.bz2 /opt/share/packages/
popd
exit
配置SSH 首先保证节点间的通讯畅通无阻,硬件上的不必说,软件上还需要配置一下
su - youbest
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub >> /opt/share/authorized_keys
创建计算节点 计算节点的加入方式是相同的,这里以mpi-node1(192.168.0.11)为例子
设置系统的IP为192.168.0.11,机器名设置为mpi-node1
使节点支持nfs,并挂载存储节点上的共享空间
安装软件包:
Tcp_wrapper-7.6
Portmap-5beta
Blfs-bootscript-20070729
make install-portmap
make install-netfs
挂载共享空间
groupadd -g 99 nogroup
useradd -c "Unprivileged Nobody" -d /dev/null -g nogroup -s /bin/false -u 99 nobody
mkdir /opt/share
chmod 0777 /opt/share
echo “192.168.0.1:/opt/share /opt/share nfs rw,_netdev,rsize=8192,wsize=8192 0 0” >> /etc/fstab
/etc/rc.d/init.d/portmap restart
/etc/rc.d/init.d/netfs start
建立主机名文件
cat > /etc/hosts << “EOF”
127.0.0.1 localhost
192.168.0.1 nfs-node
192.168.0.2 control-node
EOF
cat > /etc/hosts.equiv << “EOF”
control-node
EOF
建立OpenMPI软件环境
su root
tar xvf /opt/share/packages/mpi-packages.tar.bz2 -C /
建立计算用户:
这里建立一个youbest的用户名用于集群计算
useradd -s /bin/bash -m -k /dev/null youbest
配置ssh
su - youbest
mkdir ~/.ssh
cp /opt/share/authorized_keys ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
在控制节点上“登记”刚刚建立的计算节点(控制节点) su root
echo “192.168.0.11 mpi-node1” >> /etc/hosts
echo “mpi-node1” >> /etc/hosts.equiv
echo “mpi-node1” >> /etc/openmpi/openmpi-default-hostfile
或者用编辑软件编辑openmpi-default-hostfile文件加入mpi-node1
注:如果节点有多个CPU,那么可以在mpi-node1后加入”:CPU数”,如:mpi-node1的节点有两个CPU,那么可以在openmpi-default-hostfile中写入
mpi-node1 slots=2
来表示,这样可以更加有效的利用计算资源。
exit
建立其它计算节点: 这里有两种方法来建立
1) 按照mpi-node1的建立方法来一遍,在IP和机器名的地方修改为新节点的IP和机器名即可;
2) 直接将mpi-node1中所有的文件复制到新节点上,然后修改IP和机器名为新的节点的IP和机器名即可。
在建立好新的节点后都要在控制节点上“登记”刚刚建立的计算节点,以便进行计算时使用该节点。
测试ssh工作是否正常 在控制节点上运行
ssh mpi-node1 date
ssh mpi-node2 date
……
如果上述命令执行后应该直接返回日期而不会提示输入密码,那么可以继续了,否则请检查之前的操作是否有遗漏或错误。
加入到控制节点上openmpi-default-hostfile文件中的就是参与集群运算的节点,这里也可以将control-node加入到其中,但如果计算节点较多建议不要把control-node加入,因为控制节点除了运算还要处理节点的调度,所以control-node加入运算反而可能降低运算效率。
建立计算用目录(控制节点) mkdir /opt/shared/test
在用户目录建立链接(控制节点及所有的计算节点)
ln -s /opt/shared/test ~/
到目前为止我们的集群环境已经搭建完成,现在可以找一个程序来测试一下了。
如果你编译Openmpi的源代码目录还没有删除,那么可以进入其目录中的example下,编译hello_c.c文件
make hello_c
会生成一个hello_c可执行文件,将该文件复制到/opt/shared/test目录下
然后在控制节点上运行
mpirun /opt/shared/test/hello_c
你将会看到多个节点的显示返回,代表集群搭建成功了。
下面我们来做一个比较能测试性能的程序,这里利用另一个mpi的软件mpich中带有一个pi的运算程序,在控制节点上编译该文件(mpich软件包可以自行到mpich的网站上下载)
mpicc icpi.c -o pi
然后将pi复制到/opt/shared/test目录下
运行mpirun -n 1 /opt/shared/test/pi (以一个节点的方式运算)
提示输入一个数,你可以按10倍的速度逐步增加,当增加到运行需要不少的时间后,重新运行
mpirun -n 2 /opt/shared/test/pi (两个节点来运算)
或者
mpirun /opt/shared/test/pi(所有的节点均参加运算)
看看是否节点越多,输入同样的数字运算速度越快。:)
好了,到此为止你已经有了一个可以实际工作的计算集群了,你可以继续添加节点来提高并行性能。把没有用的机器集合到一起看看是否可以把这些机器再利用一下。
新的尝试 前面我们是在相同架构的机器来搭建的计算集群,下面我们尝试使用不同架构的机器来搭建一个计算集群。
例如我们在上面的计算集群上加入一组由龙芯CPU为核心的机器,那么我们可以按照下面的步骤加入,下面的方法同样适合加入一台机器。
这组机器我们定义它的名字和IP为:
192.168.0.21 loongson-node1
192.168.0.22 loongson-node2
192.168.0.23 loongson-node3
因为采用的是不同体系的机器,那么之前编译的系统不能用在这些机器上,需要重新编译OpenMPI所需要的所有依赖的包,但同样可以在一台机器完成了编译之后直接应用到其它相同体系结构的机器上运行。
虽然体系不同,但编译过程大同小异(可能有些体系需要打一些补丁),下面仅讲述搭建步骤,编译过程省略。
这里以loongson-node1为例,在其上
1) 安装所有LFS标准包
2) 内核支持NFS
3) 设置机器的IP为192.168.0.21,机器名为loongson-node1
4) 安装软件包以支持NFS
Tcp_wrapper-7.6
Portmap-5beta
Blfs-bootscript-20070729
make install-portmap
make install-netfs
5) 配置NFS
groupadd -g 99 nogroup
useradd -c "Unprivileged Nobody" -d /dev/null -g nogroup -s /bin/false -u 99 nobody
mkdir /opt/share
chmod 0777 /opt/share
echo “192.168.0.1:/opt/share /opt/share nfs rw,_netdev,rsize=8192,wsize=8192 0 0” >> /etc/fstab
/etc/rc.d/init.d/portmap restart
/etc/rc.d/init.d/netfs start
6) 建立主机名文件
cat > /etc/hosts << “EOF”
127.0.0.1 localhost
192.168.0.1 nfs-node
192.168.0.2 control-node
EOF
cat > /etc/hosts.equiv << “EOF”
control-node
EOF
7) 编译gmp、mprf、gcc(为了包含fortran,推荐)
8) 编译openmpi
9) 将编译的各个包合在一起打包,以便今后同样的机器加入节点方便安装。
10) 创建用于计算的用户
注意:这里建立的用户名必须和控制节点上进行计算的用户名相同。
11) 建立计算用目录(控制节点)
mkdir /opt/shared/test-loongson
在用户目录建立链接(控制节点及所有的计算节点)
ln -s /opt/shared/test-loongson ~/test
12) 配置SSH,以便控制节点使用该节点进行计算
13) 在控制节点上“登记”刚刚建立的节点
现在我们已经加入了一个体系结构不同于之前计算节点的机器,下一步就是要探讨一下如何让不同体系架构的计算机同时进行同一项计算任务。
MPI是采用消息的方式进行计算控制的,应此这个过程是指令集无关的,利用这个特点,不同指令集的机器可以进行协同计算,下面我根据前文所建立的两种不同指令集的机器进行一次集群计算任务。
还是使用之前用过的MPICH源代码下的icpi.c文件,将该文件复制到/opt/shared/test-loongson下,然后在刚刚建立的龙芯机器上编译该文件
pushd /opt/shared/test-loongson
mpicc icpi.c -o pi
popd
这样我们就有了一个可以在龙芯机器上运行的集群计算的可执行文件,由于/opt/shared/test-loongson链接到~/test上,那么对于之前的节点中编译的pi和现在龙芯中编译的pi文件所处的位置是相同的,这个时候我们可以在控制节点上执行
mpirun ~/test/pi
如果之前的操作没有问题,那么这个时候将出现请求输入的界面,输入数字后,计算便开始了,在不久后(视你输入数字的大小)你将见到计算结果。
好了,一个多种架构的计算集群搭建完成,而对于在控制节点上进行计算任务的人来说完全感觉不到这个计算集群是由不同指令集来搭建的。
我们可以再加入更多不同类型的机器来构建这样一个集群,是不是很有意思?:-)
性能调节: 对计算节点性能的研究,在一个集群中最好是相同工作能力的计算机搭建,如果性能差异比较大,同时配置节点不够合理那么即使计算节点变多了,可能计算性能反而下降了。我这里给出一个简单的设计原则
以速度最慢的节点作为单位1,如果比该节点速度快一倍则在openmpi-default-hostsfile文件中将该节点的slots的值设置为2,以此类推,快多少倍就设置slots的值为倍数即可
曾经做过一个优化的设置和没优化的设置,在两个单节点的机器上做集群计算,在其中比较快的节点上单独运行pi计算使用了5秒左右,而在慢的节点上单独计算则需要20秒左右,而如果两个节点都不设置slots的值则使用10秒左右,这大大超过了最快的节点单独运算所耗费的时间,计算节点增加了,但计算速度却降低了,之后进行了优化设置,将比较快的节点的slots值设置为5后,两个节点的计算时间缩小到4秒左右,这样两个节点的计算速度终于要少于最快的节点单独计算的速度了。
总结: 下面来总结一下本文对于计算集群架设的要点:
1) 所有的节点均建立好了标准的LFS系统,并且内核支持NFS
2) 建立共享存储使用的节点,通过该节点可以非常方便的为后续的节点建立和计算任务的发布提供方便
3) 除了存储节点,其它节点应该安装上openmpi及openmpi所依赖的所有相关软件包,不过为了加快节点的节点可以使用同种类型节点所编译软件包。
4) 建立至少一个控制节点,用于计算任务的发布和计算控制。
5) 建立至少两个计算节点(废话!否则就不是计算集群了)
6) 设置好各个节点的SSH,这里的要点是控制节点可以顺利的通过SSH访问各个计算节点,为了计算方便,发布控制节点的公钥到各个计算节点上。
7) 控制节点的openmpi的配置文件中配置好需要用来计算的节点,而计算节点则不需要进行任何openmpi的配置。
8) 共享存储节点、控制节点及计算节点可以相互合并为一个节点,甚至三种节点可以合并到一台节点上,如果计算机设备比较充裕,建议将三类节点分开。
9) 计算节点可以由不同指令集或者不同计算机架构的节点共同组成,并可以共同完成同一个计算任务。
10) 如果计算节点中包含不同类型的计算节点,则应该在发布计算任务(计算用的可执行文件)的时候应该针对不同的计算节点发布能在该节点上运行的执行文件。
11) 如果计算集群由不同性能的节点构成,那么应该根据性能倍数的原则设置各个节点上slots的值,以便充分发挥集群的计算性能。
补充一下: 本文写好有一段时间了,但没有进行细致的整理,因此一直没有发出来,最近抽了点时间整理了一下发布出来,所以本文中使用的一些软件版本可能已经不是最新的了,不过这并不影响文章的整体思路,由于本人能力所限文中难免会有错误和偏差,希望发现问题后能及时告诉我,以便最快的进行修改。
(转载请保持文章的完整性,请注明作者和出处) 作者:孙海勇 Email:youbest@sina.com 发表日期:2007年9月8日