结合P2P软件使用Ansible分发大文件
一 应用场景描述
现在我需要向50+数量的服务器分发Logstash新版本的rpm包,大概220MB左右,直接使用Ansible的copy命令进行传输,命令如下:
|
1
|
ansible all -m copy -a "src=/opt/software/logstash/logstash-agent-2.3.3-fb.centos6.x86_64.rpm dest=/opt/software/logstash" |
在执行的过程中,很快就收到Zabbix网络监控的报警,报警项目就是瞬间流量变化大于5Mbps。同时,有的服务器很快执行完成,有很多出现ssh连接错误,Ansible卡死。
开启Ansible的pipelining功能依然卡在ssh连接上。分发文件失败!!
所以,使用Ansible来分发执行命令很快速,但是如果直接使用Ansible来处理稍微大一点的文件分发就是一个很大的问题,即使耗费点时间可以忍受,但是单个分发点的带宽也会直接影响分发效率。
对于大文件分发,首先想到的就是BitTorrent,利用P2P协议实现快速分发,节省带宽,提高效率。
二 P2P软件介绍
这里我们使用Twitter开源的murder。Twitter用它来分发大文件完成代码更新。在早期,Twitter为每天向上万太台的服务器发布代码而头疼,从中央代码服务器向其他成千上万的节点分发代码存在很大瓶颈,因为分发代码的执行时间与需要更新代码的节点成线性关系,节点越多,分发时间越长。为了解决这个问题,Twitter抛弃了以往的集中式架构,转向分布式架构,取名叫murder。使用murder后,他们以前需要40~60分钟的代码发布任务,现在12秒以内就可以完成。


|
1
2
3
|
wget https://github.com/lg/murder/archive/master.zip -O murder.zipunzip murder.zipcd murder-master |
muder是基于BitTornado来实现的。主要有以下几个组件:
torrent tracker
tracker使用murder_tracker.py运行,tracker实际上就是运行在一台服务器上的单个服务,其他任何成员都要依赖这个tracker。tracker-less disctribution(DHT)目前不支持。tracker存放BitTorrent客户端需要更新状态的路径。
seeder
seeder就是存放需要向其他主机分发的文件的服务器。这些文件存放在seeder的一个目录,torrent根据这个目录创建。Murder会将这个目录打包成tgz格式,然后创建一个.torrent文件,这个文件很小,只存放关于这个tgz文件的基本哈希信息。这个.torrent文件让各个peers节点知道他们下载的是什么文件。同时,tracker会保持跟踪有哪些 .torrent文件正在被分发。一旦Murder开始传输文件,seeder服务器是众多主机首先获取文件碎片的地方。
peers
peers就是成百上千需要接收文件的服务器,并且在它们之间可以相互传输文件。一旦一个peer节点下载整个tgz文件完成,它将继续seeding一段时间防止蜜罐效应。
命令行使用murder
1.开启tracker
|
1
|
python murder_tracker.py |
muder_tracker.py实际上调用的这个文件BitTornado/BT1/track.py
track.py有很多参数,如果需要添加参数可以修改muder_tracker.py
几个重要的参数
--port tracker监听的端口,默认是8998
--dfile 存储近期下载信息的文件
--logfile tracker日志文件,默认是标准输出
为tracker添加启动脚本/etc/init.d/murder-tracker
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#! /bin/sh## Start/Stop murder-tracker## chkconfig: 345 99 99# description: murder-tracker# processname: murder-trackerif [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functionsfiname="murder-tracker"murder_tracker_bin="/opt/app/murder/dist/murder_tracker.py"murder_tracker_log="/opt/logs/murder/murder_tracker.log"murder_tracker_data="/opt/data/murder/tracker_data"murder_user=murderfind_tracker_process () { PID=`ps -ef | grep murder_tracker | grep python |grep -v $0|grep -v grep|grep -v sh|grep -v root| awk '{ print $2 }'`}start () { getent passwd $murder_user >/dev/null || useradd -r -s /sbin/nologin $murder_user LOG_DIR=`dirname ${murder_tracker_log}` DATA_DIR=`dirname ${murder_tracker_data}` if [ ! -d $LOG_DIR ]; then echo -e "\e[35mLog dir ${LOG_DIR} doesn't exist. Creating\e[0m" mkdir -p $LOG_DIR fi if [ ! -d $DATA_DIR ]; then echo -e "\e[35mLog dir ${DATA_DIR} doesn't exist. Creating\e[0m" mkdir -p $DATA_DIR fi chown -R $murder_user:$murder_user $DATA_DIR $LOG_DIR find_tracker_process if [ "$PID" != "" ]; then echo -e "\e[35m$name is already running!\e[0m" else daemon --user $murder_user nohup python $murder_tracker_bin > /dev/null 2>&1 & echo -e "\e[35mStarting $name Done\e[0m" fi}stop () { find_tracker_process if [ "$PID" != "" ]; then echo -e "\e[35mStopping $name\e[0m" kill $PID else echo -e "\e[35m$name is not running yet\e[0m" fi}case $1 instart) start ;;stop) stop exit 0 ;;reload) stop sleep 2 start ;;restart) stop sleep 2 start ;;status) find_tracker_process if [ "$PID" != "" ]; then echo -e "\e[35m$name is running: $PID\e[0m" exit 0 else echo -e "\e[35m$name is not running\e[0m" exit 1 fi ;;*) echo -e "\e[35mUsage: $0 {start|stop|restart|reload|status|configtest}\e[0m" RETVAL=1esacexit 0 |
根据自己情况修改相应的参数
2.创建torrent文件
|
1
|
python murder_make_torrent.py deploy.tar.gz tracker.twitter.com:8998 deploy.torrent |
murder_make_torrent.py文件实际上调用的 BitTornado的makemetafile.py 文件
3.Seed the package播种需要分发的文件包
|
1
|
python murder_client.py seed deploy.torrent deploy.tar.gz 172.28.2.200 |
最后一个参数是本机的IP地址
4.从所有peers节点获取文件包
|
1
|
python murder_client.py peer deploy.torrent deploy.tar.gz 172.28.2.220 |
三 使用Ansible执行分发命令
tracker 172.168.2.171
seeder 172.168.2.179
peers 172.168.2.180~200
murder执行文件目录 /opt/app/murder
tracker和seeder的murder数据目录 /opt/data/murder
peers下载目录 /opt/software/download/
1.在tracker服务器上启动tracker
|
1
|
# ansible 172.168.2.171 -m service -a "name=murder-tracker state=started" |
2.在seeder服务器上制作torrent文件并启动seeder
seeder启动脚本/etc/init.d/murder-seeder
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#! /bin/sh## Start/Stop murder-seeder## chkconfig: 345 99 99# description: murder-seeder# processname: murder-seederif [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functionsfiname="murder-seeder"murder_seeder_data="/opt/data/murder"murder_seeder_log="/opt/logs/murder/murder_seeder.log"murder_seeder_bin="/opt/app/murder/dist/murder_client.py"murder_make_torrent_bin="/opt/app/murder/dist/murder_make_torrent.py"murder_seeder_conf="/opt/app/murder/dist/seeder.conf"deploy_file=$(awk -F= '/deploy_file/{print $2}' /opt/app/murder/dist/seeder.conf)torrent_file=$(awk -F= '/torrent_file/{print $2}' /opt/app/murder/dist/seeder.conf)tracker_ip=$(awk -F= '/tracker_ip/{print $2}' /opt/app/murder/dist/seeder.conf)local_ip=$(awk -F= '/local_ip/{print $2}' /opt/app/murder/dist/seeder.conf)murder_user=murderfind_seeder_process () { PID=`ps -ef | grep murder_client|grep seed | grep python |grep -v $0|grep -v grep| awk '{ print $2 }'` #PID=`ps -ef | grep murder_client|grep seed | grep python |grep -v $0|grep -v grep|grep -v sh|grep -v root| awk '{ print $2 }'`}start () { getent passwd $murder_user >/dev/null || useradd -r -s /sbin/nologin $murder_user LOG_DIR=`dirname ${murder_seeder_log}` DATA_DIR=${murder_seeder_data} if [ ! -d $LOG_DIR ]; then echo -e "\e[35mLog dir ${LOG_DIR} doesn't exist. Creating\e[0m" mkdir -p $LOG_DIR fi if [ ! -d $DATA_DIR ]; then echo -e "\e[35mLog dir ${DATA_DIR} doesn't exist. Creating\e[0m" mkdir -p $DATA_DIR fi ####### make torrent python $murder_make_torrent_bin $deploy_file $tracker_ip $torrent_file ####### chown -R $murder_user:$murder_user $DATA_DIR $LOG_DIR find_seeder_process if [ "$PID" != "" ]; then echo -e "\e[35m$name is already running!\e[0m" else nohup python $murder_seeder_bin seed $torrent_file $deploy_file $local_ip > $murder_seeder_log 2>&1 & #daemon --user $murder_user nohup python $murder_seeder_bin seed $torrent_file $deploy_file $local_ip > $murder_seeder_log 2>&1 & echo -e "\e[35mStarting $name Done\e[0m" fi}stop () { find_seeder_process if [ "$PID" != "" ]; then echo -e "\e[35mStopping $name\e[0m" kill $PID else echo -e "\e[35m$name is not running yet\e[0m" fi}case $1 instart) start ;;stop) stop exit 0 ;;reload) stop sleep 2 start ;;restart) stop sleep 2 start ;;status) find_seeder_process if [ "$PID" != "" ]; then echo -e "\e[35m$name is running: $PID\e[0m" exit 0 else echo -e "\e[35m$name is not running\e[0m" exit 1 fi ;;*) echo -e "\e[35mUsage: $0 {start|stop|restart|reload|status|configtest}\e[0m" RETVAL=1esacexit 0 |
启动脚本依赖一个配置文件seeder.conf
|
1
2
3
4
5
|
# cat /opt/app/murder/dist/seeder.conf deploy_file=/opt/data/murder/deploy.tar.gztorrent_file=/opt/data/murder/deploy.torrenttracker_ip=172.168.2.171:8998local_ip=172.168.2.179 |
将需要的分发的文件打包成deploy.tar.gz
启动seeder
|
1
|
# ansible 172.168.2.179 -m service -a "name=murder-seeder state=started" |
3.从seeder获取种子文件,然后分发到peers
|
1
|
# ansible 172.168.2.179 -m synchronize -a "mode=pull src=/opt/software/download/deploy.torrent dest=/opt/software/download" |
调用synchronize模块,pull模式就是从远端获取文件到本地,默认是push模式,从本地推送文件到远端
然后将种子文件分发出去
|
1
|
# ansible all -m synchronize -a "src=/opt/software/download/deploy.torrent dest=/opt/software/download" |
4.在各个peers端执行下载任务
|
1
|
# ansible all -m shell -a "sh /opt/app/murder/dist/peer_download.sh" |
peer_download.sh
|
1
2
3
4
5
6
7
8
|
#!/bin/bash#this file is used to download bt filestorrent_file=/opt/software/download/deploy.torrentdownload_file=/opt/software/download/deploy.tar.gzlocal_ip=$(hostname -I|awk '{print $1}')murder_client_bin=/opt/app/murder/dist/murder_client.pypython $murder_client_bin peer $torrent_file $download_file $local_ip |
分发完成
可以将这些步骤写成Ansible playbooks
需要注意一下:
我需要分发的服务器是外网服务器,每台服务器开启了iptables防火墙。总共有60多台服务器同时下载220M左右的压缩包总共花了约20多分钟时间。这个时间有点怀疑,通过再次了解BT原理和查看源代码发现是防火墙设置的问题。BT下载之所以是下载点越多,下载速度越快,是因为各个下载点之间可以交换数据,也就是说需要开启TCP端口用于BT下载。这点在murder的文档中是没有说明的,twitter默认是每台服务器都关闭防火墙,并且是处于一个数据中心的彼此相互信任的内网服务器。murder封装的是BTTornado,代码中默认是启动一个10000~60000范围的随机端口,每个murder
peer在下载的同时向其他peers提供下载服务就是通过这个随机端口,如果防火墙全部关闭,这个不成问题,但是如果开启了防火墙这么大的端口范围肯定不行的,就需要自己设置一个防火墙允许的范围。
如果不开端口也是可以上传数据的,但是会影响下载速度,因为其他peer端无法连接到彼此。


有关下载的参数在BitTornado/download_bt1.py中定义有
和端口相关的参数
|
1
2
3
4
|
('minport', 10000, 'minimum port to listen on, counts up if unavailable'),('maxport', 60000, 'maximum port to listen on'),('random_port', 1, 'whether to choose randomly inside the port range ' + 'instead of counting up linearly'), |
这个范围太大,根据自己情况设置小一点,然后让防火墙通行
参考文档:
http://blogs.cornell.edu/info4220/2013/04/05/murder-distributed-large-scale-code-deployment/
http://www.royans.net/wp/tag/tools/
https://github.com/effigies/BitTornado
https://github.com/russss/Herd
https://github.com/masahide/ansible-lssd
http://www.361way.com/python-p2p/4737.html
http://bt.degreez.net/firewalled.html
结合P2P软件使用Ansible分发大文件的更多相关文章
- python BitTornado P2P分发大文件
P2P分发大文件思路 1.将软件包生成种子文件 2.通过saltstack将种子文件分发至每台服务器 3.每台服务器进行种子下载 推荐使用Twitter开源的murder.Twitter用它来分发大文 ...
- p2p软件如何穿透内网进行通信
http://blog.chinaunix.net/uid-22326462-id-1775108.html 首先先介绍一些基本概念: NAT(Network Address Translators) ...
- 推荐一个大文件查找工具---WizTree
DB备份.dump.电影等文件多了以后,经常遇到磁盘空间不够用的情况,日积月累本来清晰的目录结构找起来也很费劲,尤其是要查找删除无用的大文件.windows本身那差劲的搜索功能就不提了,从搜索引擎上查 ...
- U盘无法拷贝超过4G的大文件
现在U盘的容量越来越大了,8G闪存满天飞,几乎已成“标配”,市面上再见难觅64M.128M等U盘的踪迹,可是细心的你也许已经发现,即使是8G或更大体积的U盘,仍然不能拷贝存储体积超过4G的大文件,这是 ...
- 网络打洞(P2P软件穿透内网进行通信) 原理
http://www.cnblogs.com/gansc23/archive/2010/10/20/1857066.html 首先先介绍一些基本概念:NAT(Network Address Trans ...
- 【原创】用JAVA实现大文件上传及显示进度信息
用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/grayprince/UploadBigFil ...
- 在ASP.NET中支持断点续传下载大文件(ZT)
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交 ...
- QQ上传大文件为什么这么快
今天和同事在群里讨论“QQ上传大文件/QQ群发送大文件时,可以在极短的时间内完成”是如何做到的. 有时候我们通过QQ上传一个几百M的文件,竟然只用了几秒钟,从带宽上限制可以得出,实际上传文件是不可能的 ...
- Html5大文件断点续传
大文件分块 一般常用的web服务器都有对向服务器端提交数据有大小限制.超过一定大小文件服务器端将返回拒绝信息.当然,web服务器都提供了配置文件可能修改限制的大小.针对iis实现大文件的上传网上也 ...
随机推荐
- 在django restful framework中设置django model的property
众所周知,在django的model中,可以某些字段设置@property和setter deleter getter,这样就可以在存入数据的时候进行一些操作,具体原理请参见廖雪峰大神的博客https ...
- HDU 4587 TWO NODES(割两个点的最大连通分支数)
http://acm.hdu.edu.cn/showproblem.php?pid=4587 题意: 给一图,求割去两个点后所能形成的最大连通分支数. 思路: 对于这种情况,第一个只能枚举,然后在删除 ...
- 机器学习-数据可视化神器matplotlib学习之路(四)
今天画一下3D图像,首先的另外引用一个包 from mpl_toolkits.mplot3d import Axes3D,接下来画一个球体,首先来看看球体的参数方程吧 (0≤θ≤2π,0≤φ≤π) 然 ...
- Android本地广播
Android中使用的广播一般是系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播.这样就很容易会引起安全性的问题,比如说我们发送的一些携带关键性数 ...
- async 和 await的前世今生 (转载)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- jQuery双击编辑td数据
html <td class="remark" style="width: 200px;"> {$vo.remark} </td> js ...
- [原][osg][gdal]两种方式修改tiff高程
因为对于globalmap不熟悉,不怎么怎么修改高程,好像也没有这功能. 干脆自己手动修改了高程图tiff了 由于自身一直使用osg的 自己使用了osgDB直接读取tiff,修改后保存的. 同事小周一 ...
- MSSQL 一坑 SQL Management Studio 管理工具的快捷方式被删掉了
如果确定已经安装的情况下,到这里去找下吧(我这里用的是sql 2008) C:\Program Files\Microsoft SQL Server\100\Tools\Binn\VSShell\Co ...
- mycat分布式mysql中间件(自增主键)
一.全局序列号 全局序列号是MyCAT提供的一个新功能,为了实现分库分表情况下,表的主键是全局唯一,而默认的MySQL的自增长主键无法满足这个要求.全局序列号的语法符合标准SQL规范,其格式为:nex ...
- LeetCode--219--存在重复元素2
问题描述: 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k. 示例 1: 输入: ...