降低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部门之间的配合和工作效率。