404 出现的问题一般都是因为仓库处于同步的过程中.此时 dists目录已经同步成功了,但pools目录因为内容太多导致更新缓慢.
每次同步都导致用户处于一个不可用状态. 这种不稳定状态普遍在小时级别.
各个地区以及网络情况都不同,在目前大环境下,社区提供的镜像源还是必不可少的. 但部分镜像源的同步周期是不确定的.更有些国外镜像源因为同步官方源速度实在 太慢,导致长期处于不稳定以及过期状态.
如果镜像源被黑或者当机,那么官方源无法做任何处理.用户处于无法 安装软件的状态.另外还有一个潜在风险: 内容被恶意修改.挨个通知用户 修改镜像源的效率和效果都非常差.
在保留镜像源的优势下,100%保证用户看到的数据与官方源一致,完全规避了 镜像源的劣势.
用户要下载的某个数据,如果其在镜像源中与官方源一致则采用镜像源的数据. 否则采用官方源的数据.
扩展来解释
- dists目录下的Release文件只会从官方源下载(10KB以内), 所有其他数据(包括lists文件) 优先 从镜像源下载.
- 以下情况会导致数据从官方源下载
- 镜像源中某个deb版本与官方源不一致
- 镜像源中的Packages(lists)文件与官方源不一致
- 镜像源直接服务器挂了
- 镜像源下载的deb的hash检验失败 (当前版本0.9未处理此种情况,不会fallback到官方源)
- /etc/apt/sources.list永远不会变动,只会是packages.deepin.com/deepin
因为要支持这种动态选择只能通过修改apt的逻辑进行.但为了尽量减少对apt的影响所以采取 对apt进行最小patch配合外部程序进行实际逻辑处理的方式.
目前对apt的修改在 ./smartmirror.patch
实际逻辑处理是由本项目的lastore-smartmirror提供的.
核心逻辑如下
- 对apt的pkgAcquire::Worker::QueueItem中的Item.URI U0进行hook
- 根据/etc/apt.conf.d/99lastore.conf的内容获得当前官方源地址U1以及用户期望的镜像源地址U2
- 将U0 U1 U2 传递给lastore-smartmirror,同时向U1, U2发送一个HEAD/GET的请求.然后判断最终的URI
- 将最终的URI返回给apt, 之后逻辑与正常情况相同
补充
- 因为不是所有服务器都支持HEAD方法,所以只有官方源使用HEAD. 其他源使用GET并在获取Header后 立刻断开connection
- lastore-smartmirror会判断U0是否是支持镜像源的,比如U0是一个ppa里面的deb那么就不会进行后续判断了
- pools中因为deb的名称里包含版本等信息,可以简单的通过uri即可判断镜像源是否和官方源的版本一致.
- Packages文件因为名称上不包含版本等信息所以无法通过URI是否存在来判断内容是否与官方源一致,因此 开启了apt中最新的by-hash特性.这样Packages文件也会出现在一个以hash值为名称的文件中.
- 可以通过修改99lastore.conf以及99mirrors.conf文件调整行为.主要有3个参数
- Debug 开启后可以看到实际使用的下载地址. 但可能导致某些依赖apt-get输出的程序失败.
- Enable 若关闭,则和正常apt行为一致.
- MirrorSource 用户期望的镜像源地址
所有配置信息都可以通过apt-config dump Acquire::SmartMirrors查询到, 通过-o key=value方式针对单个apt命令进行调整
官方源在更新仓库的时候先将所有数据同步到一个独立的目录下,然后直接rename到 提供仓库数据的目录去. 从而让用户完全感受不到官方源的更新过程.
补充
- 若用户正在下载,按目前的方式会导致下载中断.(但之前的方式也会)
- 镜像源的内容虽然官方无法要求按照此方式进行,但因为SmartMirrors的缘故,所以 当镜像源的某个deb失效时会直接fallback到官方源.
- 配合仓库根目录下的特殊文件,快速判断是否需要自动执行apt-get update
- 针对不同镜像源,采用时间差的方式,缓解官方源更新时的压力.可以从两方面入手
- 客户端检测的时候打时间差,不是所有客户端看到更新就立刻提示有更新.
- 针对镜像源的地理位置等信息,将更新信息分批告知出去.(可以通过不同IP不同内容的形式)