云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

免备案CDN_个人网站建设报价_学生机

小七 141 0

将我们的软件移植到ARM64

随着我们在网络中启用更多的ARM64[1]计算机,我想对我们在多体系结构环境中实现软件对等的过程进行一些技术性的了解。为了了解这个任务的规模,有必要描述一下我们在服务器上运行的软件栈。这个基础是Linux内核。然后,我们使用Debian发行版作为我们的基本操作系统。最后,我们安装数百个我们自己构建的包。有些软件包是基于开源软件的,通常是为了更好地满足我们的需求而定制的。其他包是在Cloudflare中从头开始编写的。业界对ARM64的支持非常活跃,因此已经移植了很多开源软件。这包括Linux内核。此外,Debian在2017年推出了Stretch,使ARM64成为一流的发布架构。这意味着,在获得我们的ARM64硬件后,一些工程师能够快速、顺利地将Debian引入。然后我们的注意力转向让我们所有的内部包为ARM64构建并运行。我们的堆栈使用各种各样的编程语言,包括C、C++、GO、Lua、Python和Ro锈。不同的语言有不同的移植要求,有些语言比其他语言容易。移植Go代码交叉编译Go代码相对简单,因为ARM64是一个一流的公民。Go使用系统的crossbuild工具链编译和链接静态二进制文件,这意味着我们必须在build essential上安装的唯一附加Debian包是crossbuild-essential-arm64。tom coe/Unsplash摄影在安装了crossbuild工具链之后,我们将每个go-build调用替换为GOARCH=CGO_ENABLED=1 go build的循环,其中遍历amd64和arm64。强制CGO_ENABLED=1是必需的,因为交叉编译默认禁用CGO。生成的二进制文件随后在我们的测试框架中运行。端口生锈代码Rust对ARM64也有成熟的支持。移植的步骤从安装crossbuild-essential-arm64开始,并在rustc或cargo中定义--target三元组。不同的目标被分为不同的完整性层次。在rust cross有完整的说明文件。不过,有一点需要注意的是,任何由一个包拉进来的板条箱也必须交叉编译。使用的板条箱越多,遇到交叉编译不好的机会就越高。测试,以及移植其他代码当涉及到交叉编译时,其他语言就不那么合作了。摆弄CC和LD值似乎并不是最好地利用工程资源。我们真正想要的是一个仿真层。仿真层将利用我们所有的x86_64机器,从我们的分布式计算庞然大物到开发人员的笔记本电脑,用于构建和测试代码。输入QEMU。QEMU是一个具有多种模式的仿真器,包括全系统仿真和用户空间仿真。我们的计算节点足够强大,可以处理系统级的仿真,但是对于开发人员的笔记本电脑来说,用户空间仿真提供了大部分好处,并且开销较小。对于用户空间仿真,我们的移植团队不想在开发人员的正常工作流程中加入太多。我们的内部构建系统已经使用Docker作为后端,因此能够Docker运行到ARM环境中是非常理想的,如下所示:主机$uname-mx86?64主机$docker run--rm-it stretch-arm64/主人:最新的客人-maarch64公司幸运的是,我们并不是第一个提出这个想法的人树脂.io已经解决了这个问题!他们还向qemu用户提交了一个补丁,该补丁在每个execve调用中预装模拟器,类似于binfmt_misc的实现方式[2]。通过预先设置仿真器,实际上是强制每个新进程也被模拟,从而产生一个良好的自包含环境。使用qemu user内置的exece补丁,我们只需将模拟器复制到ARM64容器中,并设置适当的入口点:#qemu内部构建,带补丁来自qemu-aarch64/主人:最新的模拟器#arm64v8/德比安:舒展苗条2018-02-12T13:02:00Z来自arm64v8/debian@sha256:841BBE6F4132526BE95C91BEC657831C76E603309A47992E6444DE6A0B6521ACOPY--from=qemu/qemu-aarch64/qemu-aarch64壳牌/qemu-aarch64","/bin/sh","-c"]#setcap是"sudo"工作所必需的,但会中断环境变量的传递#运行`setcap-r/qemu-aarch64`来中断sudo,但允许环境变量传递#也许有一天我们也会吃蛋糕运行apt get update&&apt get install-y--no install推荐libcap2bin&&\setcap cap_setuid,cap_setgid+ep/qemu-aarch64和\apt get remove--purge-y libcap2 bin&&apt get autoremove-y&&\rm-rf/var/lib/apt/列表/*入口点/qemu-aarch64","--execve","/qemu-aarch64"]CMD/bin/bash"]这个Dockerfile产生了我们之前寻找的跨体系结构输出。现在我们有了一个独立的ARM64环境,我们可以相对顺利地构建和测试我们的大部分代码。技术难题当然,在通往完美的道路上总有一些障碍。在向我们的开发人员发布这个修改过的Debian映像后,他们返回了一些有趣的问题:由于LD_LIBRARY_PATH不工作,测试失败Go程序以不确定的间隔分段系统安装的库优先于用户安装的库缓慢的构建和零星的测试用例失败,加快了我们对本机构建和CI的计划图书馆路与朋友结果发现LD_LIBRARY_PATH不是唯一一个无法正常工作的环境变量。所有的环境变量,无论是在命令行上设置还是通过其他方式(例如导出)都无法传播到qemu用户进程中。通过对已知良好代码的二等分,我们发现是Dockerfile中的setcap阻止了环境变量passthrough。不幸的是,这个setcap是允许我们调用sudo的同一个setcap,因此我们要提醒我们的开发人员,他们可以在容器中运行sudo,也可以传递环境变量,但不能两者兼而有之。间歇Go故障随着大量Go代码在我们的CI系统中运行,很容易发现间歇性分段故障的趋势。凭直觉,我们确认了一个假设,即非确定性故障通常是由线程问题引起的。不幸的是,对问题跟踪程序的意见显示Go/QEMU不兼容不是优先考虑的问题,因此我们没有上游修复程序。我们提出的解决方法很简单:如果问题与线程相关,请限制线程的运行位置!当我们打包内部go二进制文件时,我们添加一个.deb安装后脚本来检测我们是否在ARM64仿真下运行,如果是这样,那么将go二进制文件可以运行的cpu数量减少到一个。我们会因为固定在一个CPU上而损失性能,但是当我们已经在仿真环境下运行时,这种减速可以忽略不计,慢代码比不工作的代码要好。有了解决办法,间歇性车祸的报告降到了零。下一个问题!共享库混合我们喜欢站在科技的前沿。从建议改进TLS1.3,到与Mozilla合作使DNS查询更加安全,以及两者之间的一切。为了能够支持这些新技术,我们的软件必须处于最前沿。另一方面,我们也需要一个可靠的平台来建立。我们选择Debian的原因之一是它的长期支持生命周期,而不是其他滚动发布操作系统。与这两种想法相反,我们选择不使用我们的最新版本覆盖/usr/lib中的系统库,而是通过安装到/usr/local/lib中来补充默认值。报告LD_LIBRARY_PATH问题的开发团队也来找我们说,他们的软件ARM64版本将无法加载共享对象符号。启动了一个调试会话,我们最终将其与/etc的顺序隔离开来/ld.so.conf公司.d/在Debian中。比较x86_64计算机:$uname-百万x86?64$ls/等/ld.so.conf公司.d/图书馆会议x86_64-linux-gnu.conf$cat/等/ld.so.conf公司.d/图书馆会议#libc默认配置/usr/本地/lib$cat/等/ld.so.conf公司.d/x86_64-linux-gnu.conf#连拱支架/lib/x86_64-linux-gnu/usr/lib/x86_64-linux-gnu对于arm64机器:$uname-百万aarch64公司$ls/等/ld.so.conf公司.d/aarch64 linux-gnu.conf图书馆会议$cat/等/ld.so.conf公司.d/aarch64 linux-gnu.conf#连拱支架/lib/aarch64 linux gnu/usr/lib/aarch64 linux gnu$cat/等/ld.so.conf公司.d/图书馆会议#libc默认配置/usr/本地/lib通过遍历/等/ld.so.conf公司.d/按字母顺序,/usr/local/lib中的共享库将在x86_64上的/usr/lib/$(uname-m)-linux gnu之前加载,而arm64则相反!内部讨论导致我们没有更改系统默认的搜索顺序,而是使用链接器标志--rpath请求运行时加载程序首先显式搜索/usr/local/lib位置。这个问题同时适用于模拟的和物理的ARM64环境,这对于我们刚刚构建的仿真框架来说是一个福音。本机构建和CI交叉和模拟编译带来了超过99%的边缘代码库,但是仍然有少数包不符合我们定义的模型。构建他们的虚拟机需要花费6个小时的时间来并行构建虚拟机。其他包调用了更深奥的函数,而QEMU不准备处理这些函数。我们没有将资源用于模拟长尾,而是分配了一些ARM64计算机用于开发人员访问,并为本机CI代理分配了一台计算机。长尾的维护者可以和平地进行迭代,因为他们知道失败的测试用例决不是由仿真层造成的。当准备好后,CI将接受他们的更改,并构建一个正式的包,然后进行评审。虽然本机编译是最不容易出错的构建方法,但是有限的机器供应使得这个选项没有吸引力;我们分配给开发的机器越多,CI就意味着我们使用的awa机器越多