FreeBSD在亚马逊EC2平台的一年技术实践
发布工程工作
自2023年11月担任FreeBSD发布工程负责人以来,我管理了四个FreeBSD版本发布:13.4(2024年9月)、14.2(2024年12月)、13.5(2025年3月)和计划于6月10日发布的14.3。每个发布周期的工作包括督促开发者及时提交代码、审核合并请求、与其他团队协调、构建测试镜像(通常三个Beta版、一个候选发布版和最终版)、撰写公告文本以及修复发布构建过程中出现的问题。这些工作主要集中在发布前一个月(我称之为"Beta月"),耗时从33.5小时(13.5版本)到79小时(14.2版本)不等。
FreeBSD/EC2平台开发
AWS Graviton电源驱动
在Graviton系统上,“电源按钮"是一个GPIO引脚,其详细信息通过ACPI _AEI对象指定。我添加了代码在ACPI中查找这些信息,并将适当配置传递给PL061 GPIO控制器驱动。当GPIO引脚被触发时,控制器生成中断,导致ACPI"电源按钮"事件被触发,进而关闭系统。
遇到的一个小问题是:EC2提供的ACPI表指定相关GPIO引脚应配置为"上拉"引脚,但PL061控制器实际上没有任何上拉/下拉电阻。这在Linux上不会造成问题,因为Linux会静默忽略GPIO配置失败,而在FreeBSD上我们会在配置失败后禁用设备。作为临时解决方案,我在FreeBSD/EC2 AMI中添加了ACPI_Q_AEI_NOPULL特性,忽略_AEI对象中GPIO引脚规格的上拉标志。
设备热插拔支持
实现热插拔(特别是热拔插)需要大量工作,主要因为存在几个不同问题,每个问题出现在部分EC2实例类型上:
-
IRQ泄漏:在某些Graviton系统上,PCI附加期间会泄漏(虚拟)IRQ保留。在附加和分离EBS卷67次后,我们会耗尽IRQ导致FreeBSD内核恐慌。我通过添加引导加载程序设置来在EC2中关闭该代码。
-
PCI设备电源状态:在某些Graviton系统上,固件使用PCI设备电源状态作为操作系统已完成使用设备并准备"弹出"的指示。这是EC2的一个错误,临时解决方案是FreeBSD/EC2 AMI具有ACPI特性ACPI_Q_CLEAR_PME_ON_DETACH,指示它们在弹出设备前翻转PCI电源管理寄存器中的某些位。
-
NVMe驱动恐慌:在最新一代EC2实例(x86和Graviton)上,PCIe拔插后FreeBSD的nvme驱动会恐慌。我向nvme驱动维护者报告了此问题。
-
幽灵设备:在某些EC2实例上,设备弹出后我们会在PCI总线上看到"幽灵"设备。这原来是另一个EC2错误:管理PCI总线的Nitro固件与管理PCI设备的固件异步操作。临时解决方案是FreeBSD/EC2 AMI具有ACPI特性ACPI_Q_DELAY_BEFORE_EJECT_RESCAN,在发出设备应弹出信号与重新扫描PCI总线之间添加10毫秒延迟。
我还对FreeBSD的热插拔处理进行了"生活质量"改进:添加了引导加载程序可调参数来调整PCIe要求的5秒延迟超时,在EC2中将其设为零。最后,我编写了一个测试脚本,可以启动EC2实例并通过EC2 API反复插拔EBS卷,确认FreeBSD能够连续300次成功附加和分离它。
启动性能优化
数据收集与分析
我基准测试了自2018年以来的每周EC2 AMI构建的启动时间,在此过程中启动了超过一万个EC2实例,并开始生成FreeBSD启动性能图表。收集新数据和更新这些图表现在是我每周快照测试过程的一部分。
具体问题与修复
-
根磁盘大小影响:2024年第一周,FreeBSD启动过程突然变慢约3倍。通过二分提交追踪到将根磁盘大小从5 GB增加到6 GB的提交。将根磁盘大小增加到8 GB后,性能恢复到早期水平。
-
Graviton 2熵种子问题:FreeBSD在Graviton 2实例上启动也很慢,追踪到内核熵种子问题。我重写了代码,使其可以从EFI获取64字节并使用PBKDF2作为"熵扩展器”,将其转换为我们的熵馈送API所需的2048字节。这将FreeBSD arm64/base/UFS的启动时间从约25秒减少到约8秒。
-
ZFS镜像启动慢:ZFS镜像启动比UFS镜像慢得多,且此差异取决于磁盘上的数据量。问题是我们的文件系统构建代码(makefs)和附加ZFS池时发生的情况之间的奇怪交互。FreeBSD的makefs专家通过记录文件系统上更高的事务组解决了问题,ZFS镜像启动时间从约22秒下降到约11秒。
-
IPv6支持问题:2024年12月,在net/aws-ec2-imdsv2-get端口添加IPv6支持时,它首先尝试IPv6连接(尽管IPv4是默认IMDS实例配置),并保持默认TCP超时(75秒)。我修复了此问题,使其首先尝试IPv4并将超时减少到100毫秒。
AMI变体与资源清理
我为FreeBSD/EC2添加了更多AMI"风味":
- 小型AMI:类似基础版但没有调试符号、LLDB调试器、32位库、FreeBSD测试、Amazon SSM代理或AWS CLI,将磁盘空间使用从约5 GB减少到约1 GB
- 构建器AMI:FreeBSD AMI构建器AMI,为用户创建自定义FreeBSD AMI提供简单路径
随着4种FreeBSD AMI风味、两种文件系统(UFS和ZFS)、两种架构(amd64和arm64)和三个FreeBSD版本(13-STABLE、14-STABLE和15-CURRENT),所有每周快照构建开始累积。我在5月清理了旧镜像(及其关联的EBS快照),删除了336 TB的EBS快照。
发布工程改进
并行化发布构建
我重新设计了发布代码以并行化VM镜像中的FreeBSD安装过程,但发现这导致零星构建失败。经过多小时工作,最终追踪到问题是一个缺失的Makefile行:我们没有指定在安装文件之前应创建目录。通过此修复,我能够将发布构建从约22小时减少到约13小时。
构建可重现性
作为每周快照镜像测试的一部分,我现在启动EC2实例并让它们构建自己的AMI,然后使用diffoscope比较它们构建的磁盘镜像与它们启动时使用的镜像。这已经发现了几个问题,其中一些我已经修复,其他一些我已传递给其他开发者处理。
其他工作
除了大项目外,还有大量较小问题需要处理:构建中断(每周快照构建很擅长发现这个问题!)、审查ENA驱动补丁、帮助Dave Cottlehuber添加构建OCI容器支持并上传到仓库、教我的bsdec2-image-upload工具优雅处理内部AWS错误、报告我偶然发现的AWS安全问题等。
未来展望
我仍然是FreeBSD发布工程负责人和FreeBSD/EC2平台维护者,只是用于这项工作的时间少得多。FreeBSD发布将继续进行,但我不太可能有时间深入修复问题。在EC2方面,现在我设置了启动性能回归测试,我可能会发现需要修复的任何问题,但我的"待实现功能"列表中的其他项目可能会停滞,除非我找到更多时间。