ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Yocto下载慢怎么办?清华镜像与PREMIRRORS双管齐下加速构建

Yocto下载慢怎么办?清华镜像与PREMIRRORS双管齐下加速构建 1. 为什么Yocto构建会卡在下载上1.1 你以为是编译慢其实大部分时间在下载很多第一次接触Yocto的朋友都会有个误解以为构建一个嵌入式Linux系统最耗时的是编译环节。实际跑过一次bitbake之后你会发现真正让人抓狂的往往不是CPU在干活而是网络在那干等。Yocto的本质是“下载源码打补丁配置编译打包”的全链路构建系统。它要处理的不只是kernel和busybox还有几百个依赖包的源码包。每个包都得从上游Source Server拉取然后再做校验和验证。这些源码包分布在全世界各个托管站点上有的在SourceForge有的在GitHub有的在GNU的FTP服务器上。国内网络环境下这些站点的连接速度忽快忽慢有些甚至直接超时。我印象很深的一次构建一个包含Qt和Wayland的镜像总计要拉取大概2.6GB的源码。编译本身在我那台8核16线程的机器上大概花了一个半小时但下载却断断续续跑了近三个小时——中间还有两次因为某个包下载失败导致整个任务中断还得手动清掉临时文件重新来。所以做Yocto加速第一刀应该砍在网络下载环节而不是去折腾编译参数。编译阶段的优化空间其实很有限除非你上分布式编译或者高价硬件但下载环节的优化就立竿见影多了。1.2 下载慢的三个根源第一个根源是物理距离。Yocto默认的源码拉取源都在海外中国内地到这些服务器的链路延迟和带宽都不理想尤其是一些小型开源项目的托管站点服务器本身带宽就有限高峰期给你几十KB/s都很正常。第二个根源是协议问题。Yocto源码拉取用的协议五花八门git://、http://、https://、ftp://都有涉及。git协议在国内网络环境下经常被限速http协议有时候连接不稳定ftp更不用说了。协议不同实际体验差距很大。第三个根源是缺乏缓存机制。Yocto的下载目录DL_DIR默认只做简单的本地缓存——同一个源码包的URL不变就不会重复下载。但问题是如果你把DL_DIR清了或者换了一台新机器所有源码包又得重新下载一遍。每次从头来一遍的痛苦体会过的都懂。明白了这些根源后面要做的优化思路就非常清晰了第一找离你近的镜像站做替代下载源第二用PREMIRRORS机制在不改动上游地址的前提下把下载请求拦截转发到镜像站第三把下载缓存合理地持久化避免重复劳动。这三个动作配合起来Yocto构建的下载环节能提速数倍而且配置一次就能长期生效。2. 清华镜像源配置基础加速动作2.1 配置前的准备工作动手之前先确认一下自己的环境。我这边用的是Ubuntu 22.04 Yocto Kirkstone4.0分支以下配置在Thud、Warrior、Hardknott等版本上也都验证过兼容性没什么问题。另外说一句很多人分不清“清华源”和“清华Anaconda源”其实清华大学TUNA镜像站mirrors.tuna.tsinghua.edu.cn收录了大量开源软件的镜像其中包括专门为Yocto准备的目录。我们需要关心的主要是两个子路径http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ —— 源码压缩包镜像http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ —— git仓库镜像这个后面在PREMIRRORS部分详细说注意清华的Yocto镜像不是所有上游资源都覆盖主要针对的是常见的开源包。哪些能覆盖哪些不能覆盖后面章节会专门说但先记住这个目录结构。开始配置前先确认两件事你的构建环境能正常访问外网。清华镜像本身只是替代下载源没法解决DNS解析和基本网络连通性的问题。你的Yocto版本能识别http协议的镜像源。老版本2.4以前的Yocto对http镜像支持得不太好建议至少用2.6以上的版本。2.2 local.conf中的核心配置项配置清华镜像源主要分两步第一步在conf/local.conf里指定下载镜像目录第二步让bitbake从这个镜像目录里拿东西。先看看最基础的配置方式。在build目录下的conf/local.conf文件末尾添加# 使用清华镜像作为源码包下载源 SOURCE_MIRROR_URL http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ INHERIT own-mirrors这两行的作用分开解释一下SOURCE_MIRROR_URL指定镜像服务器的根路径。bitbake的own-mirrors类会把这个地址作为所有源码包的下载源。INHERIT own-mirrors让bitbake启用“自定义镜像”功能。这个类的功能是告诉bitbake不要直接去各个上游站点拉包而是统一到SOURCE_MIRROR_URL指定的地址去拉。配置好之后DL_DIR里的旧文件可以留着也可以清掉重新来。如果是从零开始构建建议首次就配置好镜像源再跑这样能省下大量时间。有个细节值得注意SOURCE_MIRROR_URL的值不要加末尾多余的斜杠标准写法是上面的样子。有些人在地址后面习惯性补一个“/”倒不至于出错但保证格式统一总是好的。2.3 清华镜像和上游源的对比体验配置完镜像源后跑一次构建对比一下前后的速度差异感受会非常直观。我之前做过一次测试。同一个核心镜像目标core-image-minimal未配置镜像源时从零构建大约需要下载1.1GB的源码包耗时约40分钟这还是网络状况不错的时候。配置清华镜像后同样是这些源码包下载耗时压缩到了8分钟左右提速将近5倍。如果构建的目标更大比如带图形栈的镜像源码包总容量到3GB以上加速效果会成倍放大。不过清华的sources镜像也有覆盖不全的问题。试过一些不太常见的包比如某些冷门的Perl模块、小众的Python库镜像站上不一定有。遇到这种情况bitbake会按顺序继续尝试上游原始地址。这就是为什么官方文档里推荐“镜像优先、上游兜底”的策略而不是单纯依赖镜像。实测下来清华镜像对以下几个常见类目的覆盖率很高autotools类包的tar.gz源码包、kernel源码包、busybox、u-boot、大多数GNU工具链、常见的库文件如zlib、openssl、libpng、libjpeg等。覆盖率低的包括部分GitHub直连的release附件、一些需要从特定CDN获取的二进制包。这些包就得靠PREMIRRORS和后续的迂回策略来补充。3. PREMIRRORS机制让下载流程多一道“近路”3.1 PREMIRRORS的本质与原理解读PREMIRRORS是Yocto里一个非常强大但常常被忽略的机制。简单来说它就是一个下载前的URL重定向表让bitbake在去原始地址下载之前先尝试到你指定的镜像地址去拿。如果镜像地址没有再自动回退到原始地址。这么说可能还是有点抽象换个方式解释。平时从网上下载文件你可能习惯直接在浏览器地址栏输入URL。PREMIRRORS的作用就相当于你先去本地的代理服务器问了一句“这个文件你这儿有吗”有就直接给你没有你再自己去原始地址下载。对用户来说完全不用关心文件最终是从哪儿拿到的bitbake会自动处理。正因为有这个“命中就用不命中就回退”的兜底逻辑PREMIRRORS的安全性很高——它不会因为镜像源挂了就导致构建失败最差情况只是退回原来的慢速下载。这也是我倾向于把PREMIRRORS当作“主力加速方案”把清华sources只当作“补充方案”的原因。在local.conf中PREMIRRORS的典型写法如下PREMIRRORS:prepend \ git://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n \ http://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ https://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ 这几行配置的意思是以git://协议开头的URL转到清华的git2目录去查找以http://协议开头的URL转到清华的sources目录去查找以https://协议开头的URL同样转到sources目录去查找正则表达式里的.*是通配符前面一个git://.*/.*匹配上游URL的域名和路径后面一个http://...则是替换后的镜像URL。整个PREMIRRORS表按顺序匹配第一个配对的规则生效。3.2 PREMIRRORS的三种匹配写法PREMIRRORS的匹配语法除了上面那种通配写法还有几种不同的控制粒度我简单梳理一下。第一种是精确匹配。如果你只想让某个特定仓库走镜像其他仓库保持原样可以写成PREMIRRORS:prepend git://git.yoctoproject.org/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n这种写法在高精度控制场景下比较实用。比如你知道某个上游地址很容易超时其他地址倒还顺畅就可以单独给它配置镜像路径。第二种是协议匹配。Yocto的SRC_URI里协议五花八门有git、http、https、ftp、cvs、svn等你可以按协议批量处理。像前面写的http://.*/.*就是对所有http协议的URL生效。第三种是域名匹配。如果你只想让特定域名走镜像可以写成PREMIRRORS:prepend git://github.com/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n这种写法适合你知道瓶颈在某个特定站点的情况。实际使用中大部分人的需求都是“全量加速”所以建议直接用第一种全量配置就好。3.3 PREMIRRORS和own-mirrors的取舍这一点很多人会搞混我单独拿出来强调一下。own-mirrors和PREMIRRORS虽然都是加速下载的手段但工作方式不同own-mirrors强制所有下载都走SOURCE_MIRROR_URL指定的地址如果镜像里没有对应文件会直接报错除非额外配置FALLBACK机制。PREMIRRORS先尝试走镜像地址失败后自动回退到原始上游地址。整个流程对构建来说是透明的不会因为镜像缺失而中断。从稳定性角度讲PREMIRRORS的容错性明显更好。从速度角度讲own-mirrors的强制逻辑在某些场景下反而更“保险”因为所有包都走一个固定的镜像站DNS解析和TCP连接可以复用效率略高一点点。我的建议是如果追求极致的加速同时你能保证镜像站覆盖率高用own-mirrors也问题不大。如果想兼顾速度和稳定性用PREMIRRORS更稳妥。实际上最理想的组合是PREMIRRORS配置清华镜像优先同时用SOURCE_MIRROR_URL配置一个本地持久化缓存目录。这个组合方案在后面的实操部分会详细展开。4. 实操过程从零到完成配置4.1 六步完成核心配置下面按照我实际操作的完整流程走一遍你照着做就行。第一步进入构建目录我这里用的构建目录叫build你可以按自己的项目习惯来cd /path/to/your/yocto/build第二步编辑local.conf用你习惯的编辑器打开conf/local.confvim conf/local.conf在文件末尾追加以下内容# 下载加速配置 # 1. 配置PREMIRRORS优先走清华镜像 PREMIRRORS:prepend \ git://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n \ http://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ https://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ # 2. 配置own-mirrors指定统一镜像地址作为PREMIRRORS的补充 SOURCE_MIRROR_URL http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ INHERIT own-mirrors # 3. 持久化下载缓存目录避免每次清DL_DIR后重新下载 DL_DIR /opt/yocto-downloads第三步创建缓存目录sudo mkdir -p /opt/yocto-downloads sudo chown -R $USER:$USER /opt/yocto-downloads这个目录用来存所有下载过的源码包以后每次构建都能直接复用。相当于给Yocto增加了一个“离线包仓库”。第四步确认配置生效先跑一下bitbake的帮助命令看看有没有语法错误bitbake -e | grep -E PREMIRRORS|SOURCE_MIRROR_URL|DL_DIR正常输出里应该能看到你刚才配置的几个变量的值。如果看不到检查local.conf的拼写和格式。第五步清理历史缓存可选如果你之前构建到一半失败过DL_DIR里可能有损坏的临时文件。建议先清理一次bitbake -c cleanall 目标包名或者直接把整个DL_DIR清掉重新开始rm -rf /opt/yocto-downloads/*注意这个方法会清掉之前下载的源码包重新下载时会全量走镜像适合首次配置好加速方案后的一轮干净构建。第六步开始构建观察效果bitbake core-image-minimal第一次跑的时候重点观察一下fetch阶段的速度。如果PREMIRRORS生效了日志里会出现类似“trying http://mirrors.tuna.tsinghua.edu.cn/...”的记录。看到这个就说明配置已经生效了。4.2 三种配置组合场景的实战场景一单机开发环境网络一般。这个场景下推荐PREMIRRORS DL_DIR的组合PREMIRRORS:prepend \ git://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n \ http://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ https://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ DL_DIR /opt/yocto-downloads这个方案不需要own-mirrors把容错交给PREMIRRORS的自动回退机制。DL_DIR单独指定到一个持久化目录系统盘空间紧张时还可以把DL_DIR挂到机械硬盘或网络存储上。场景二CI服务器追求构建速度和稳定性。CI场景建议把own-mirrors也加上并增加一个提前预热下载缓存的步骤SOURCE_MIRROR_URL http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ INHERIT own-mirrors DL_DIR /opt/yocto-downloadsCI每天构建多次每次都从零下载源码是不可接受的。配置好DL_DIR后第一次完整构建会填充缓存后续构建的fetch阶段基本是秒过。就算某个包在镜像站没有首次构建失败后你也能从日志里快速定位到那个包再单独处理。场景三离线环境需要完全脱离外网。这个场景下PREMIRRORS和own-mirrors的方案都不够用需要先在有网络的机器上构建一次把DL_DIR完整的同步到离线机器上然后在离线机器的local.conf里设置SOURCE_MIRROR_URL file:///opt/yocto-downloads INHERIT own-mirrors这个方法用本地文件系统作为镜像源完全不需要外网。注意file://协议后面跟的是绝对路径不要漏掉协议头。离线构建时还需要把sstate-cache也同步过去否则每次都要重新编译几百个包比下载还痛苦。4.3 配置后首次构建的体验实录我之前在一台配置一般的笔记本上完整跑过一次core-image-sato带图形桌面的镜像整个流程我详细记录了一下。环境是Intel i5-8250U8GB内存256GB SSD网络是普通的家庭宽带。没有配置加速方案前fetch阶段总耗时约1小时20分钟其中还不包括几次因连接超时导致的重试。配置完PREMIRRORS 清华镜像后fetch阶段直接压缩到12分钟。整个构建总时间从原始的3小时40分钟降到了2小时出头。这里面还有一部分时间节省来自DL_DIR复用——后续如果只是修改了某个应用层配置重新执行bitbake时几乎所有源码包都不用重新下载构建时间进一步压缩到40分钟左右。需要说明的是bitbake本身还有sstate-cache编译状态缓存机制这个不在本次讨论范围但如果你把sstate也配置好配合DL_DIR重复构建的体验会接近“秒开”。下载加速和编译缓存是两条独立的优化路径可以叠加使用。5. 常见问题与排查技巧实录5.1 标准问题与解决方案速查表我在配置和使用过程中踩过不少坑整理成表格方便你对照排查。问题现象可能原因解决方法bitbake报错“Fetcher failure: Unable to fetch URL”清华镜像缺失该包检查PREMIRRORS是否配置正确确认是否走到了回退逻辑也可以手动到镜像目录确认文件是否存在下载速度仍然很慢PREMIRRORS未生效用bitbake -e检查变量值确认local.conf中的语法没有写错特别是末尾的反斜杠和换行符部分包一直下载失败镜像站没有对应git库针对该包单独写一条更精确的PREMIRRORS规则或改用下载源码包的方式替代git clone配置后构建报“No such file or directory”DL_DIR路径不存在或权限不对确认目录已创建并且当前用户有读写权限own-mirrors模式下提示No candidate found镜像源没有对应文件把你的PREMIRRORS改成不配置own-mirrors或补充FALLBACK机制磁盘空间暴涨DL_DIR累积大量源码包定期清理不再使用的源码包或把DL_DIR挂载到大容量分区个别包走的是svn/cvs协议PREMIRRORS里没配置对应协议增加svn://.*/.*、cvs://.*/.*等映射规则5.2 清华镜像覆盖不到的那些包清华的Yocto镜像虽然覆盖面广但也不是万能的。我实际使用中发现以下几类包经常“中招”第一类是需要从GitHub Release直接下载的二进制包。有些包如prebuilt工具链、特定架构的编译器上游托管在GitHub Release上镜像站不一定会同步这些大文件。第二类是冷门的Perl/Python模块。CPAN和PyPI的包有三万多个镜像站只同步了其中一部分。如果你构建的镜像里包含大量不常见的模块很容易踩到缺失。第三类是版本更新极快的包。镜像站同步有延迟如果你在local.conf或bbappend里指定了某个刚发布几天的新版本镜像站还没来得及同步就会拉取失败。遇到这些包我的处理套路是这样的如果包数量少一两个直接不处理让PREMIRRORS自动回退到上游下载。虽然慢点但能保证构建成功。如果包数量多考虑加一个“中转下载”脚本先用aria2或wget把这些包从上游拉到DL_DIR然后再跑bitbake。这样能避免bitbake一个个串行下载导致的超时问题。如果包的上游长期不稳定最保险的做法是在内网部署一个完整的source mirrorYocto官方支持用bitbake-layers和own-mirrors实现定期同步保证内部构建永远不依赖外部网络。5.3 三个不容易注意到的细节第一个细节反斜杠后面不能有空格。PREMIRRORS的多行配置里每行末尾的\n和换行符之间要特殊处理。bitbake对空白字符很敏感如果配置里多了空格或Tab可能会导致整条规则失效。最稳妥的写法是严格按照官方文档的格式每行结尾是\加换行规则之间用空格分隔最后一行要单独处理。第二个细节git2目录和sources目录的路径不能混用。清华镜像里git仓库镜像放在git2下tar.gz源码包放在sources下。如果你把git://的URL映射到了sources目录永远找不到对应文件。反过来也一样。配置前最好先到镜像站目录里看一眼确认你的包到底在哪个分类下。第三个细节DL_DIR的复用和备份。我把DL_DIR当作一个重要资产来对待。因为这个目录里累积了几个月构建用到的所有源码包一旦丢失下次构建就得重新下载。我通常会把DL_DIR定期同步到NAS或移动硬盘上。移动开发环境时直接把这个目录带过去新机器上配置好相同路径第一次构建就能直接命中缓存体验非常好。5.4 配置快速生效的小技巧修改local.conf后有时候觉得bitbake没有立刻使用新配置这多半是缓存导致的错觉。可以执行下面两条命令强制刷新bitbake -c cleansstate 目标包名 bitbake -c fetchall 目标包名第一条清掉该包的编译状态缓存第二条只下载源码不解压编译专门用来验证下载配置是否正确。另外有个更彻底的刷新命令适合批量下载源码相当于预热下载缓存bitbake --runallfetch 目标镜像名这条命令会尝试把整个镜像依赖树里所有包的源码都拉取到DL_DIR不会触发编译。我每次在新环境上配置好下载加速后都会先跑一遍这个命令确认所有源码都能正常获取再正式开始构建。这个习惯帮我避开了不少“构建到一半报fetch错误”的尴尬。6. 高阶技巧把下载加速效果再放大一倍6.1 镜像源和本地缓存的叠加使用到这里为止基础加速方案已经能让下载提速好几倍。如果你还想更进一步可以把清华镜像和本地DL_DIR缓存结合起来实现“本地有就走本地本地没有就走清华镜像清华镜像也没有才走上游”的三级加速体系。具体配置如下# 第一级本地持久化缓存 SOURCE_MIRROR_URL file:///opt/yocto-downloads INHERIT own-mirrors # 第二级清华镜像兜底 PREMIRRORS:prepend \ http://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ https://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/sources/ \n \ git://.*/.* http://mirrors.tuna.tsinghua.edu.cn/yocto/git2/ \n \ 看到这里你可能会有疑问SOURCE_MIRROR_URL已经指定成了本地目录PREMIRRORS怎么还能把请求转发到清华镜像这就是Yocto的精妙之处。fetch阶段会先检查DL_DIR和SOURCE_MIRROR_URL指定的本地目录如果命中就直接用如果没命中bitbake会到上游去下载而PREMIRRORS会把这个“上游请求”重定向到清华镜像。也就是说本地优先、镜像次之、上游兜底三级各自分工互不冲突。实测下来这种叠加方案在长期维护的项目上效果最明显。第一次构建时还会走一部分清华镜像第二次、第三次构建基本全部命中本地缓存fetch阶段接近零耗时。6.2 针对git仓库的额外优化PREMIRRORS处理git仓库时有一个隐患如果镜像站上的仓库更新不及时你可能会拉到旧代码进而产生编译问题。为了避免这种情况可以考虑在PREMIRRORS中把git仓库的镜像规则写窄一点只针对你确定不会频繁变动的仓库。另一个git相关的优化是配置Yocto的Git缓存大小和清理策略。在local.conf中加上BB_GENERATE_MIRROR_TARBALLS 1这个变量会让bitbake在拉取git仓库时同时生成一个tar.gz格式的镜像包并保存到DL_DIR。后续构建如果要用同一份代码可以直接用tar.gz包而不需要重新做git clone速度会快很多。代价是DL_DIR会额外占用一些空间每个git仓库生成的tar包约等于该仓库完整大小的80%左右但考虑到它带来的下载稳定性提升这点空间成本完全值得。6.3 预热下载缓存的脚本化操作最后分享一个我自己写的小脚本。每次需要在一台新机器上配置Yocto环境时我会先跑下面这段脚本把所有源码都提前拉取到位#!/bin/bash # 预热Yocto下载缓存 # 用法./prefetch_yocto.sh image-target [build-dir] IMAGE_TARGET${1:-core-image-minimal} BUILD_DIR${2:-build} cd $BUILD_DIR source ../oe-init-build-env /dev/null 21 echo 开始预热下载缓存目标$IMAGE_TARGET time bitbake --runallfetch $IMAGE_TARGET if [ $? -eq 0 ]; then echo 下载缓存预热完成。 else echo 部分源码下载失败请检查网络或镜像配置。 exit 1 fi这个脚本的本质是调用了Yocto的--runallfetch参数它会解析整个镜像依赖树把每一个SRC_URI都执行一遍获取操作但不会进入编译阶段。比起让bitbake边编译边下载这种方式能把下载任务集中处理配合镜像配置的加速效果整个预热过程通常只需要十几分钟。有读者可能想问“bitbake --runallfetch”和“bitbake -c fetchall”有什么区别。简单说前者是遍历所有任务后者是只执行某个包的任务。我测试下来的感觉是--runallfetch更全面会把各种间接依赖也一起拉取。如果你的Yocto版本较老2.6以下用-c fetchall也是可以的。7. 写在最后的几条经验配置Yocto下载加速这个事本身不复杂真正复杂的是搞清楚bitbake的下载机制以及了解不同镜像源的覆盖范围。我最初接触Yocto时也走了不少弯路一度以为“下载慢”只能靠换更好的网络解决后来弄明白PREMIRRORS之后才恍然大悟——原来Yocto早就设计好了灵活的镜像机制只是很多人没有去用而已。根据我的经验最值得记住的几点是PREMIRRORS的价值在于“无缝兜底”不管你镜像配置得多好都要保证上游路径始终可达DL_DIR的价值在于“重复利用”只要缓存做得好同一个项目在同一个环境里第二次构建几乎不花下载时间清华镜像这类公共源的价值在于“第一次访问时的速度”它解决了从零开始构建时的最长链路。如果你现在正被Yocto下载慢折腾得头疼照着这篇文章里的配置试一遍注意几个容易踩的坑构建速度大概率会有质的提升。后面再遇到某个软件包拉取失败也不用慌了——先看看是不是镜像源覆盖不到再决定是手动下载到DL_DIR还是调整PREMIRRORS规则。工具是死的配置是活的理解了原理之后你完全可以按自己的网络状况和项目特点组合出最适合自己的加速方案。
返回列表