[help wanted] 检测镜像站延迟的自动化工具

我可能自己没有精力去做这个,所以把想法放在这里,难度不会特别大,如果有感兴趣的同学可以拿去做,如果需要指导也可以找我,也算是一个比较好的学习和使用 Julia 的机会。(当然整个工作是完全可以脱离 Julia 来做的)

Julia PkgServer 镜像服务及镜像站索引 里面可以找到一系列的镜像站可以使用,除去不同服务器本身的带宽和网络资源以外,其实还存在一个比较值得注意的问题:同步延迟。因为存储服务器和镜像站的存在,一个包的新版本从发布到被用户获得,在有些时候可能会有一个一到两天甚至更久的延迟。

背景知识

一个包从源代码到发布再到我们从镜像站下载安装,其中经过了大概这么几个步骤:

  1. 利用 Julia registrator 来将当前代码版本注册到公共的包注册表 General 中。
  2. 目前上游为 JuliaHub 提供的两个存储服务器,他们有一个 while true 循环来持续监测 General 的状态,并且以增量的形式下载数据,打包,并且归档。
  3. 国内的镜像站大概以1-2个小时的频率从上游的 JuliaHub 存储服务器中拉取数据。
  4. 用户通过 pkg> add xxx 的方式进行安装

关于延迟的分析:

  • 基本上我们可以假定 GitHub 的 CDN 网络足够可靠,一旦 General 里有一条新的记录(commit),那么就可以立刻获取到。所以可以假定第一步里面不存在延迟。(偶尔会存在一到两分钟的延迟,但是这属于不被感知的部分)
  • 上游存储服务器的下载,打包和归档环节:根据每次 General 的记录不同,延迟有有可能会是几分钟到几个小时不等,也遇到过几天的情况。
  • 国内镜像站:国内的镜像站主要是高校的学生团体维护的,大体来说是可用的,但是也难免会出现这样或者那样的运维问题。有些镜像脚本可能几个月不工作了也没有人注意到也是有可能的。

存储服务器本身有一份 General 注册表的归档,这份归档只在当前迭代的打包环节进行完之后才会更新,而用户通过 Pkg 更新包注册表的时候,是直接从存储服务器(或者镜像站)进行下载的。也就是说上面的每一个环节的延迟都会累加起来并最终影响到 Julia 的用户体验。例如,下面是一些关于镜像延迟的 issue:

绕过延迟的方式有两种:

  1. 将环境变量重置直接关闭 Pkg Server 功能:ENV["JULIA_PKG_SERVER"] = ""
  2. 因为影响用户体验的延迟的关键在于 General 注册表没有被更新,所以可以通过 git 协议直接从 GitHub 获取 General 注册表,而不是从 JuliaHub 的存储服务器或者国内镜像站来获取。这时 pkg> add xxx 的时候会试图去下载最新版本,但是由于存储服务器的打包并没有进行完,因此可能会出现下载失败,然后 fallback 到 GitHub。

想法

虽然存在绕过延迟的方式,但是这些相对来说都不够自动化,需要用户来交叉检查不同的 General 版本才能确认问题的原因是由于镜像延迟导致的。我的想法是:

  1. 提供一个延迟监测的脚本,放在 JuliaCN 或者 JuliaHub 的服务器上不断执行,并给出类似于 https://status.julialang.org/ 的状态监控页面
  2. 暴露一个 REST API 来直接查询镜像站的延迟状态
  3. 我之前写的 PkgServerClient.jl 会根据 ping 延迟来自动切换到最近的镜像站,但是这还不够可靠,因为有可能会切换到一个过期的镜像站。所以可以通过前面提供的镜像延迟信息来滤掉一些过期镜像站,来保证用户的体验。

成果:

  1. 一个监控脚本及对应的监控页面,部署到 JuliaCN 或者 JuliaHub
  2. 改进 JuliaPkgClient 来让它选择的镜像站一直是可靠的

思路和可能的解决方案

  1. 查询并生成信息

这是我早期写的一个监测脚本,背后的原理非常简单:

  • 每一个 Git commit 都有一个时间戳,将 General 仓库 clone 下来,然后查询每一个 commit 的时间戳,作为基准
  • 获取镜像站的当前提供的 General 版本,它记录在 /registries 里面,例如 https://mirrors.bfsu.edu.cn/julia/registries 打开之后类似于下面这种:
/registry/23338594-aafe-5451-b93e-139f81909106/28ca26a6ab4833de11f3a8fa83ededc8d1febd6e

它对应的格式是 /registry/<UUID>/<SHA>

其中 UUID 表明这个注册表的身份是 General,原始记录在 Registry.toml 可以找到,而 SHA 的话则是当前版本的 hash 值,可以通过 git rev-parse 来得到。

  1. 将信息记录到数据库中,因为数据量很小,所以对于数据库的选择没有什么要求。
  2. 根据数据库的信息,生成对应的图表。大概类似于 BFSU mirror server status 这种。
  3. 提供一个简单的 HTTP server 来响应延迟查询的请求,如果选择用 Julia 的话,这个可以参考 Pkg Server 的实现
  4. 包装成 Docker,然后部署到 JuliaCN 的服务器上,并试图与 JuliaHub 沟通,部署到 status.julialang.org