【IT168 技术】每年双十一,不仅是剁手族的狂欢节,更是各大电商技术团队技术水平与技术创新实践检验的舞台,不断创新高的销售额、交易峰值、支付峰值,这些惊人数字的背后都离不开强力的技术支撑。IT168希望通过技术报道的形式向读者揭秘各大电商平台在双十一这一“超级工程”背后的巨额投入与技术创新,让更多人了解技术,尊重技术,促进同行业之间的技术交流分享,推动提高行业整体技术水平。
本文摘要
2017天猫双11, 交易峰值达32.5万/秒,支付峰值25.6万/秒,数据库处理峰值4200万次/秒,成交额1682亿,这些数字的背后是阿里50多种神秘技术的支撑!其中,作为阿里集团基础设施的蜻蜓,双十一期间对上万台服务器同时下发5GB数据文件,让大规模文件分发这一关完美渡过。
蜻蜓,通过解决大规模文件下载以及跨网络隔离等场景下各种难题,大幅提高数据预热、大规模容器镜像分发等业务能力。月均分发次数突破20亿次,分发数据量3.4PB。其中,容器镜像分发比natvie方式提速高达57倍,registry网络出口流量降低99.5%以上。今天,阿里巴巴集团基础架构事业群运维中台负责人,亲历者如柏将为我们详述蜻蜓从文件分发到镜像传输的技术之路。
作者:毛茂德(花名:如柏)
▲阿里巴巴集团基础架构事业群运维中台负责人 毛茂德
编辑整理:赵钰莹
简介:阿里巴巴集团基础架构事业群运维中台负责人,亲历者。主导架构设计高可靠、高并发、大规模的基础运维平台和应用运维平台, 十余年来坚持不懈的追求研发、测试、运维效率提升,推动DevOps实施落地。目前正致力于打造基于混合云的应用运维无人值守解决方案以及自动化、数据化、智能化应用运维解决方案。曾任职于IONA,RedHat,eBay,也是 Apache 优异项目CXF 初创成员之一。
正文
蜻蜓是阿里自研P2P文件分发系统,是阿里基础运维平台的重要组成部分,是云效-智能运维平台的核心竞争力,也是阿里云容器服务的关键组件。
蜻蜓的诞生要从15年开始讲起......
问题起源
随着阿里业务的爆炸式增长,2015年时,发布系统日均发布量已突破两万,很多应用规模开始破万,发布失败率逐渐增高, 根本原因就是发布过程需要大量文件拉取,文件服务器扛不住大量请求。当然很容易想到的解决方案就是服务器扩容,可扩容后又发现后端存储成为瓶颈。此外, 大量来自不同IDC的客户端请求消耗了巨大网络带宽,造成网络拥堵。
同时,很多业务走向国际化,大量应用部署在海外,海外服务器下载要回源国内,浪费了大量国际带宽,而且速度很慢;如果传输大文件,网络环境差,失败的话又得重来一遍,效率极低。
于是很自然就想到了P2P技术,因为P2P技术并不新鲜, 当时也调研了很多国内外系统,调研的结论是这些系统的规模和稳定性都无法达到我们的期望,所以就有了蜻蜓的出现。
设计目标
针对这些痛点,蜻蜓在设计之初所定目标如下:
1. 解决文件源被打爆问题,在Host之间组P2P网,缓解文件服务器压力,节约跨IDC之间的网络带宽资源。
2. 加速文件分发速度,并且保证上万服务器同时下载跟一台服务器下载没有太大波动。
3. 解决跨国下载加速和带宽节约。
4. 解决大文件下载问题,同时必须要支持断点续传。
5. Host上的磁盘IO,网络IO必须可控,以避免对业务造成影响。
系统架构
▲蜻蜓整体架构
蜻蜓整体架构分三层:Config Service, 管理所有Cluster Manager;Cluster Manager管理所有Host;Host就是终端,dfget就是类似wget一样的客户端程序。
Config Service 主要负责Cluster Manager管理、客户端节点路由、系统配置管理以及预热服务等。简单来说, 就是负责告诉Host离它最近的一组Cluster Manager地址列表,并定期维护和更新列表,使Host总能找到离它最近的Cluster Manager。
Cluster Manager 主要职责有两个:一是以被动CDN方式从文件源下载文件并生成一组种子分块数据;二是构造P2P网络并调度每个peer之间互传指定的分块数据。
Host上就存放着dfget, dfget的语法与wget非常类似,主要功能包括文件下载和P2P共享等。
在阿里内部,我们可以用StarAgent来下发dfget指令让一组机器同时下载文件,在某种场景下一组机器可能就是阿里所有的服务器,所以使用起来非常高效。除了客户端, 蜻蜓还有Java SDK,可以让你将文件“PUSH”到一组服务器上。
下图阐述了两个终端同时调用dfget下载同一文件时的系统交互情况:
▲蜻蜓P2P组网逻辑示意图
两个Host和CM会组成一个P2P网络,首先CM会查看本地是否有缓存,如果没有,就回源下载,文件当然会被分片,CM会多线程下载分片, 同时将下载的分片提供给Host, Host下载完一个分片后, 同时会提供出来给peer下载,如此类推, 直到所有Host全部下载完成。
本地下载时会将下载分片的情况记录在metadata里, 如果突然中断下载,则将再次执行dfget命令, 断点续传。
下载结束后, 比对MD5以确保下载文件和源文件完全一致。蜻蜓通过HTTP cache协议控制CM端对文件的缓存时长,当然,CM端也有定期清理磁盘的能力, 确保有足够空间支撑长久服务。
在阿里,还有很多文件预热场景需要提前把文件推送到CM端, 包括容器镜像、索引文件、业务优化的cache文件等。
在第一版上线后,我们进行了一轮测试, 结果如下图:
▲传统下载和蜻蜓P2P下载测试结果对比图
X轴是客户端数量, Y轴是下载时长
文件源:测试目标文件200MB,(网卡:千兆bit/s)
Host端:百兆bit/s网卡
CM端:2台服务器(24核 64G,网卡:千兆bit/s)
从上图可看出两个问题:
1. 传统模式随客户端的增加, 下载时长也逐渐增加,而dfget可以支撑到7000客户端依然没变好
2. 传统模式到了1200客户端以后就没有数据了, 因为数据源被打爆了
每年双11之前都是发布高峰期, 15年双11就是靠蜻蜓完美渡过的。
从发布系统走向基础设施
自2015年双11后,蜻蜓的下载次数达到了12万/月,分发量4TB。当时的阿里还有其他下载工具,如wget, curl,scp, ftp 等,也有自建的小规模文件分发系统。我们除了全面覆盖自身发布系统外, 也做了小规模推广。2016年双11前后,蜻蜓的下载量已达1.4亿/月,分发量708TB。业务增长近千倍。
2016年双11后,我们提出了一个更高的目标, 我们希望阿里大规模文件分发和大文件分发90%的业务由蜻蜓承担,我们希望蜻蜓成为全集团的基础设施。
我希望通过这个目标锤炼出最好的P2P文件分发系统,此外也可以统一集团内所有文件分发系统。统一可以让更多用户受益,但统一从来不是终极目标, 统一的目的是:
1. 减少重复建设
2. 全局优化
只要优化蜻蜓一个系统, 全集团都能受益。比如,我们发现系统文件是每天全网分发的, 而光一个文件的压缩就能给公司每天节省9TB网络流量,跨国带宽资源尤其宝贵。如果大家各用各的分发系统, 类似这样的全局优化就无从谈起了。
所以,统一势在必行!
在大量数据分析的基础上,我们得出全集团文件分发量大概是3.5亿次/周, 而我们当时的占比只有10%不到。
经过半年努力,在17年4月份,我们终于实现了90%+的业务占有率。业务量增长到3亿次/周(跟我们之前分析的数据基本吻合),分发量977TB(这个数字比半年前一个月的量还大)。
当然这里不得不说跟阿里容器化也是密不可分的,镜像分发流量大约占了一半。下面我们就来介绍下蜻蜓是如何支持镜像分发的,在说镜像分发之前当然要先说下阿里的容器技术。
阿里容器技术
容器技术的优点自然不需要多介绍,全球来看, 容器技术以Docker为主占了大部分市场,当然除此之外还有其他解决方案,比如rkt,Mesos Uni Container, LXC等,而阿里的容器技术命名为Pouch。早在2011年,阿里就自主研发了基于LXC的容器技术T4,只是当时我们没有创造镜像这个概念, T4还是当做虚拟机来用, 当然比虚拟机要轻量的多。
2016年,阿里在T4基础上做了重大升级,演变为今天的Pouch,并且已经开源。目前Pouch容器技术已经覆盖阿里巴巴集团几乎所有的事业部,在线业务100%容器化,规模高达数十万。镜像技术的价值扩大了容器技术的应用边界,而在阿里如此庞大的应用场景下,如何实现高效“镜像分发”成为一个重大命题。
回到镜像层面。宏观上,阿里巴巴有规模庞大的容器应用场景;微观上,每个应用镜像在镜像化时,质量也存在参差不齐的情况。
理论上讲,用镜像或传统“基线”模式在应用大小上不应该有非常大的区别。但事实上,这完全取决于Dockerfile写的好坏,也取决于镜像分层是否合理。阿里内部其实有非常好的实践,但是每个团队理解接受程度不同, 肯定会有好坏之分。尤其在一开始, 大家打出来的镜像有3~4GB都是非常常见的。
所以,作为P2P文件分发系统,蜻蜓就有了用武之地,无论是多大的镜像, 无论是分发到多少机器, 即使你的镜像打的非常糟糕, 蜻蜓都可以提供非常高效的分发,都不会成瓶颈。这样就给我们快速推广容器技术,让大家接受容器运维模式,给予了充分的消化时间。
容器镜像
在讲镜像分发之前先简单介绍下容器镜像,我们先看下Ubuntu系统的镜像:我们可以通过命令 docker history ubuntu:14.04 查看 ubuntu:14.04,结果如下:
需要额外注意的是:镜像层 d2a0ecffe6fa 中没有任何内容,也就是所谓的空镜像。
镜像是分层的,每层都有自己的ID和尺寸,这里有4个Layer,最终这个镜像是由Layer组成。
Docker镜像通过Dockerfile来构建,一个简单的Dockerfile如下图所示:
镜像构建过程如下图所示:
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
当容器启动时,一个可写层会被加载到镜像的顶层,这个可读可写层也被称为“容器层”,容器层之下都是“镜像层”,都是只读的。
如果镜像层内容为空,相应的信息会在镜像json文件中描述,如果镜像层内容不为空,则会以文件形式存储在OSS中。
镜像分发
▲Docker 镜像下载流程图
以阿里云容器服务为例, 传统的镜像传输如上图所示,当然这是最简化的一种架构模式, 实际的部署情况会复杂的多, 还会考虑鉴权、安全、高可用等等。
从上图可以看出来,镜像传输跟文件分发有类似问题, 当有一万个Host同时向Registry请求时, Registry就会成为瓶颈,海外Host访问国内Registry时也会存在带宽浪费、延时变长、成功率下降等问题。
下面介绍下Docker Pull的执行过程:
▲Docker 镜像分层下载图
Docker Daemon调用Registry API得到镜像的Manifest,从Manifest中算出每层的URL,Daemon随后把所有镜像层从Registry并行下载到Host本地仓库。
最终,镜像传输问题变成了各镜像层文件并行下载的问题,而蜻蜓擅长的正是将每层镜像文件从Registry用P2P模式传输到本地仓库。
那么具体又是如何做到的呢?
事实上,我们会在Host上启动dfGet proxy,Docker/Pouch Engine的所有命令请求都会通过这个proxy,我们看下图:
▲蜻蜓P2P容器镜像分发示意图
首先,docker pull命令会被dfget proxy截获,由dfget proxy向CM发送调度请求,CM在收到请求后会检查对应的下载文件是否已被缓存到本地,如果没有被缓存,则会从Registry中下载对应的文件并生成种子分块数据(种子分块数据一旦生成就可以立即被使用),如果已经被缓存,则直接生成分块任务,请求者解析相应的分块任务并从其他peer或者supernode中下载分块数据,当某个Layer的所有分块下载完成后,一个Layer也就下载完毕了。同样,当所有Layer下载完成后,整个镜像也就下载完成。
蜻蜓支持容器镜像分发的设计目标如下:
1. 大规模并发:必须能支持十万级规模同时Pull镜像
2. 不侵入容器技术内核(Docker Daemon, Registry),也就是说不能改动容器服务任何代码。
3. 支持Docker, Pouch, Rocket ,Hyper等所有容器/虚拟机技术
4. 支持镜像预热(构建时就推送到蜻蜓集群CM)
5. 支持大镜像文件 (至少30GB)
6. 安全
Native Docker V.S 蜻蜓
我们一共做了两组实验:
实验一:1个客户端
1. 测试镜像大小:50MB、200MB、500MB、1GB、5GB
2. 镜像仓库带宽:15Gbps
3. 客户端带宽:双百兆bit/s网络环境
4. 测试规模:单次下载
▲单客户端不同模式对比图
Native和蜻蜓(关闭智能压缩特性)平均耗时基本接近,蜻蜓稍高一点,因为蜻蜓在下载过程中会校验每个分块数据的MD5值,下载之后会校验整个文件的MD5,以保证下载文件跟源文件一致;在开启的智能压缩模式下,其耗时比Native模式还低!
实验二:多客户端并发
1. 测试镜像大小:50MB、200MB、500MB、1GB、5GB
2. 镜像仓库带宽:15Gbps
3. 客户端带宽:双百兆bit/s网络环境
4. 多并发:10并发、200并发、1000并发
▲不同镜像大小和并发数的对比图
从上图可看出,随着下载规模的扩大,蜻蜓与Native模式耗时差异显著扩大,最高提速可达20倍。在测试环境中源的带宽也至关重要,如果源带宽是2Gbps,提速可达57倍。
下图是下载文件总流量(并发数 * 文件大小)和回源流量(去Registry下载的流量)的对比:
▲蜻蜓镜像分发出流量对比图
向200个节点分发500M镜像,比docker原生模式使用更低的网络流量。实验数据表明,采用蜻蜓后,Registry的出流量降低了99.5%以上;而在1000并发规模下,Registry的出流量更可以降低到99.9%左右。
在阿里的效果
蜻蜓在阿里已投入使用两年左右, 两年来业务发展迅速,从分发次数来统计,目前一个月接近20亿次,分发数据达3.4PB,其中,容器镜像的分发量接近一半。
▲蜻蜓在阿里文件vs镜像分发流量趋势图
在阿里,目前最大的一次分发应该是今年双11期间, 要对上万台服务器同时下发5GB数据文件。
走向智能化
阿里在AIOps起步虽然不是最早, 但近年来投入巨大,并在很多产品上有所应用。在蜻蜓产品中的有应用如下:
智能流控
流控在道路交通中很常见,比如中国道路限速规定,没有中心线的公路,限速为40公里/小时;同方向只有1条机动车道的公路,限速为70公里/小时;快速道路80公里;高速公路最高限速为120公里/小时等。这种限速对每辆车都一样,显然不够灵活,在道路非常空闲的情况下,道路资源其实是非常浪费的,整体效率低下。
红绿灯其实也是流控的一种手段,现在的红绿灯都是固定时间,不会根据现实流量智能判断,所以去年10月召开的云栖大会上,王坚博士曾感慨,世界上最遥远的距离不是从南极到北极,而是从红绿灯到交通摄像头,它们在同一根杆上,但从来没有通过数据被连接过,摄像头看到的东西永远不会变成红绿灯的行动。这既浪费了城市的数据资源,也加大了城市的运营发展成本。
蜻蜓其中一个参数就是控制磁盘和网络带宽利用率, 用户可以通过参数设定使用多少网络IO/磁盘IO。如上所述,这种方法是非常僵化的。所以目前阿里智能化方面的主要思想之一是希望类似的参数不再需要人为设定,而是根据业务情况,结合系统运行情况智能决定参数配置。一开始可能不是优秀的解决方案, 但是经过一段时间的运行和训练后可自动达到最优化状态。保证业务稳定运行同时又尽可能充分利用网络和磁盘带宽,避免资源浪费。
智能调度
分块任务调度是决定整个文件分发效率高低与否的关键因素,如果只是通过简单的调度策略,比如随机调度或者其他固定优先级调度,这种做法往往会引起下载速率的频繁抖动,很容易导致下载毛刺过多,同时整体下载效率也会很差;为了最优化任务调度,我们经历了无数次的尝试和探索,最终通过多维度(比如机器硬件配置、地理位置、网络环境、历史下载结果和速率等维度)的数据分析(主要利用了梯度下降算法,后续还会尝试其他算法)智能动态决定当前请求者最优的后续分块任务列表。
智能压缩
智能压缩会对文件中最值得压缩的部分实施相应的压缩策略,从而节约大量网络带宽资源。
对容器镜像目前的实际平均数据来说,压缩率(Compression Ration) 是40%,也就是说100MB镜像可以压缩到40MB。针对1000并发规模,通过智能压缩可以减少60%的流量。
安全
在下载某些敏感文件(比如秘钥文件或者账号数据文件等)时,传输的安全性必须要得到有效保证,在这方面,蜻蜓主要做了两个工作:
1、支持携带HTTP的Header数据,以满足那些需要通过header进行权限验证的文件源;
2、利用对称加密算法,对文件内容进行传输加密。
开源
随着容器技术的流行,容器镜像这类大文件分发成为一个重要问题,为了更好的支持容器技术的发展,以及数据中心大规模文件的分发,阿里决定开源蜻蜓来更好推进技术发展。阿里将持续支持开源社区,并把自己经过实战检验的技术贡献给社区,敬请期待。
商业化
蜻蜓除了用于阿里集团内部容器化,也完全兼容社区版Docker,可以和[阿里云容器服务](https://www.aliyun.com/product/containerservice),飞天专有云敏捷版(https://yq.aliyun.com/articles/224507)无缝结合,在公共云和专有云环境下支撑大规模容器镜像分发。
总结
蜻蜓使用P2P技术的同时结合智能压缩、智能流控等多种创新技术,解决大规模文件下载以及跨网络隔离等场景下的各种文件分发难题,大幅提高数据预热、大规模容器镜像分发等业务能力。
蜻蜓支持多种容器技术,对容器本身无需做任何改造,镜像分发比natvie方式提速高达57倍,Registry网络出流量降低99.5%以上。承载着PB级流量的蜻蜓,在阿里已然成为重要的基础设施之一,为业务的极速扩张和双11大促保驾护航。