记一次解决用AMI首次启动的AWS EC2实例的 EBS Volume 访问慢的问题
问题缘起
最近在 AWS 上部署深度学习模型时,遇到了一个让人困惑的现象:明明是配置很高的 EC2 实例,为什么从AMI Launch之后,首次加载模型的速度出奇地慢(花了我半个多小时,一般整个推理也不到1分钟)?更奇怪的是,第二次加载时速度就恢复正常了。这个问题困扰了我好一阵子,直到深入研究 AWS 的技术文档才恍然大悟。
问题排查
通过查阅 AWS EBS 的技术文档,终于找到了问题的症结所在。原来,当我们从 Snapshot 创建新的 Volume 时,AWS 采用了一种"延迟加载"的机制:存储块并不会立即从 Amazon S3 完整下载到 Volume,而是在首次访问时才会触发下载。这种机制虽然能让 Volume 创建过程变快,但代价就是首次访问时会遇到明显的延迟。
正如 AWS 文档所说:
对于从 Snapshot 创建的 Volume,存储块必须从 Amazon S3 拉取并写入到 Volume 中,然后才能访问它们。这个预加载动作需要时间,会导致首次访问时 I/O 操作的延迟显著增加。
参考
解决方案
既然找到了原因,解决方案就很明确了:我们需要提前预热(Pre-warm)这个 Volume。说白了,就是在正式使用之前,先触发一次完整的数据读取,让所有数据块都预先加载到位。
这里介绍两种预热方法:
方案一:使用 dd
命令(简单但稍慢)
这是 Linux 系统自带的命令,用起来直截了当:
sudo dd if=/dev/nvme0n1 of=/dev/null bs=1M
方案二:使用 fio
工具(推荐,更快更强大)
fio
需要先安装,但功能更强大:
sudo fio --filename=/dev/nvme0n1 --rw=read --bs=1M --iodepth=32 --ioengine=libaio --direct=1 --name=volume-initialize
安装方法:
- Amazon Linux:
sudo yum install -y fio
- Ubuntu:
sudo apt-get install -y fio
fio
命令看起来参数不少,我们来一一解读:
--filename=/dev/nvme0n1
:指定要预热的设备--rw=read
:只读模式--bs=1M
:每次读取block size为 1MB--iodepth=32
:并行处理 32 个请求--ioengine=libaio
:使用异步 I/O--direct=1
:直接读取,绕过系统缓存
如何监控预热进度?
预热过程可能持续几分钟到几小时不等。这里分享两个监控方法:
- 在
fio
命令中加入--status-interval=1
参数,每秒显示进度:
sudo fio --filename=/dev/nvme0n1 --rw=read --bs=1M --iodepth=32 --ioengine=libaio --direct=1 --name=volume-initialize --status-interval=1
- 另开一个终端窗口,用
iostat
命令监控:
sudo iostat -x nvme0n1 1
注意事项
在动手操作前,有几点需要特别注意:
-
确认设备名称:使用
lsblk
或df -h
仔细核对设备名,就像确认钥匙是否对应正确的锁。 -
谨慎处理 Root Volume:如果是根目录所在的 Volume(
/
),要格外小心,确保只执行读取操作。 -
耐心等待:预热时间取决于几个因素:
- EC2 的网络带宽
- Volume 的 IOPS 配置
- Volume 的大小
知识要点总结
-
为什么选
fio
?- 支持多线程,速度更快
- 异步 I/O,效率更高
- 进度监控更直观
- 可配置项更丰富
-
最佳实践
- 从 Snapshot 创建新 Volume 后,最好立即进行预热
- 选择业务低峰期进行预热
- 可以将预热步骤加入系统初始化脚本
-
收益
- 消除首次访问的性能延迟
- 提供稳定一致的 I/O 性能
- 改善用户体验
结语
这个问题的解决过程,让我对 AWS EB预热这个解决方案虽然简单,却能带来立竿见影的效果。
希望这篇文章能帮助遇到类似问题的同学。