查看原文
其他

面向百度网盘的大规模数据面存储架构思考与设计

GB 百度智能云技术站 2023-07-25
本文整理自同名《云智公开课》系列分享。
这是百度沧海·存储的数据面存储底座 ARIES 的第一次公开分享。 本文完整地涵盖了从存储系统的设计思想、ARIES 架构设计、关键概念和工程实现挑战等环节,所以全文有点长,建议先收藏再慢慢阅读。
关于百度沧海·存储的元数据存储底座 TafDB 的详细介绍,文章链接见文末“传送门”。
注释:ARIES,A Reliable and Integrated Exabytes Storage。

这次我分享的主题是《面向百度网盘的大规模数据面存储架构思考与设计》。
下面是我今天分享的内容的目录:
第一部分介绍背景,第二部分对大规模数据存储做个概述,第三部分介绍一下百度沧海如何支撑网盘的存储架构,第四部分分享一下经验与思考。
1. 背景介绍
第一部分是背景介绍,我简单介绍下百度沧海的及其与网盘的关系。
下面是百度沧海整个一个全景图,从底下的技术平台,到产品体系,再到解决方案,百度沧海都有非常丰富的内容,之前的同学已经介绍过了,这里我就不展开了。
下一页是百度网盘的简介。
百度网盘大家都比较清楚,它是中国最大的个人云存储服务,实际上它除了提供云存储这种服务以外还提供了丰富的数据和内容应用类的服务,同时它也支持企业客户。
百度网盘与百度沧海的关系是,网盘的底座存储是基于百度沧海构建的,当然,网盘自身这一层同样也存在非常复杂的数据管理机制。
右边我贴了两张图,都是从我的手机上网盘 APP 截图而来。第一张图是全部工具,可以看出网盘有非常多的应用。第二张图,从中我们可以看出网盘有一些智能化的服务。我个人也是网盘的十年老用户了,也是网盘的会员,在这里我给网盘和百度沧海打个 Call。
2. 大规模数据存储概述
第二部分是大规模数据存储概述。在这一部分,我对大规模数据存储的相关核心主题进行一个简要的介绍。
下面一页是权威机构前几年对全球的数据增长情况做的一个预测。
从中我们可以看出不仅数据的体量比较大,而且有加速增长的趋势。这张图里面都以 ZB 为单位来形容数据,我们都知道一个 ZB 等于 1024EB,可以说数据的规模是相当庞大的。
下一步我们对常见的数据进行一个分类,这个分类我是从一个工程人员的视角出发去看待的。
从三个层次来看数据的分类,最底层我认为它是一个基础层,就是非常简单的一个数据的组织,比如说数据流或者数据片段或者数据项。
再往上一层,根据工程实现的需求,进行一些结构的表达,所以我认为它是结构层。从这一层来看,我认为数据可以分为非结构化和结构化或半结构化这种这些类型。非结构化的类型包括比如文件和对象、块、二进制流、文本流等等。结构化和半结构化的类型就更加丰富了,包括数据结构、关系、关系数据库、键值数据库、表格数据库、文档、程序、时序、图等这些数据库数据类型。当然,很多时候,结构化或者半结构化类型也是依赖非结构化的类型去表达的。
最上面一层,从应用的视角来看,数据类型就更加丰富了,包括媒体、图片、纯文本/日志、 word / PDF、可执行文件、数据库文件、压缩文件等等。
下面介绍一下大规模数据存储的范畴,也就是说,当我们做大规模数据存储的时候我们要考虑哪些东西。
我认为可以分为两个圈层,第一个圈层是存储比较偏核心的一些东西,下面介绍一下。首先是模型和组织,我们要对数据建立合理的存储模型和访问模型,并进行合理的组织和结构化。
同时我们要提供访问的接口与协议,还有各种访问方式等等。然后我们还需要管理数据的分布、数据的分区以及数据的复制。这个复制除了包括传统的多副本复制,也包括像冗余编码这种形式的复制。
我们也需要对数据进行容错,因为数据总是有可能损坏,我们要及时发现损坏的数据并修复到正确的状态。同时也包括故障容错,我们要具备一定的抵御各类异常和错误的能力。再就是备份与恢复,作为一种容灾机制而存在。
然后很重要的一点就是性能和成本,性能和成本是非常关键的部分,因为性能和成本在很多时候会存在一种折衷的状态,所以需要提供合理的性能和合理的成本,尽量以较低的成本满足业务的性能需求。
最后是系统,我们有了上述这些能力,我们需要有能力把这些能力构建成系统,并且运维好,运营好,让客户使用起来更方便。
第二圈层我认为它包括流通管理、计算分析的支撑以及产品服务与解决方案。
第一点是流通管理,数据在不同的位置、地域、应用、部门、使用者之间进行流通,我们需要管理这些数据的流通过程,以及相应的安全保证。
第二点是计算分析的支撑,我们知道,抛开备份这种需求,静态的数据其实是没有太大的价值的,很多数据都需要通过计算和分析,甚至一些智能化的处理方式来挖掘数据中隐藏的价值。作为一个存储系统,一定要支撑好这类需求。
第三点是产品服务与解决方案,我们要把这些系统构建成产品,构建成服务,并且能够与其它的产品和服务一起构建解决方案。
我们再讨论一下大规模数据存储的挑战,我从两个方面去看待这些挑战。第一个方面是客观世界带来的挑战,第二个方面是组织与文化带来的挑战。
我们先看看第一个方面,客观世界带来挑战,我认为包含四个点:第一个是行为,所谓行为就是数据的访问特征与模式,数据访问特征和模式千差万别,会给我们的存储带来各种挑战。第二个就是环境,这个主要指分布式环境的复杂性以及应对这些复杂性带来的挑战。第三点是资源的挑战,包括资源管理以及资源自身的一些局限性。第四点就是折衷,成本、性能和数据可靠性的折衷。我们知道,在很多领域都存在成本和性能的各种折衷,因为我们是讨论存储,所以还涉及到数据的可靠性,参与折衷的点会更多。
第二个方面是组织与文化带来的挑战,包括团队的经验与能力、组织的需求及优先级、组织架构的影响和组织的文化风格等。
下面我就客观世界带来的挑战进行一些阐述。第一部分是行为带来的挑战,行为包括数据访问特征和数据访问模式。
我们先简单看看有哪些数据访问特征。比如可读可写,这是最常见的,数据可以被修改,可以随时去读取。还有一些数据是一次写入多次读取,比如像媒体日志之类的文件,一般不会有修改。还有一些数据是一次写入也只读一次,比如消息系统中的消息很多都只允许消费一次。还有一些数据是一次写入可能永远都不会读取,比如备份数据只有在需要恢复的时候才可能去读取,当然我们也希望备份数据永远都不会被读取。
完整读取和部分读取,比如一张图片我们一般需要完整读取出来展示或使用,可能才有意义,再比如视频和音频之类的数据,我们从任意一个片段开始也能读取并播放,又比如数据文件或数据库文件,一般我们的的访问只是读其中一部分数据而已。
访问规律,很多时候数据访问特征遵循一些规律。比如幂律分布,也就是我们常说的二八分布,20% 的数据可能贡献了 80% 的访问。再一个就是周期分布,比如说白天访问得多,晚上访问得少等等。
我们再看看数据访问模式。写入模式,包括一次性写入、追加写入、随机写入。读取模式,包括一次性完整的读取,也包括顺序读取、流式读取、随机读取等。复合模式,比如说批量读写、原子读写和事务性读写等。I/O Size 是连续的,可以划分为不同的大小级别,根据不同的存储场景或者存储介质,不同级别之间的边界也可能不一样。
第二部分是环境带来的挑战,主要是分布式环境带来挑战。
分布式环境带来的复杂性可以分为三个方面,第一个是不可靠的网络,第二个是不可靠的时钟,第三个就是真相与真理。
不可靠网络,网络出现延时或者超时,都是比较常见的,也会出现拥塞和排队现象。网络传输的时候可能会出错,如何处理,网络一旦出现分区之后系统怎么应对,同步网络和异步网络它带来挑战也有所不一样。最后如果出现大规模网络异常,应该怎么处理等等。
不可靠的时钟,看到时钟,首先会想到如何进行计时,计时方法是否会带来时钟误差。如果带来误差之后,在一个数据中心里面,所有机器之间怎么进行时钟同步。有些时候,为了简化这个应用程序的设计,系统可能需要提供单调时钟这种机制。为了克服物理时钟的局限,数据库领域还提出了混合逻辑时钟这种机制。最后就是时序问题,包括偏序和全序等等。
真相与真理,比如网络上一个数据包在发送的时候被第三方截获并篡改了,那么目的地收到的消息可能是一个错的或者假的,会引发安全问题,甚至可能会引发拜占庭故障这样的复杂异常。一个分布式环境有很多节点,那么存在多数派和少数派的认知问题,怎么在节点之间形成共识,达成一致性。如何克服网络环境的不可靠实现跨节点的原子性和事务性处理。最后一点就是这几年比较热门的像区块链这种技术方法。
这里我给了两张图,左边这张图是一个数据中心里面常见的一种网络架构图,右边的话是 Paxos 算法过程的描述。左边代表真实的网络世界,右边代表软件人员和研究人员怎么去应对这种真实世界带来的挑战。
第三部分是资源带来的挑战,包括资源管理和存储介质的局限。
第一点是资源管理的挑战。像机器管理也好,机房管理也好,数据中心基础设施的保障不是一件简单的事情,这些也都是很大的挑战。毕竟做存储不是随便把数据存到几块磁盘上去这么简单,存储系统底下还会依赖很多基础设施的东西,只有整个基础设施层得到了比较好的保障,整个存储系统才可能稳定地运行。除了基础设施保障的挑战,资源的运营、调度等也是很大的挑战。
第二点是存储介质自身的局限性带来的挑战。存储介质本身一般都会有一些局限性,除了访问方式的差异性,还有很重要的一点就是存储介质的性能与成本成反比。这里右边我给了一张图,很多人应该都见过这张图,从图上从上往下看,从寄存器 和CPU 缓存这种非常高速的高性能的介质到下面的 SSD、磁盘、磁带,它的访问速度变得越来越慢,但介质的单位价格也越来越便宜。从下往上看,介质访问速度越来越快,但它的单位价格也会越来越贵。实际上,就每种介质它都有它的一个优势和局限,我们要做好存储系统,要根据需求,充分发挥好这些介质的优势,尽量避开它局限。
最后一部分是折衷带来的挑战。
这里我提出“ CDP Trade-off ” 的观点,这里的 C 就是成本(Cost),D 是数据可靠性(或持久性,Durability ),P是性能( Performance )。很多时候,我们存储系统需要在 C、D、P 之间进行折衷。
右边我给了一些考量,是我们在做真实存储系统的时候可能会遇到的一些考量。这里给的考量也比较多,这里不展开介绍了。基本上,总结来看就是,存储系统还是难以同时在三个方面都做到非常理想的程度,往往还是会有一些取舍。
 3. 百度沧海支撑网盘的存储架构
下面进入今天分享的第三部分,在这部分,给大家介绍一下我们百度沧海云存储是如何支撑网盘的,它的整体架构是什么样子,如何去应对我们前面提到的这些挑战。
我们先展示一下百度沧海存储的核心技术栈。

从图中我们可以看出,最底下是一个名为 Aries 的系统(全称为 A Reliable and Integrated Exabytes Storage ),它是沧海数据面的存储底座。
它向上支撑网盘的 PCS 层(全称为 Personal Cloud Storage ),以及沧海自身的对象存储 BOS 和块存储 CDS。块存储 CDS 又支撑了文件存储 CFS。当然 CFS 和 BOS 自身还有复杂的目录树和元数据,这个是由沧海的元数据底座服务提供的支撑。
今天我们关注的重点是网盘 PCS 和百度沧海 Aries,网盘 PCS 是网盘业务中比较底层的一层,通过与百度沧海 Aries 交互,完成了最终的数据存储和管理职责。
我们看看网盘 PCS 是怎么对接 Aries 的。
首先看看数据模型,对于用户上传的文件,网盘 PCS 对其按照 MB 级别的大小进行切片(目前默认是 4MB ),生成一系列的有序的切片,然后将每个切片作为 Aries 管理数据的基本单位。
然后再看看数据的访问特征,需要说明的是,这里的访问特征仅指代指网盘的的数据落到 Aries 这一层的访问特征,就不代表网盘业务自身看用户侧的数据访问特征。第一点,读多写少,读流量是写流量的数倍大小;第二点,绝大部分数据的读取概率都比较低,可以认为冷数据占主要部分;第三点,即使是偶尔会被读取的非冷数据,它们之间的访问热度差异也并不是很显著;第四点,昼夜访问压力呈现明显的变化规律,白天访问多,夜里访问少;第五点,在长假日结束之后的几天内,写入流量会出现一个明显上升的过程,这个很容易理解,因为大家出去玩了之后拍了很多照片,回来之后很多人会备份照片到网盘。
最后再看看网盘 PCS 的数据访问模式。第一点,一个切片,一次性写入,不支持追加也不支持修改;第二点,一个切片一般是完整读取,很少有部分读取,虽然 Aries 可以提供部分读取,但是从实际情况看,网盘 PCS 层基本都是完整读取切片。
我们再介绍一下 Aries 系统的架构,这里我给了一张简要的架构图。
初看这个图,第一感觉是这个系统似乎有点复杂,模块有十几个,是不是很难理解。其实不然,第二眼会发现 Aries 是一种子系统化的设计,整个系统目前包含 4 个子系统,各模块分属不同的子系统,理解了子系统的功能,就理解了 Aries 的整体架构。
下面简单介绍一下各个子系统。Master 和 DataNode 构成资源管理子系统,它主要负责存储资源管理以及集群的一些基础的管理。左边的 DataAgent、 VolumeService、 Allocator 和 StateService 几个模块构成用户访问子系统,主要负责对接用户访问通路;右边的 CheckService、 TinkerService、 Validator 和 Gardener 构成修复、校验与清理子系统,顾名思义,这个子系统主要负责数据正确性保证、可靠性保证和垃圾清理;中间有一个由 TapeService 和 TapeNode 这两个模块组成的一个子系统,专门负责对接磁带库存储。
Aries 在架构设计上的关键思路包括如下几点:
1.  Aries 基于微服务化和子系统化的设计,模块间高内聚低耦合架构,比较容易实现架构的扩展和演进;
2. 作为云存储的数据底座,我们认为 Aries 应当主动承担存储领域更多的能力,实现更好的技术复用;
3. 面向故障设计,我们认为,系统的故障应对能力与系统的功能处于同等重要地位,这二者都不可或缺;
4. 面向 EB 级别单体规模的设计,以 EC 模型为主,同时也支持多副本;
5. 全介质管理,从傲腾到 SSD、 HDD,再到 SMR HDD,甚至到磁带 Aries 都可以管理,多引擎集成,针对不同的业务场景、不同的介质我们使用不同的引擎,系统能够运行在不同的状态下,充分体现 CDP Trade-off。
我们看看 Aries 的基础数据模型和概念。
首先是数据模型, Aries 以 Slice 为基本服务实体,这个就对应刚才说的文件切出来的一个切片,Slice 不可追加,不可修改。Slice ID 为 128 位,可以实现全域唯一,这里我也给了 Slice ID 这样一个组成图,从图中可以我们可以看到,左边的高 64 位是 Volume ID,Volume 是一个容器的概念,Volume ID 进一步划分为两个部分,高 16 位是集群 ID,低 48 位是集群内给 Volume 分配的 ID,所以 Volume ID 可以实现全域唯一。Slice ID 的低 64 位即一个 Volume 内部给 Slice 分配的 ID,这个 64 位进一步分为两个部分,其中高 32 位是分配进程的生命周期版本,低 32 位是分配进程在这个版本下,给这个 Volume 的 Slice 分配的 ID。
从读写模型上来看, Aries 采用的是直接 EC 模型( Direct Erasure Coding ),也就是说,一个 Slice 写进来之后,直接做 EC 编码,然后写到对应的 DataNode 上。写入过程是基于 Quorum 机制的 1PC 写入。支持 Put、Get、RangeGet、Remove 、Restore、Exist等接口。
Aries 的主要概念。
第一个是 Volume 和 Volumelet。Volume 是一个逻辑容器的概念,大小一般在几十 GB 到 1TB 的之间,Volumelet 就是 Volume 的一个物理存在,假定 EC 模型为( r,k ),那么一个 Volume 会存在 r+k 对应的 Volumelet 。Volumelet 实际上就是 DataNode 里面容纳数据的一个物理容器,当然,在不同的存储引擎里面,Volumelet 的形态有所不一样。
第二个是 Slice 和 Shard。Slice 是 Aries 系统对外的基本实体,Shard 是 Slice 做完 EC 之后编码出来的各个分片,DataNode 上管理的基本数据单位实际上是 Shard。Slice 和 Shard 的关系等同于 Volume 和 Volumelet 的关系。
第三个是 Table Space,Table Space 是一个类似于数据库表的概念。一个 Table Space 包含多个 Volume,这些 Volume 具有相同的 EC 模式。Table Space 会绑定到一个/些资源池,基于 Table Space 的概念可以实现 Volume 和资源池的映射。
这一页的右边给了一个图,这是一个 EC 为 2+1 的例子,这个例子比较好地体现了这些概念之间的关系。从图中可以看出,这个 Volume 里面有一个 Slice X ,EC 之后生成了 Shard 0、Shard 1 和 Shard 2 ,另外一个 Slice Y 也是一样的。Shard 0、Shard 1 和 Shard 2 分别存储在这个 Volume 对应的 Volumelet 0、Volumelet 1 和 Volumelet 2 里面。这个 Table Space 除了包括这个 Volume,还包括了很多别的 Volume。
在上述概念的基础上,下一步看看我们如何应对分布式环境的挑战。后面几页分别从高可用设计、数据可靠性(包括故障处理与数据修复、数据校验等)、系统的扩张能力以及资源管理等方面,介绍我们的应对能力。
这一页介绍相关的高可用设计。
第一点读写路径的高可用设计。右边有两张图,一张是 Put 流程图,另一张是 Get 流程图。我们先看看 Put 流程,Put 的时候数据首先从 API 发送到 DataAgent ,然后 DataAgent 访问 Allocator 服务获取 Slice ID,最后再做 EC 编码并将各个 Shard 的数据分别写到对应的 DataNode 上面去。因为 Aries 的 Slice 是一次性处理的,DataAgent 不需要管理会话状态,是无状态的。那么在第一个步骤中,一旦 DataAgent 出现超时或者异常,API 可以立即重试其它的 DataAgent 继续 Put 流程。第二个步骤中,如果 Allocator 超时或者异常,DataAgent 可以立即重试其它的 Allocator 去获取一个新的 Slice ID,能这么做的原因是,Allocator 是多节点部署的,并且用一致性 Hash 方法来管理。第三个步骤是写入 Shard 到 DataNode,基于 Quorum 机制,可以容忍少量异常的 DataNode 对写入的影响。可以看出,整个 Put 路径中,每个步骤都具备一些高可用的设计。
我们再看看 Get 流程,第一个步骤和 Put 一样的,API 可以请求或者重试任意一个 DataAgent 以实现高可用,第二个步骤是 DataAgent 从 VolumeService 获取目标 Slice 的(对应 Volume 的)分布信息,多个 VolumeService 节点之间是对等关系,每个 VolumeService 都包含全部的分布信息,故 DataAgent 可以访问或者重试任意一个 VolumeService 以实现高可用。实际上,DataAgent 也会尽量缓存一部分 Volume 的分布信息,尽可能优化掉这个步骤,当然,缓存有相应的失效和更新机制。第三个步骤是 DataAgent 从相应的 DataNode 中读取足够的 Shard 并解码出原始数据,因为 EC 的特性,一个 (r,k) 的 EC 模型,最少只需要 r 份数据就可以解码出原始数据,为了规避少数异常 DataNode 节点,DataAgent 会根据策略及时发送一些 Backup Requests。同样可以看出,整个 Get 流程具备多个高可用的设计。
Aries 的读写流程还有一个特点,从图上也能看出来,读写链路做了适当的分离,好处是尽量减少读写的故障干扰,尽可能缩小故障域。最后一点是,Aries 的读写路径中不包含中心化的单点,不会出现单点瓶颈问题。
为了保证高可用,Aries 也具备一些容错设计。比如在 DataNode 之间、Rack 之间、DC 之间以及 AZ 之间的精细化的副本分布管理。Aries 可以保证,一个 Rack 内并行升级,或者 Rack 级别出现异常时不会影响读写。同时 Aries 也支持多 AZ 容灾,但是支持多 AZ 容灾它一定是带有条件的。不管是机房建设、还是资源供应都会影响多 AZ 容灾的能力,另一方面,多 AZ 容灾也可能会导致副本数,也就是存储成本上升。总体而言,Aries 支持多 AZ 容灾,但是是带条件的。
我们看看 Aries 是如何从数据可靠性的角度去应对挑战的,包括包括故障处理和数据修复两个部分。
存储系统面对的故障,更多的是磁盘和机器的故障。对于磁盘故障,一方面我们通过百度智能云的 HAS 服务去预测故障或者发现故障,另一方面, Aries 程序自身内部会持续检测 I/O 线程是否 hang 住,以及连续多块盘同时故障这种具备关联性的异常。如果磁盘被预测出可能会故障,那么 Aries 会尽快把上面的数据 Balance 出去,如果盘已经故障,访问总是出错,那么会自动踢掉这个坏盘,触发数据修复。当然,自动踢盘不是盲目的,有条件进行兜底保护,确保不会因为随意踢盘导致数据出现严重的丢失风险。除了换盘本身是人工操作,剩下的上下线流程都是自动化的,具备较高的效率。另外 Aries 还有磁盘在线率监控,关注坏盘处理的过程是否符合预期。
如果出现机器级别的故障,根据不同的机型和集群规模,处理策略有所不一样。如果是一个超大规模的集群,并且机型的密度不算很高(不超过我们设定的阈值),那么可以直接踢掉机器(同样有相应的兜底保护机制)触发数据修复。如果机器密度很高,或者集群规模太小,不会触发自动踢机器,而是由运维介入,尽快把机器的坏件进行修复,然后带数据回归集群,这样做的目的是避免无畏的数据修复。在有备件的情况下,我们的运维流程能保证在 X 天(一般是 2 天)之内完成机器的坏件修复和回归。如果机器超过 Y 时间(不同的集群 Y 值不一样,一般为个位数天数)没能完成坏件修复和回归,集群也可能直接进入踢机器和数据修复的流程。当然了,即使已经进入数据修复过程,修好的机器如果一旦带数据回归,Aries 也能支持将尚未来得及修复的数据直接加载进去,减少修复量。
如果系统出现大规模故障,会自动进入 Safe Mode 状态,在这个状态中,一部分操作是自动化处理的,同时运维也会及时人工介入,按照预案来进行处理。
数据修复是自动检测和触发的,修复机制中,以 Volume 为单位做任务调度,以 Slice 粒度做精确修复。任务调度机制支持优先级,可以保证可靠性风险比较高的数据,尽量得到更高优的修复。
其它的数据可靠性机制还包括 Slice 回收站机制、Master 的元数据备份与恢复以及 DataNode 的元数据重建等。
我们再看看 Aries 如何通过数据校验机制保证数据可靠性去应对挑战。
Aries 的数据校验机制包括三个方面,分别是实时校验、后台周期性校验和跨系统校验。
第一个方面是实时校验,一个是数据在网络中传输时端到端的校验,再一个是数据在内存和磁盘之间存取时的校验,最后一个是 DataAgent 在完成数据编码之后会立即做一次解码的校验,这么做的目的是及时发现 CPU 或者内存这些硬件的异常(虽然概率很小)导致的数据出错。
第二个方面是后台的周期性校验,包括正确性校验、一致性校验和完整性校验。正确性校验是指校验磁盘上的 Shard 的正确性,确保能够发现静默错误之类的异常。一致性校验是指 Shard 之间的自洽性校验,其目的是确认任意 r 个 Shard 都能够解码出原始的 Slice。完整性校验是指校验某个 Slice 是否出现某些 Shard 长期缺失,也就是说,确认整个 Slice 是完整的,这么做的原因是,我们不能假定数据修复机制永远不会出现 Bug 或者失效,所以需要另外一个机制对修复机制自身的运行效果进行检测。上面的这些校验机制均支持抽查模式,在抽查模式下,系统能够很快地校验一遍所有的 Volume。
最后一个方面是跨系统的校验。对于网盘而言,跨系统校验就是在网盘 PCS 层和 Aries 层之间进行校验,主要目的是确保上下两层所看到的数据存在性视图是一致的,确认没有出现数据丢失,也能发现一些垃圾数据。
这里给了两张 Aries 线上校验相关的监控图,左边的图是一致性校验的进展监控图,从图中我们可以看到,各个集群的校验进度在缓慢上行,一般而言,我们根据业务的要求进行速度调节,确保在比如一个季度或者半年之内能够完成一轮校验。右边的图是完整性校验的进展监控图,从这个图中可以看出,其校验周期比一致性校验要小很多。
这一页我们看看 Aries 如何在系统的扩展性上去应对挑战。
系统的扩展性包含如下几个方面,规模的扩展、数据分布管理、服务能力的扩展和架构扩展。
在规模上,Aries 的 Master 只管理 Volume 这个粒度的分布,因为 Volume 这个容器很大,所以即使是一个高达 EB 规模的集群,Volume 的元数据也只有几个 GB ,可以说是非常小了。相比于管理 Slice 粒度的分布,元信息的总量要低几个数量级,这种方式使得 Aries 很容易扩展规模。
数据分布管理。第一点是 Balance 机制,Aries 的 Balance 机制支持 Usage-Based (基于容量利用率)、Rule-Based (基于副本分布规则)、Decommission 等多种场景,自动化常态运行。Aries 支持任意规模的扩容,小到一块盘一台机器,大到一大批机器都可以支持。扩容之后无需值守,系统自动调节新磁盘/机器上面 Balance 流量和用户流量,尽量在不影响用户读写的情况下加快 Balance。Aries 也支持动态升降副本,支持数据在磁盘和磁带库之间进行迁移,也支持 Volume 的跨集群迁移。
服务能力的扩展。Aries 的几个服务模块中,VolumeService 是对等多实例部署, Allocator、CheckService 和 TinkerService 是基于一致性 Hash 的多实例管理和部署,都非常便于线性扩展。DataAgent 节点和 Gardener 节点无状态的工作节点,可任意伸缩实例数量。
架构的扩展性。Aries 的重大新功能,可以作为一个子系统进行演进,在这种方式下,新功能对原有的架构的侵入性会比较小,也容易实现比较好的兼容性。
这一页介绍一下资源管理的挑战。
先看看 Aries 使用的是什么样的资源,首先看存储介质,Aries 现在支撑网盘还是以 HDD 磁盘为主,CMR 磁盘 18T 和 20T 的为主,SMR 磁盘就以 20T 的为主,我们也正在引入 22T 的 CMR 盘和 26T 的 SMR 盘。同时网盘也开始使用磁带库,目前磁带使用的是 LTO-8 系列,单盘 12T。再看看机型,从早期的 18 盘已经演进到现在主流的 38 盘,也开始上量 92 盘机型,138 盘机型也已经在验证中。磁带库单体在 200PB 以上。
纵向来看, Aries 的整个资源视图,从上往下,分为多个层次。一个集群包含多个 AZ ,每个 AZ 下面包含多个 DC ,每个 DC 下面包含多个机架,然后每个机架下面包含多个机器,每个机器下面包含多个磁盘。也就是说, Aries 管理物理资源到磁盘的粒度。
横向来看,Aries 的资源池对应到一堆的机器,通过 Table Space 绑定资源池的形式,实现逻辑资源和物理资源的映射。
除了上述的资源类型和管理视图两个方面之外,还有大量的资源运营管理工作。包括容量预测,资源调配,供应链以及风险跟踪等等,还包括硬件维修管理,磁盘在线率管理,机器在线率管理等等。
这一页分享一下网盘 PCS 的成本考量和相应的 Trade-off。
先看看我们在成本方面做的工作。
第一块是空间节省,Aries 实现了非常灵活的 EC 模型,最低可达 1.2 副本。Aries 也支持压缩,包括通用压缩( Slice 压缩和 Shard 压缩)和图片无损压缩等。Aries 在引擎的设计上也做了一些特殊的优化,比如说可以实时回收利用删除留下的空洞。还有一些小的优化,比如磁盘格式化的优化,因为 Aries 的随机写引擎中 Volumelet 在磁盘上是大型文件,所以磁盘格式化的时候不需要保留过多的 Inode 空间,这样可以减少一些 Inode 空间浪费。 
第二块是硬件成本。Aries 机型和介质主要采用大容量低成本的硬件,同时在运营层面保证足够的磁盘在线率和机器在线率,减少浪费。
右下角提供了一个表格,这是网盘的一个线上集群的统计。很明显,这个集群非常大,实际有 1.7EB 的物理规模。可以看出,这个集群的 EC 模式分三种,一种是 2+4 的,一种是 18+6 的,还有一种 27+6 的,分别对应 3.0 副本、1.33 副本和 1.2 副本,其中主流的是 1.33 副本,总体来看,这个集群的平均副本数在 1.3 左右。
再看看网盘 PCS 在数据存储上的 Trade-off,当然,这个 Trade-off 只代表数据存储在 Aries 上的 Trade-off,不代表网盘业务自身。总体而言的话,我觉得网盘的数据在 Aries 这一层,存储的成本和数据的可靠性的优先级稍高于性能。
那么这些 Trade-off 是如何体现的?
第一,对于大部分数据,采用比较大的 EC 参数,也就是采用比较大的 r 值,去实现更低的副本数。比如说采用 18+6 的方式,相比于传统的 8+4 的方式,能够实现更低的副本数,但是因为 r 值变大了,访问 Shard 的时候,会有更大的概率受磁盘长尾的影响,会导致 Slice 的访问延迟上升。
第二,对于那些特别小的数据,这种大的 EC 参数可能导致这种访问延迟差异过大,考虑到这部分数据容量占比非常低,我们做一个反向的折衷,减少 r 值,也就是,数据不要 EC 得太细,同时设置足够的 k 值以保证足够的数据可靠性。也就是说,在保证数据可靠性足够的前提下,通过增加副本数,来降低延迟,提升性能。
第三,引入磁带这种介质来降低成本。但磁带是一种线性访问介质,磁带库硬件构造有其特殊性,这导致首字节访问延迟至少在分钟级,而且整个磁带库的总吞吐非常低,一旦有大量数据同时访问,会出现排队现象,总体延迟会受到很大的影响。
第四,在 Aries 的单机引擎中,数据是 DIO 写入的,相比于写 Page Cache,DIO 的延迟更慢,性能会变差,但在面对极端异常时,数据会更加安全可靠。
这一页我们简单看看 Aries 的监控管理。
实际上,Aries 的监控还是比较完善的。这里也给了一些非常核心的监控,像资源监控、服务能力监控,还有一些数据可靠性相关的监控。从实际运行情况来看,监控有比较好的整体表现。这里也给了 Aries 支撑网盘 PCS 的可用性监控大屏图,从图中可以看出,不管是以天、周、月、季度和年度为周期来统计,也不管是 Put、Get 还是 Remove 接口,基本都实现了五个九的可用性,这其实是一个非常高的可用性。
4. 百度沧海的经验与思考
第四部分,也是这次分享的最后一部分,在这里分享一下我们做存储的过程中的一些经验与思考。下面分别从系统设计层面和监控与运维两个层面来分享。
先从系统设计层面分享一些我们的经验和思考。
需求管理方面。
第一,我们认为就是当下的需求和目标是最为重要的,当然往往也需要对这些需求进行 Trade-off。
第二,对未来可能的需求的预见性同样很重要,也就是说,不能仅仅只看当前的需求,还需要看一下未来一年两年甚至三年的需求,进行综合的考量,当然也不一定要看到五年、十年这么远。如果能充分考虑到近两三年可能的需求的话,在设计系统时候能做到更好的兼容性,也更易于演进。
系统设计方面。
第一,我们老生常谈一些东西,像服务可靠性、数据可靠性、扩展性、成本和性能等等,它们仍然是存储系统的核心价值。如果说一个存储系统在这些点上做得不太好,那我们觉得这个存储系统的应用价值会大打折扣。
第二,这一点也是我们经验之谈,一个系统,它的故障处理或者故障应对能力应当与系统的功能同等重要,这些也是保障系统能够长期稳定运行的关键所在,所以一定要重视系统的故障应对能力,提升系统的观测能力,提升系统的运维效率等等。
第三,我们认为存储系统在架构层面目前仍然没有强范式化,可以继续创新,可以拥抱不同的新思路,在设计系统的时候,要重视架构的长期演进能力。
第四,我们认为应用层面也可以有很多创新,比如说长 ID 的应用,这个举个例子,我们最开始设计 Aries 的时候,参考了文件系统的 Inode 设计,把 Slice ID 设计为 64 位,但是我们发现,64 位的长度捉襟见肘,使得一些问题非常难以解决,所以我们把 Slice ID 的长度从 64 位扩展为 128 位,ID 中新增了多种信息,不仅使得我们很快解决了遇到的设计难点问题,而且还带来了一些其它的好处。又比如说一些新型硬件应用,有些问题,客观来说,用硬件解决,比用软件解决要高效很多。
第五,工程和代码一定要便于测试,然后便于其他同学来维护,也要非常便于多人协作开发。除了研发角色,测试和运维这样的角色,我们认为也需要在设计过程中参与进来,而不是等研发把工程开发完了,测试才介入,等系统上线了,运维才介入。这些角色提前参与到设计阶段,有利于让系统充分反映各方的意见和期望,做出更完善的设计。
第六,技术复用和自主可控的考虑,不管是在设计还是研发阶段,不管是从整个系统层面还是其中或大或小的组件的层面,架构师都需要充分考虑是复用业界/同行/同事做得比较优秀技术,还是要自己研发保证自主可控。
第七,形式化验证,形式化验证是业界近几年开始比较重视的方向,现在的系统,逻辑越来越复杂,设计的时候靠工程师的经验去推理固然很重要,但难免会有遗漏,如果能通过形式化验证的方法去对复杂的逻辑进行一个完整的验证,有助于提前发现问题,提前规避异常风险,非常有利于系统更稳定地运行。
再从监控和运维层面分享一些我们的经验和思考。
监控方面。
第一,监控是非常重要的,系统一定要为监控提供便利性。比如说一定要有合理有效的日志,通过日志能够获知系统各种各样的运行状态,当然只有日志肯定也是不够的,也要对系统的运行状态进行各种统计,这需要有完善的指标采集、汇聚、统计等机制。
第二,监控面对的是已知的问题,作为一个复杂的分布式系统,仍然可能存在一些潜在的未知问题,监控尚未覆盖到,所以一定要有风险意识,不能因为系统上线跑了三五年没再出过新问题就掉以轻心,要对线上环境有敬畏之心。
第三,监控后面对应的是报警,报警一定要精准有效,不要什么都报,否则一天收个几百条报警,有效报警和无效报警各种混杂在一起,使得人很容易遗漏重要信息,而且时间长了,容易对报警产生不再重视的意识,埋下隐患。所以报警一定要有分级管理机制,什么时候只报 IM 消息即可,什么时候该报短信,什么时候该报邮件,什么时候该直接打电话都需要仔细确定,报警接收人也需要清楚何种级别的报警对应何种处理方式。
运维方面。
第一,运维必须要提供完善的预案机制,而且预案是必须经过演练和验证的,比如 Aries 系统,有非常多的预案,都经过了演练,形成了非常明确和完善的预案手册。
第二,不论是何种操作,都需要遵循相应的流程,比如说有些操作可能比较关键,需要审批,那就先走审批流程。对于操作,在执行过程当中需要做检查,执行结束之后也需要做检查是否符合预期等等,操作做完之后需要做好记录方便以后回溯。
第三,尽量让更多的操作能够在系统内部程序化、自动化地执行,降低由人在线上现场操作出错触发异常的风险,这一点也要求系统在设计的时候,充分考虑可运维性。
第四,简单事情复杂化和复杂事情简单化的的考量,简单事情复杂化是指,有些操作本身特别简单,但可能带来很严重的后果,所以要把它的执行变得更加复杂,避免“不小心”出错。比如说一个强制删除数据的操作,一条命令即可,很简单,但是一旦出错后果很严重,可能需要执行过程中间加一个二次确认等等。复杂事情简单化是指,比如一些操作过程包含很多步骤,步骤之间是纯流水线式执行的,而且不会带来严重后果,对于这类操作,把它的所有步骤封装起来一键执行,或者让系统内部能够自动化一次性执行,不仅能提高效率,也能减少出错的概率。
第五, Devops 和 SRE(Site Reliability Engineer),这是这几年业界出现和讨论得比较多的两个词汇。Devops 是指从开发走向测试、交付和运维的循环迭代方法,SRE 是站点稳定性工程师,SRE 隐含的意义是指,作为稳定性工程师,不仅只是做线上部署与操作、安装监控、处理线上问题这么简单,还需要能够参与到稳定性相关的各个环节,甚至包括设计与研发阶段,做出自己的贡献。从这两个词汇中,我们可以看到一个趋势,即研发和运维等角色,其边界是在逐步模糊的,这些角色之间不再是严格孤立的,需要有机地合作,各方都对线上稳定性负责。
第六,也是最后一点,我特别想分享的是,“事出反常必有妖”,线上不管出现什么样的异常,即使是很小的异常,都不应该忽略,而需要去定位清楚,找到根因。有果必有因,如果不能及时定位出根因,后续有可能会造成更大的问题。实际经验表明,很多大问题在爆发之前,往往会有很多先兆,及时发现并解决这些小的先兆问题,有利于降低出现大问题的风险。
本期公开课回放链接:https://cloud.baidu.com/live/58
- - - - - - - - - - END - - - - - - - - - - 
点击阅读原文,了解百度沧海更多内容

传送门
  1. 面向高性能计算场景的存储系统解决方案
  2. 面向大数据存算分离场景的数据湖加速方案
  3. 面向大规模数据的云端管理,百度沧海存储产品解析
  4. AI 应用的全流程存储加速方案技术解析和实践分享
  5. 数据湖系列之一 | 你一定爱读的极简数据平台史,从数据仓库、数据湖到湖仓一体
  6. 数据湖系列之二 | 打造无限扩展的云存储系统,元数据存储底座的设计和实践

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存