降低Environment Modules的I/O Load
背景
在前司的多个数据中心中,每个数据中心都有多个集群,单个集群规模可以达到数千台物理机。当大量验证任务并发时,我们常常会遇到NFS卡死的问题。用户在执行ls命令时,可能会卡住几十秒,甚至无法响应。
问题爆发后,CAD与IT部门之间出现了相互推诿的情况:
- CAD部门抱怨IT提供的存储性能太差,无法满足正常的业务需求;
- IT部门则责怪CAD没有合理引导业务,将许多不必要的I/O操作去除。
分析
通过深入分析,发现问题的根源来自双方:
- CAD部门未能深入定制业务流程和脚本,很多任务是随意发展的。CAD自有的脚本和工具也缺乏性能优化;
- IT部门将项目目录与工具目录放在同一存储机头,未能将不同的业务隔离开。再加上CAD依赖的各种环境,导致在项目目录下执行
ls命令时,需要从工具目录读取大量信息。
解决方案(或缓解措施)
针对不同根因,我们分别展开了讨论,并制定了解决方案。由于涉及的点较多,后续有机会再详细展开。本文将重点介绍如何通过Environment Modules减少I/O负载。
2020年:首次提出优化方案
在2020年时,开源社区的Environment Modules(TCL版)虽然实现了常见功能,但未关注性能优化。在我们的环境中,MODULEPATH路径下有约5000个modulefile文件,每次执行module av命令时,需要遍历MODULEPATH路径,并读取每个文件的第一行来判断是否存在Magic cookie,从而确定是否为有效的modulefile文件。
当时我正好跟随李智慧学习缓存架构,我们开始对如何通过缓存优化Environment Modules的性能展开讨论。最终,我们提出了可行的方案:
- 缓存方案:每次安装完工具后,EDA管理员会将
module av命令的结果以特定格式存储到一个文本文件中(缓存文件)。 - 包装命令:用户执行经过包装的
module av命令时,命令只读取缓存文件,而不会再次遍历整个MODULEPATH路径。这种方式将每次执行的任务从用户每次递归遍历和读取几千个文件,转换为管理员一次递归遍历和读取几千个文件+用户每次读取一个缓存文件,极大地提升了用户的体验。
2023年:开源社区对性能的进一步关注
到了2023年,开源社区也开始关注Environment Modules的性能优化。在官方文档中,我们看到了几种优化I/O负载的技术:
-
使用TCL扩展库优化Modules
通过使用专门为Modules优化的TCL扩展库,可以减少不必要的ioctl、fcntl和readlink系统调用,并且将getents的数量降低到50%。这些优化显著减少了I/O负载。 -
rc文件迁移至根层级
将每个深层次的.modulerc与.version文件迁移到MODULEPATH路径的根层级。这样做可以显著减少access、stat、open、read和close系统调用的次数,从而减少I/O负担。 -
不再检查Magic Cookie
在早期版本中,Environment Modules会通过读取每个modulefile的第一行来判断是否有效。然而,在我们的生产环境中,MODULEPATH路径下的文件几乎都是有效的modulefile。为了提高性能,我们可以取消这一Magic cookie的检查,从而减少不必要的open、read和close操作。 -
虚拟modules
虚拟modules是一种缓存方案,将modulefile的路径缓存到.modulerc文件中。执行module av时,读取.modulerc即可直接获取所有modulefile路径,从而避免了遍历目录和读取多个文件的操作。 -
Module cache
另一种缓存方案是使用module cachebuild命令,在每个MODULEPATH路径下创建缓存文件。执行module av时,直接读取缓存文件,而不需要再次遍历目录。虽然该方案会在每个路径下生成缓存文件,但它的性能与我之前的单一缓存方案相近,已经接近于理想的性能。
总结
通过对Environment Modules的性能优化,我通过以下几种手段有效降低了I/O负载:
- 使用缓存来减少用户对文件系统的重复遍历;
- 利用TCL扩展库、rc文件迁移和取消Magic cookie检查来减少不必要的I/O操作;
- 使用虚拟modules和module cache进一步减少读取操作,提高性能。
这些措施显著提升了环境中module av命令的响应速度,缓解了NFS卡死问题,也优化了CAD和IT部门之间的配合和工作效率。
