亚马逊AWS官方博客

基于 ZFS 搭建 EDA 场景的共享存储系统架构与实践

前言

本文针对大并发多任务 EDA 场景下对于存储的高性能、高吞吐需求,提供了结合 Amazon I3实例以及开源文件系统 ZFS 搭建一个可扩展的、安全的、低成本、高性能的共享文件系统的架构设计和操作实践。希望通过本文,可以为那些高性能、高吞吐存储需求的业务场景,不仅仅限于 EDA 领域,提供一个不同于云原生的一些存储服务的设计思路,从而在性能和成本上可以实现更多的选择。

本文的架构设计和实践部分假定你对 AWS 的计算和存储服务有一定的了解,能够基于控制台或者 CLI 命令行创建虚拟机、EBS 卷等常见操作,并且对 Linux 操作系统和开源 ZFS 文件系统常见命令有一定的了解。

 

EDA 的存储需求

EDA(Electronics Design Automation)电子设计自动化,在 EDA 的前端后端流程中,无论是前端的设计、验证、仿真、综合,或者后端的布局、布线、静态时序仿真等等,不同的任务阶段都会有大量的Library文件和项目数据需要共享访问;另外,无论是在数据中心还是在公有云上来运行 EDA 任务,都会是大规模的并发的EDA 工作负载在同时运行,因此这些并发运行的任务同样需要共享访问大量的数据,例如library、tool、userspace、tmp目录,home目录。

随着电子系统和集成电路变得越来越复杂,体积越来越小,对设计、测试、验证和构建这些系统的计算存储能力和基础设施的要求也显著提高,对于大规模运行的EDA 工作负载,存储会随着大量Job的提交很快成为瓶颈。为了支持较高的 EDA 吞吐量(后端)与IOPS(前端) ,通常要一次性投入巨资购买传统的SAN/NAS存储。即使这样在某些Job集中提交的阶段,存储的性能依旧会成为 EDA 的瓶颈,导致作业运行时间增加并相应地抬高 EDA 许可成本。另外EDA 数据的计划内或意外增加,以及快速增长的集群访问数据的需求,都意味着存储最终会耗尽可用空间,或在网路或存储层遭遇带宽/IO限制。因此大规模 EDA 负载并发运行的场景下,存储的瓶颈也是上云的一个越来越强烈的驱动力。可以充分利用云计算的无限扩展的计算和存储能力,可以在无限的计算节点上并发运行大量的 EDA 任务。

由于不同的EDA场景会有不一样的IO需求,区别于通过一台专用存储来支撑各种场景,EDA 应用程序可以充分利用 AWS 云提供的广泛存储选项,缩短大型批处理工作负载的运行时间。在AWS 上,有多种存储服务可以应用到 EDA 的共享存储需求,比如:共享文件存储服务EFS,托管的分布式文件服务 Lustre,块存储 EC2+EBS。

Amazon EFS 文件系统旨在实现高可用性和持久性,并且可以在大规模部署时提供高吞吐量,适用 于 IOPS 不敏感的工作负载。例如 home 目录,存放用户的脚本文件或者配置文件。

那么对于像library/project 目录,会有大量的并发任务同时访问目录,因此在同一个命名空间内既需要满足高IOPS的需求,同时也需要能够满足高带宽的吞吐。那有什么方案既能在同一个命名空间下支持大容量的存储又能提供非常好的IOPS与吞吐?

Amazon FSx for Lustre 提供了一种经过优化的高性能文件系统,可以在短短几分钟内启动和运行这样一个文件系统,让用户可以轻松地使用高性能文件系统处理EDA任务,从性能上、运维上、管理上都比较好的选择,但是因为是托管的Lustre,需要在计算节点安装Lustre的client driver,官方目前只支持较高版本的Linux系统,大量的EDA用户因为EDA工具的原因,OS还是停留在较低的版本,例如Centos6.7/6.9,所以如果客户不能升级客户端操作系统版本的话,就不一定能使用Amazon FSx for Lustre 作为EDA场景下的存储方案。

并行文件系统是一个选择,例如Lustre、BeeGFS、GPFS,但是运维并行文件系统通常需要具备专业知识和投入管理资本,特别是大规模的并行文件系统,需要配置服务器并优化复杂的性能参数,在运维、调优方面带来了一定的压力。

ZFS是一个开源的文件系统,提供存储池、读写缓存、快照、Raid-Z等特性。通过结合AWS 云的 I3/I3en 系列实例类型中所提供的最高达60T 本地实例存储、以及25Gbps、甚至100Gbps的带宽,可以最大程度的发挥ZFS 文件系统的读写缓存、存储池等特性。在实践当中,可以为 EDA 任务的Library/Project数据的高性能和高吞吐的需求,搭建一个可扩展的、安全的、低成本、高性能的共享文件系统。

 

ZFS 文件系统特性介绍

ZFS是一个开源的文件系统,ZFS(Zettabyte File System)是由SUN公司的Jeff Bonwick领导设计的一种基于Solaris的文件系统,最初发布于20014年9月14日。 SUN被Oracle收购后,现在称为Oracle Solaris ZFS。它有一些有趣的特性,比如:

  • 存储池。ZFS 使用存储池的概念来管理物理存储,完全避免使用卷管理。ZFS 将设备聚集到存储池中,而不是强制要求创建虚拟卷。存储池描述了存储的物理特征(设备布局、数据冗余等),可以在上面创建文件系统,并充当任意的数据存储库。文件系统不再受限于单个设备,允许它们与池中的所有文件系统共享磁盘空间。对于用户来说,不再需要预先确定文件系统的大小,因为文件系统会在分配给存储池的磁盘空间内自动增长。添加新存储器后,无需执行其他操作,池中的所有文件系统即可立即使用所增加的磁盘空间。
  • 缓存。ZFS可以使用单独的高速缓存设备以改善读取性能。高速缓存设备在主内存和磁盘之间提供了一个进行高速缓存的附加层。使用高速缓存设备,可以最大程度地提高大多数静态内容的随机读取工作的性能。通过在AWS提供的I3或者I3en机型里的实例存储上部署ZFS缓存,可以极大提高数据读取的性能。
  • 写时拷贝。ZFS 是事务性文件系统,数据是使用写复制语义管理的。数据永远不会被覆盖,并且任何操作序列会全部被提交或全部被忽略。因此,文件系统绝对不会因意外断电或系统崩溃而被损坏。尽管最近写入的数据片段可能丢失,但是文件系统本身将始终是一致的。此外,只有在写入同步数据(使用 O_DSYNC 标志写入)后才返回,因此同步数据决不会丢失。
  • 数据完整性验证和自动修复。对于 ZFS,所有数据和元数据都通过用户可选择的校验和算法进行验证。ZFS 使用校验和的存储方式,从而可确保检测到数据块故障并可以正常地从其中进行恢 复。所有校验和验证与数据恢复都是在文件系统层执行的,并且对应用程序是透明的。
  • 快照。快照是文件系统或卷的只读副本,可以快速创建快照。
  • RAID-Z。ZFS 还提供具有单/双/三奇偶校验容错性的 RAID-Z 配置。单奇偶校验 RAID-Z (raidz 或 raidz1) 与 RAID-5 类似。双奇偶校验 RAID-Z (raidz2) 与 RAID-6 类似。

ZFS 文件系统的存储池、缓存、快照等特性,可以为多种业务场景包括数据库、快照备份、 HPC、EDA任务等提供可扩展的、安全的、高性能的共享文件系统。

 

基于的I3实例的ZFS 存储架构

前文已经提到,基于Amazon I3/I3en 系列实例最高提供60T的本地实例存储,高达25Gbps(最高甚至达到100Gbps)带宽,结合ZFS文件系统存储池、读写缓存、快照、Raid-Z等特性,可以为 EDA 任务的Library/Project数据搭建一个可扩展的、安全的、低成本、高性能的共享文件系统。下图显示了一个使用了I3机型(以i3.16xlarge机型为例)以及ZFS搭建的共享存储架构。

 

性能方面,ZFS可以使用单独的高速缓存设备以改善读取性能,因此可以充分利用Amazon I3/I3en的NVMe SSD的本地实例存储充当ZFS文件系统的缓存,提高共享存储的IOPS性能。对于 EDA 的任务,library目录几乎是只读的场景,所以只需要挂载读缓存,而对于home目录或者project 目录,可以同时挂载读/写缓存,写缓存还可以用两块NVMe SSD实现镜像从而提高可用性。另外,当某些场景需要的性能以上方式满足不了时,还可以直接把Amazon I3/I3en的NVMe SSD的本地实例存储做成一个RAID组,数据全部都存储在这些本地NVMe SSD上以支持超高的存储性能需求。

在扩展性方面,ZFS 的存储池可以实现动态增加 EBS 卷,从而动态扩容 ZFS的存储容量,并且数据会在新增的存储设备上自动进行数据平衡,从而提升并发读写性能。对于大量并发EDA任务,或者长时间多项目的EDA 任务,共享 Library、Project 等数据会随着时间的推移持续增长。因此,可以利用 ZFS 的存储池特性实现 EDA共享存储的在线扩展,而不会对进行中的 EDA 任务造成任何影响。

安全方面,例如project目录或者home目录,通常会因为研发工程师在文件系统上的误操作要求恢复出某个指定时间前的文件,这个需求在前端的HDL阶段特别的多。由于 EDA 场景下会通过ZFS的存储池功能把多块EBS卷做成一个存储池,从而提高共享存储的性能以及容量,通过利用ZFS提供的快照功能,结合开源项目 Z3,可以实现 ZFS 存储池的快照存储到Amazon S3对象存储,从而实现数据的持久性存储以及基于快照的文件恢复。

 

ZFS存储架构实践

下面会基于Amazon 的i3.8xlarge  实例来搭建一个 ZFS 文件系统,并实践生产环境下 EDA 任务的常见管理运维操作。包括搭建一个 ZFS 文件系统,配置读写缓存从而提高 IOPS,实现在线扩容以及快照的备份与恢复等操作。

在搭建 ZFS 文件之前,首先需要通过 AWS 控制台启动一个 EC2实例,本文中使用的操作系统为Ubuntu Server 16.04,实例类型为i3.8xlarge(具有4块1.7 TiB SSD来作为读写缓存),并使用1TB的GP2类型的EBS卷 。具体的启动实例过程在这里不展开描述,可以参照 Amazon EC2文档。

创建ZFS 文件系统

创建 ZFS 文件系统的过程比较简单。通过以下步骤及命令即可安装一个ZFS文件系统以及存储池。

$sudo apt-get update -y
#安装文件系统
$sudo apt-get -y install zfs 
#列出当前设备
$sudo lsblk
#在指定存储卷上创建存储池
$sudo zpool create -f edastore /dev/xvdb
#挂载存储池
$sudo zfs set mountpoint=/edastore edastore
#查看文件池状态
$sudo zpool status

设置配额( Quota)

在一些场景下,为了避免用户在存储池中过多的存储一些不必要的文件,造成存储空间的过快增长,并在实际上造成存储空间的浪费,可以根据前期的项目规划和目录规划,针对目录层级或者用户层级设置相应的 Quota,在写入的数据超过 Quota 定义的大小尺寸后,不能再继续写入数据。 Quota 设置命令如下:

#创建文件系统
$sudo zfs create edastore/tools
#设置目录 quota: 
$sudo zfs set quota=1G edastore/tools
#设置用户quota
$sudo zfs set userquota@ubuntu=2GB edastore/tools
#验证quota设置,通过dd命令写入数据进行测试
$sudo dd if=/dev/zero of=/edastore/tools/sun.txt bs=2G count=1

当写入磁盘数据超出 Quota 设置后,ZFS 会报错出如下错误:

需要注意的是,在实践中遇到的问题是,在通过目录服务和企业内部环境打通进行用户登录和认证的情况下,不能基于目录服务中的用户设置 Quota 的限制。因此在实际操作中更多的做法是基于项目目录和共享目录来做 Quota 限制。

利用NVMe实例存储设置缓存

针对 EDA 的 Library 库,在大量并发任务的情况下,会有非常高的读性能的要求。可以结合 ZFS 文件系统的读写缓存以及 I3实例的 NVMe 本地实例存储,提高并发读的性能。实际操作如下:

#查看当前磁盘,会看到有四块 NVMe 设备/dev/nvme0n1,/dev/nvme1n1,#/dev/nvme2n1,/dev/nvme3n1
$sudo lsblk
#插入缓存盘
$sudo zpool add -f edastore cache /dev/nvme0n1 /dev/nvme1n1 
#增加log缓存
$sudo zpool add edastore log mirror nvme2n1 nvme3n1
#检查当前状态
$sudo zpool status edastore

检查 ZFS pool 的状态我们可以看到,当前缓存已经插入成功。

 

可以通过下面的操作分别对于加缓存和不加缓存的两种情况进行测试,验证缓存对 ZFS IOPS 和吞吐的提升情况。

#安装 fio
sudo apt-get install -y fio
#创建文件系统
$sudo zfs create edastore/projectA
#测试随机写
$sudo fio --directory=/edastore/projectA --direct=0 --rw=randwrite --refill_buffers --norandommap --randrepeat=0 --ioengine=libaio --bs=4k --size=2G --iodepth=32 --numjobs=20 --runtime=300 --group_reporting --name=4k_mixed
#测试随机只读
$sudo fio --directory=/edastore/projectA --direct=0 --rw=randread --refill_buffers --norandommap --randrepeat=0 --ioengine=libaio --bs=4k --size=2G --iodepth=32 --numjobs=20 --runtime=300 --group_reporting --name=4k_mixed
#检查缓存 的 读写状态
$sudo zpool iostat -v 5

需要注意的是,添加高速缓存设备之后,这些设备中将逐渐填充来自主内存的内容。填充设备可能需要一个小时以上的时间,具体取决于高速缓存设备的大小。因此在通过 fio 写入数据以后,测试缓存的读性能需要等到数据填充到缓存盘以后。通过下图我们可以看到,目标卷中的数据为200G,而 NVMe 的cache中已经缓存了超过90%的数据。

下面通过 fio分别测试20个线程和100个线程并发随机读写的场景,测试结果如下所示,可以看到无论是 IOPS 还是吞吐量,在20个并发的情况下,有NVMe缓存的性能差不多是无 NVMe 缓存性能的12倍,而在100个并发的情况下,有NVMe缓存的性能差不多是无 NVMe 缓存性能的7倍。因此通过Amazon I3实例的本地 NVMe实例存储可以显著提高 ZFS 文件系统的 IOPS 和吞吐量。

线程数  IOPS  吞吐量
无 NVMe 缓存 20 168K 675MB/s
有 NVMe 缓存 20 2144K 8377.2MB/s
无 NVMe 缓存 100 174K 696MB/s
有 NVMe 缓存 100 1209K 4724.2MB/s

需要说明的是,本测试场景是在 ZFS文件系统本机进行的 fio 压测, ZFS 文件系统不支持参数 direct=1直接写磁盘的测试,因此数据反应的不是磁盘本身的性能。另外多次执行测试结果数据有一定的波动,这里取的是数次执行结果的平均值。

利用存储池在线扩展容量

在企业的真实业务中,Library 是多任务多项目共享的,因此随着时间的推移, Library 文件的规模也在不断增长。企业在初始规划时,从成本的角度设计了一个较小的满足当前需求的存储容量。那么随着存储规模的增长,存储如何扩容,并且是在线扩容,不要对运行中的任务造成任何影响,就是企业最直接的一个需求。

ZFS 文件系统的存储池特性很好的支持了这样的用户需求。通过增加一块新的 EBS 卷到存储池中,可以实现:1) 工具端的访问路径不需要做任何修改;2) 运行中的任务没有任何影响; 3) 数据会在新增的盘上自动平衡,从而提升并发读写的效率。具体扩容步骤如下:

  • 在Amazon EC2 服务里,选择卷服务, 创建一块EBS卷, 容量可以自定义, 单卷最大不超过16T,可以根据实际情况而定;
  • 将新创建的卷挂载到这台Amazon I3服务器机器上;
  • 执行 lsblk 命令查看新加卷的设备号;
  • 执行添加和升级命令
#检查新加设备号
$lsblk
#执行添加命令,其中edastore为pool名称:
$sudo zpool add edastore /dev/{deviceno} 
$执行升级命令:
$sudo zpool upgrade edastore
#检查 pool 状态
$sudo zpool status edastore

基于 Z3实现快照备份与恢复

由于 ZFS 存储池可以使用多块EBS 卷,数据分布在所有的 EBS 卷上,通过利用ZFS 文件系统的存储快照功能,创建快照,并与开源项目 Z3结合,从而实现将 ZFS 本地快照上传到Amazon S3,以及从 Amazon S3快照恢复存储池的功能。

Z3备份与恢复的基本原理是围绕zfs send和zfs receive的管道来实现的。Z3 backup 命令,首先是执行 zfs 的 snapshot命令创建本地快照,然后执行 z3 send 以及结合 Amazon S3 multi-part 上传接口,将快照文件上传到 Amazon S3存储桶。Z3 restore命令,首先通过Amazon S3的接口下载 snapshot 文件到本地,执行 ZFS命令将文件恢复为 ZFS本地快照,再执行 zfs receive 恢复快照到 zfs 文件系统。具体可以参考 ZFS的文档以及开源 Z3项目。

基于 Z3的备份与恢复步骤如下:

快照备份

  • 通过AWS控制台或者CLI创建快照S3存储桶: eda-snapshot
  • 登录 ZFS 文件服务器,安装 ZFS 备份工具 Z3
  • 安装Z3并设置配置文件
#如果没有 python-pip 工具,执行安装
$sudo apt install -y python-pip
$export LC_ALL=en_US.UTF-8
#pip 安装 Z3
$sudo pip install z3
#安装其他依赖
$sudo apt-get install pv
$sudo apt-get install pigz
# 更新配置文件
$sudo mkdir /etc/z3_backup
$sudo vi /etc/z3_backup/z3.conf

参考配置文件如下:

##sample configuration file
[main]
#Amazon S3的endpoint。在开源的配置文件中没有说明,在中国区一定要配置#这个参数
HOST = s3---cn-northwest-1.amazonaws.com.rproxy.goskope.com.cn 
#Amazon S3存储桶名称
BUCKET= eda-snapshot
#AWS的Access Key和Secret Key
S3_KEY_ID= *****
S3_SECRET= ***** 
#上传Amazon S3并发线程数
CONCURRENCY=64 
#上传失败重试次数
MAX_RETRIES=3 
#Amazon S3快照对象前缀
S3_PREFIX= project
#文件系统可以配置多个,也可以直接配置存储池的名称
FILESYSTEM=edastore/projectA
# only backup snapshots with this prefix
SNAPSHOT_PREFIX=
  • 创建快照
#创建快照
$sudo zfs snapshot edastore/projectA@projectA.snap01
#检查快照是否创建成功
$sudo zfs list -t snapshot
  • 执行 Z3 backup 命令,快照将会被上传到配置文件中指定的S3存储桶
#Z3 backup
$sudo z3 backup --full --snapshot projectA.snap01
  • 验证Amazon S3存储桶的快照文件
##执行 S3 list 命令
$aws s3 ls s3://eda-snapshot/edastore/ --region cn-northwest-1

快照恢复

如果 ZFS 文件系统损坏,比如对于project目录或者home目录来说,通常会因为研发工程师在文件系统上的误操作要求恢复出指定时间前的文件,那么通过 Z3恢复一个指定时间的快照,就可以实现单个文件或者整个文件系统的恢复。具体恢复步骤如下:

  • 如果原文件系统损坏,需要重新启动一个新的原有配置的 Amazon EC2,并按照上述步骤安装 ZFS,插入缓存盘,安装Z3,并设置好Z3的配置文件
  • 创建同名的存储池以及文件系统
  • 执行 Z3恢复命令
#执行 z3恢复命令
$sudo z3 restore projectA.snap01 --force
##检查 zfs 文件: zfs status
$sudo zpool status 
$cd /edastore/projectA
##检查是否所有文件都正确恢复
$ls -la
  • 执行Job,验证恢复的文件的正确性。可以根据实际业务场景,比如执行典型的 Job,来验证恢复的文件的完整性和正确性;

 

结论

基于 Amazon I3实例以及 ZFS 文件系统搭建的大容量高性能的存储系统已经应用到多个 EDA 的案例中,通过本方案,帮助用户实现了一个可弹性扩展的、安全的、低成本的、高性能的共享文件存储系统。对于那些需要大规模并发访问共享文件存储系统的其他场景例如 HPC 场景,本方案也是一个可以选择的共享存储设计方案。

 

Reference

芯片设计云计算白皮书 1.0

Oracle® Solaris 11.1管理:ZFS文件系统

Amazon Elastic File System

Amazon FSx for Lustre

Z3开源项目 Github

Amazon EC2 Document

 

本篇作者

琚小龙

AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,擅长DevOps和容器领域。加入 AWS 之前,曾任职互联网创业公司以及HPE,拥有多年移动互联网、大型企业复杂应用的系统架构和设计经验。