Yebangyu's Blog

Fond of Concurrency Programming and Machine Learning

利用Distcc和Dmucs构建大规模、分布式C++编译环境(下)

上篇文章,我们介绍了如何利用Distcc来搭建分布式编译环境,但是Distcc的默认调度策略过于简单,并且并不合理。假如我们的配置是

export DISTCC_HOSTS="192.168.1.11 192.168.1.22 192.168.1.33"

那么Distcc会根据DISTCC_HOSTS中机器出现的先后顺序,来安排编译任务,越靠前的机器(比如这里的192.168.1.11)获得越多的任务,这显然是不科学的。

因此,我们可以利用Dmucs提供的调度策略,来优化我们的方案。它可以根据编译机的负载情况和硬件实力,来合理的调度资源。能者多劳嘛。

为了保证本文的完整性,我们还是不厌其烦地把我们的环境再交待下:

开发机(Client):这一台机器上有我们的项目、工程文件、代码,平时我们在这台机器上写代码,要编译的对象也在这台机器上。机器IP192.168.1.99

服务器(Server):负责编译的机器,一共有3台。IP分别为192.168.1.11,192.168.1.22,192.168.1.33

调度器(Scheduler):调度程序Dmucs所在的机器,负责把编译任务合理的派发到编译机器(服务器)的编译程序上。IP192.168.1.88

服务器

1,安装gcc

sudo apt-get install gcc

2,安装Distcc

sudo apt-get install distcc

安装后可以得到两个二进制文件,distccddistcc。前者主要负责网络数据处理,后者可以认为是g++的前端,调用g++进行编译。

3,配置Distcc

打开/etc/default/distcc,设置如下配置项:

STARTDISTCC="true"  
ALLOWEDNETS="127.0.0.1 192.168.1.0/24"
LISTENER="0.0.0.0"

第一行设置开机就启动distccd

第二行设置允许利用本机进行编译的开发机

第三行设置监听的网络

4,启动distccd

sudo service distcc start

经过以上配置,每次机器开机,都会自动运行distccd

运行如下命令确认下:

ps -aux | grep distccd

如果看到类似的输出,说明distccd成功启动了。

distccd   3457  0.0  0.0   3260   144 ?        SNs  23:33   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --listen 0.0.0.0 --nice 10
distccd   3458  0.0  0.0   3260   144 ?        SN   23:33   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --listen 0.0.0.0 --nice 10
distccd   3461  0.0  0.0   3260   144 ?        SN   23:33   0:00 /usr/bin/distccd --pid-file=/var/run/distccd.pid --log-file=/var/log/distccd.log --daemon --allow 127.0.0.1 --listen 0.0.0.0 --nice 10

5,安装Dmucs

首先,从这里下载最新版本的Dmucs

安装也就是普通的configuremakemake install,需要注意的是,执行make时,需要加上参数,例如:

make CPPFLAGS=-DSERVER_MACH_NAME=\\\"192.168.1.88\\\"

其中192.168.1.88是我们的调度器的机器IP,根据实际情况自行修改。服务器上的编译程序,需要把编译负载情况,发送给调度器上的调度程序,作为它调度时的参考信息。

如果您嫌这样麻烦,那么也可以在make的时候不指定选项,而是在安装后,打开/etc/default/dmucs文件,设置如下字段:

USE_SERVER = 192.168.1.88

6,启动loadavg

loadavg是安装Dmucs后得到的一个二进制文件,它会定期发送服务器平均负载情况给调度器,供调度程序决策之用。

sudo loadavg -s 192.168.1.88 &

其中,192.168.1.88是调度程序所在机器的IP地址。

调度器

1,安装Dmucs

请参考上面的第5步。

2,配置服务器属性

在调度器的/usr/local/share/dmucs/目录下,新建hosts-info文件,格式和内容如下:

#Format: machine number-of-cpus power-index
192.168.1.11       4            10
192.168.1.22       4            5
192.168.1.33       4            5

其中,power-index(必须大于等于1)表示了这台机器的战斗力,值越高代表性能越强,分到的编译任务也越多。能者多劳嘛。

3,启动调度程序

命令为:

sudo service dmucs start

开发机

1,安装Distcc

当然啦,我们假设您的开发机上已经安装gcc了。

2,安装Dmucs

请参考上面的第5步。

3,应用DistccDmucs

应用DistccDmucs来编译代码有几种方法:

方法一:修改makefile中的CXX的值

makefile文件中的这一行

CXX = g++

改为

CXX = gethost distcc g++

然后运行make -j18即可。这里的18,为所有服务器的CPU Cores的数量乘以1.5。上面有3台服务器,每台有4核,因此这里设置为18

为了获得最优值,很可能需要反复实验、测试。这里的gethostDMUCS里的一个组件。

方法二:修改configure文件

如果您的makefile文件由automake产生,那么在运行./configure时得加上参数,变为:

./configure --CXX=gethost distcc g++

那么生成的makefile文件将自动使用DistccDmucs了。

附录:调度策略

根据文档Dmucs的调度策略是:

1,Dmucs会维护几个列表(原文为tier,表示等级、阶梯),每个列表对应一个power-index,具有相同power-index值的机器会在同一个列表中。因此,上面三台服务器,192.168.1.22192.168.1.33会在同一个列表里,192.168.1.11在一个列表里。

2,每次获得编译任务请求时,Dmucs会优先从高power-index对应的列表里随机选一台机器。

3,如果Dmucs获知某台机器的平均负载过高(回忆下,该信息是服务器上的loadavg进程发过来的),那么会把该机器放到低一级的power-index对应的列表里。例如,192.168.1.11会被“下放”到power-index5对应的列表里。

4,如果某台机器的平均负载过高超过五分钟,那么该机器会被暂时雪藏,不会给它分发编译任务,直到它的负载下降到正常水平。