设为首页 收藏本站
查看: 1212|回复: 0

[经验分享] 结合P2P软件使用Ansible分发大文件

[复制链接]

尚未签到

发表于 2018-7-30 08:56:01 | 显示全部楼层 |阅读模式
  一 应用场景描述
  现在我需要向50+数量的服务器分发Logstash新版本的rpm包,大概220MB左右,直接使用Ansible的copy命令进行传输,命令如下:
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秒以内就可以完成。
DSC0000.jpg       DSC0001.jpg


wget https://github.com/lg/murder/archive/master.zip -O murder.zip  
unzip murder.zip
  
cd 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
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
#! /bin/sh  
#
  
# Start/Stop murder-tracker
  
#
  
# chkconfig: 345 99 99
  
# description: murder-tracker
  
# processname: murder-tracker
  

  
if [ -f /etc/rc.d/init.d/functions ]; then
  
    . /etc/rc.d/init.d/functions
  
fi
  

  

  

  

  
name="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=murder
  

  

  
find_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 in
  
start)
  
        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=1
  
esac
  
exit 0
  根据自己情况修改相应的参数
  2.创建torrent文件
  
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播种需要分发的文件包
python murder_client.py seed  deploy.torrent deploy.tar.gz 172.28.2.200  最后一个参数是本机的IP地址
  4.从所有peers节点获取文件包
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
# ansible 172.168.2.171  -m service -a "name=murder-tracker state=started"  2.在seeder服务器上制作torrent文件并启动seeder
  seeder启动脚本/etc/init.d/murder-seeder
#! /bin/sh  
#
  
# Start/Stop murder-seeder
  
#
  
# chkconfig: 345 99 99
  
# description: murder-seeder
  
# processname: murder-seeder
  

  
if [ -f /etc/rc.d/init.d/functions ]; then
  
    . /etc/rc.d/init.d/functions
  
fi
  

  

  

  

  
name="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=murder
  

  

  
find_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 in
  
start)
  
        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=1
  
esac
  
exit 0
  启动脚本依赖一个配置文件seeder.conf
# cat /opt/app/murder/dist/seeder.conf  
deploy_file=/opt/data/murder/deploy.tar.gz
  
torrent_file=/opt/data/murder/deploy.torrent
  
tracker_ip=172.168.2.171:8998
  
local_ip=172.168.2.179
  将需要的分发的文件打包成deploy.tar.gz
  启动seeder
# ansible 172.168.2.179  -m service -a "name=murder-seeder state=started"  3.从seeder获取种子文件,然后分发到peers
# ansible 172.168.2.179  -m synchronize -a "mode=pull src=/opt/software/download/deploy.torrent dest=/opt/software/download"  调用synchronize模块,pull模式就是从远端获取文件到本地,默认是push模式,从本地推送文件到远端
  然后将种子文件分发出去
# ansible all  -m synchronize -a "src=/opt/software/download/deploy.torrent dest=/opt/software/download"  4.在各个peers端执行下载任务
# ansible all  -m shell -a "sh /opt/app/murder/dist/peer_download.sh"  peer_download.sh
#!/bin/bash  
#this file is used to download bt files
  
torrent_file=/opt/software/download/deploy.torrent
  
download_file=/opt/software/download/deploy.tar.gz
  
local_ip=$(hostname -I|awk '{print $1}')
  
murder_client_bin=/opt/app/murder/dist/murder_client.py
  

  
python  $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中定义有
  和端口相关的参数
('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/lg/murder
  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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-543352-1-1.html 上篇帖子: Ansible的几个基本语句 下篇帖子: ansible使用方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表