PHP 依赖镜像出问题后,阿里工程师的一顿“神操作“令人叫绝!

 阿里云安全     |      2019-12-25 00:00:00

作者 | 顾咏

一则消息

前段时间,因为国际网络不稳定问题,国内各大Composer镜像都出现了间歇性无法访问情况,这对国内PHPer的生产工作造成了极大的影响。受此影响,国内各家Composer服务都出现了相同的问题,而阿里工程师的这个解决方案堪称“简单粗暴”,效率高到没朋友!

阿里云的 PHP Composer 最初研发灵感源自阿里内部一位 90 后工程师顾咏。作为负责开发阿里云产品的 PHP SDK的工程师,他在工作中经常遇到同一个问题:尽管已经根据PHP 最新版本发布了新的 SDK,但由于镜像工具没有实时同步版本,导致用户安装不成功。 此外,云效平台企业开发者对镜像工具的使用体验,同样受到这个问题的困扰,为此,阿里技术团队一起设计开发并开源了这套阿里云版镜像工具。

此次国际网络不稳定导致的镜像问题,阿里工程师顾咏第一时间响应了PHPer的诉求,连夜排查问题。 “我们程序员都离不开这个,越早解决越好”,最后终于成功定位问题、完成系统更新,解决了大家的燃眉之急。群里的开发者主动发红包向其致谢,顾咏十分感动,然后拒绝了他:“应该做的,红包不能收。”

1201.jpg

对于PHP 开发者来说,Composer 是必不可少的依赖包管理工具,作为存储 Composer 依赖包的 Packagist,却时常因为网络问题让国内开发者头痛不已,国内开发者安装依赖通常很慢,或者超时导致无法安装,却又没有稳定的镜像服务可以使用。Packagist 鼓励开发者建立镜像,但目前的镜像也有诸多不稳定、不可靠的情况。

阿里云Composer 镜像的推出

今年七月,阿里云提供了 Packagist/Composer 全量镜像服务,其秒级同步的能力、快速稳定的下载服务、页面上的动态数据展示得到了开发者的一致好评。

1202.png

阿里云Composer 镜像的升级

11月16日开始,由于 Composer 镜像出现了间歇性无法访问情况,不少网友通过阿里云钉钉服务群反应阿里云镜像出现不可用的情况,主要 zlib_decode 和 404 错误。在测试其他镜像作对比时发现,其他镜像也存在此类情况。接到反馈后,我们第一时间进行问题排查:

问题定位:阿里工程师立即查看系统状态和日志,未发现异常。初步怀疑是由于 CDN 接入层收国际网络延迟导致不可用。

验证:阿里工程师笔将相同的数据回传至国内 Bucket ,在今经多次、多地域直接访问测试,均成功。

决心升级:以往偶尔遇到这种问题,都被当做正常现象对待,而此次持续时间较长,影响面广,为了彻底解决这类问题,阿里决定升级镜像系统部署方案,直接将最新数据传回国内。

已知现有 Packagist 镜像的问题

1)同步的数据不是 Packagist 的根数据。事实上,官方的根数据不对外公开,开发者平时所访问的数据是镜像,甚至是镜像的镜像。当客户端发起请求后,请求会被官方 DNS 指向其他的镜像站,这些镜像数据与根数据之间已经存在延迟。而由于国际网络或系统设计原因,曾经出现初次官方镜像站与根数据长达数小时不同步 的情况。

2)没有处理代码包 dist。大多数依赖包的源代码存储在在github、gitlab上,因为网络问题,也会导致使用者下载速度慢,甚至下载失败。这也是镜像站需要关注处理的,一般镜像只提供 meta 数据(包数据)。例如官方推荐的 Webysther's mirror code 镜像同步系统就不处理dist。

3)本地文件存储。目前已知的其他镜像系统,是将文件存储在本地,或至少先存储在本地再上传,这样不仅会消耗大量本地磁盘空间,还存在系统最大子目录限制,会使得系统存在致命瓶颈。优化版本使用的软连接方案也会随着包的无限增长需要重构。

4)单进程,性能表现不佳,消耗 CPU、内存资源大。且处理数据耗时长,更新速度慢,系统的设计导致任务不能分发,且同步时间间隔越长,同步的时间越常。

5)没有数据错误统计,官方源数据存在错误,也需要直观的展示,让开发者了解情况。

6)系统同步状态、数据不可视化,镜像是否已更新?什么时候更新?今天更新了多少?下一次什么时候更新?这些数据开发者都不知道。

阿里云镜像的优势

阿里云镜像的架构核心目标是实时、快读、稳定、可移植、可扩展,且具备对数据进行自我修复的能力。那么阿里云镜像和其他镜像有什么区别?阿里云镜像又是如何做到秒级同步的呢?

官方合作

在数据上,阿里云与 Packagist 官方合作,经过和 Packagist 沟通,阿里云在距离官方根数据最近的城市节点部署了服务器,同时阿里云的服务器 IP地址 被加入 Packagist 白名单,允许直接、频繁地访问其根数据(Meta)。获取和解析 Meta 后,系统从代码仓库中下载源代码压缩包,再通过阿里云洛神网络不限带宽的将数据传回国内,这从最大程度上保证了国内用户可以及时、快速地获取最新数据。开发者使用 Composer 安装依赖的数据,都是镜像,甚至是镜像的镜像。例如官方在新加坡的镜像,就数次出现长达数小时的不更新,以此为镜像源的镜像站就无法为开发者提供正常的服务。

实时

阿里云实时同步源数据,对于以下场景的用户具有十分重要的意义:

  1. 迫切需要更新补丁依赖包的使用者。当一个依赖包被发现有bug,得到修复后使用者往往需要第一时间升级更新,镜像同步的越及时、服务越稳定,使用者的补丁修复的也就越早,止损也就更及时。
  2. 检查依赖包发布状态的包开发者来说。对于包的开发者,在发布包后,能尽快的检查发布状态,通过安装命令验证其作品的可用性。

自主研发高性能系统

同步系统由阿里云自主研发,采用 Golang 编写,使用 Redis 做任务队列,心跳协程将更新的数据文件分发到任务队列,30个协程各自分工获取数据传回国内OSS。这意味着所要同步的数据不再是一个单进程按照顺序一个一个传输,而是多个协程,甚至是多台机上的多个协程一起分工,这又将同步时间大幅度缩短。

只分发有效任务

在任务分发的机制上,实现了任务不重复,由于内存会记录已经成功处理过的任务和已分发的任务,所以不会分发旧文件,也不会发布相同的任务,这避免无效、重复工作,更是大幅度的减少了工作量,降低延迟。

重试机制

对于数据获取错误的情况,系统具有重试机制,对于因为网络问题暂时访问错误的源数据、代码包,系统会重试请求。

文件存储

阿里云 Composer 全量镜像,依靠阿里云强大的 OSS 存储源数据和代码压缩包,不占用本地磁盘,在避免最大子目录的问题的同时,还能轻松移植、扩展系统。

错误记录

记录和统计官方错误,阿里云将官方记录当中的一些错误记录下来,在方便内部随时排查问题的同时,也能更准确的了解 Packagist 的情况。

自我修复

处理不成功的任务不会被记录,在间隔时间极短的下一次同步中会得到修复。而执行错误的任务则会使用重试修复。

如果需要人工修复,只需删除响应的 KEY,系统即可重新执行并更新状态。

CDN 支撑

镜像数据对外,接入了阿里云全国 CDN 节点,阿里云强大的网络基础设施保证了开发者如丝般顺滑的使用体验。

状态数据可视化

镜像系统数据状态可视,在阿里云 Composer 全量镜像的官方页面上,动态显示 Packagist 最后更新时间,阿里云同步耗时、下一次刷新 CDN 的时间,系统同步的状态和数据让开发者“心中有数”。

1203.jpg

免费全量镜像站,开发者的福音

阿里做镜像站的历史最早可追溯至2011年,从最开始阿里内部的需求,扩展到为更广大的开发者免费投入资源,提供更快、更稳定的镜像资源。从最初的几台设备,成长为现在覆盖主流语言和主流操作系统的全量镜像站。并且,在这个过程中,一直坚持免费为开发者提供镜像资源,不断追求更快、更稳定的服务。

目前阿里云镜像站不仅提供Centos、Ubuntu、 Fedora、Arch Linux、 Deepin 等10多个发行版的软件安装源和ISO下载服务, 还提供Python, Php 等多款开发语言的包管理镜像服务以及nvidia-cuda, homebrew, kubernetes等 10 多款垂直仓库的镜像服务。每月下载包文件数量已经超过 7 亿次。

国内镜像所做的是缓存所有安装包和元数据到自己的服务器,并通过国内 CDN 进行加速,实现 Composer require/install/update 的操作,并达到最快速度。阿里云的 PHP Composer 全量镜像能够实现与 PHP Packagist 官方实时同步,通过自研的镜像同步系统,实现多协程分工同步、数据自我修复的能力,在保证快速同步的同时,也能快速修复因网络不稳定造成的数据错误。