第一个是单分区事务优化:通过将目录的属性信息分离,成为目录的孩子节点,同时,底层事务 K-V 控制属于同一个目录的元数据在同一个分片,我们将绝大部分的元数据操作从 2PC 优化到 1PC。 第二个是路径解析优化:通过在传统表结构(Inode 表)之上引入目录索引表(Index 表)来加速路径解析。具体来说,就是把同一个文件系统的目录索引表放置在同一个分片中,即 Index 分片,实现了将路径解析从 N 次 RPC 优化到 1 次 RPC 调用。
加速目录 rename:Index 分片的引入除了加速路径解析,也为加速目录 rename 提供了机会,有了 Index 这个目录分片,我们就可以把目录 rename 执行过程中触发的分布式成环检测优化为单机成环检测,从而极大地提升目录 rename 的性能。 加速写操作:由于 Namespace 之间是互相隔离的,一个 Namesapce 对应一个 Index 分片,这样我们就可以把时钟服务 offload 到 Index 分片,从而减少从 TSO 获取时钟这一次 RPC 开销。
读取性能瓶颈:尽管路径解析变成了单节点操作,但因为路径深度大部分超过 10 层,底层单机引擎的多次查询仍然会消耗大量 CPU 资源。 写入性能瓶颈:所有的目录修改操作都需要访问 Index 分片 ,所以我们需要尽可能的提升 Index 分片的写入吞吐。
事务冲突:当执行 mkdir 或者 rmdir 操作时,我们需要同时修改 Index 分片和 Inode 分片,这使得 mkdir 或者 rmdir 成为一个跨分片的两阶段提交(2PC)事务。如果并发向某一个目录下插入子目录,由于父目录频繁更新,会导致大量的分布式事务冲突。 高延迟:目录修改操作触发两阶段提交协议,这会导致 mkdir/ rmdir 的高延迟。
在单机架构下,我们强制层级 Namespace 依赖的 Inode 信息和目录树信息绑定分配到同一组存储节点。这其实就是前面提到的 co-located 功能。这个时候,不需要跨机事务和多次 RPC 就可以完成文件创建、目录 rename 等元数据操作,这时候系统跟单机架构的延迟一致。 当文件规模达到 10 亿量级的临界点之后,会触发分布式数据库按不同的表边界分裂。分布式数据库的分裂操作对上层业务无感,Inode 表动态水平扩展,这个时候单机事务转换为跨节点事务,单次 RPC 转换为多次 RPC。这样单机架构就可以平滑地过渡到分布式架构了。虽然,分布式架构的性能相对于单机架构有一些衰减,单次操作到毫秒级延迟,但是可以做到线性扩展。 在单机架构下还有一个问题待解决,就是如何提升系统的吞吐。我们的做法是把文件语义操作下推到元数据底座上,减少跟上层组件的通讯次数,能够支持到几十万 TPS。
扩展性受限与高可用性不足 架构瓶颈: 采用 master-slave 架构,扩展性受限于单机的存储空间和处理能力。 单点故障风险:Master 作为单点,故障可能导致整个系统不可用。尽管使用一致性协议或者共享存储实现了高可用,但是这种方式的实现都是状态机方式,触发 bug 往往就会导致所有 master 节点故障。 迭代效率低:以 HDFS namenode 为例,其模块迭代需极为谨慎,任何问题都可能造成集群不可用,降低了系统的迭代速度。 离线 EC 导致性能瓶颈 写入过程复杂:数据先以 3 副本方式写入分布式 K-V 存储,当分布式 K-V 中单个分片数据写入达到阀值的时候,再通过读取进行 EC 编码,最终写入 EC 系统中。这样多次的读写操作消耗大量 CPU 和 I/O,导致写性能和读吞吐量降低。 存放副本机制成本高 固定副本数:采用 1.5 副本的 EC 编码系统无法进一步降低成本。
在线 EC:数据被 Put 进来后,数据面底座直接将数据进行 EC,然后将 EC 之后的各个分片 Shard 写入到对应的各个 DataNode 中去。在线 EC 的好处是不需要一个积攒和转储的过程,简化工程复杂度,减少转储之前的额外空间占用和 I/O 开销。 可变 EC:提供 1.5、1.33 甚至更低的副本数。
分层架构路线:构建统一的分布式文件系统作为底座,进而基于该系统开发上层的云存储产品,包括对象存储、块存储、文件存储等。 组件化架构路线:通过提炼出统一的元数据和数据面组件作为底座,上层的云存储产品基于这个组件式底座进行积木式进行搭建,比如百度沧海·存储的架构路线。