Ozone 是什么
一句话介绍:Ozone 是一个分布式对象存储系统,从属于 Hadoop 生态,支持海量数据存储,具有良好的扩展性。
为什么需要 Ozone
Hadoop 生态的默认存储是 HDFS,因此这个问题也可以理解为:为什么已经有 HDFS 这样成熟的分布式文件系统了,还要再开发一个分布式对象存储系统?
HDFS 和 Ozone 的对比
对比项 | Ozone | HDFS |
---|---|---|
数据模型 | OZone是一个分布式的对象存储系统,提供的是一个 key-value 形式的对象存储服务 | HDFS 是典型的树状索引结构的文件系统 |
数据获取 | 根据 Object 的名称(key)唯一的获取该 Object 的内容 虽然用户可以使用类似 test1/test.jpg 这样的名字,但是这并不表示用户的 Object是保存在 test1 目录下面的,对于 Ozone 来说,test/test1.jpg 仅仅是一个字符串,和 a.jpg 这种并没有本质区别,因此,不同名称的 Object 之间,访问消耗的资源是类似的 |
一个名为 test1/test.jpg 的文件,访问过程需要先访问到 test1 这个目录,然后再在该目录下查找名为 test.jpg 的文件 |
优势 | 支持海量的用户并发访问 | 支持文件的修改(HDFS 仅允许追加写),支持目录级别的操作,比如删除目录、重命名目录、移动目录等非常容易 |
劣势 | OZone 保存的 Object 不支持修改(追加写也不行),用户哪怕仅仅需要修改一个字节也需要重新上传整个 Object | 受限于单个设备的性能,访问越深的目录消耗的资源越大,操作拥有很多文件的目录也会很慢 |
一句话总结
在云时代特别是公有云时代,存储系统面对的数据规模急速增长(包括文件个数和文件大小),传统的文件系统受限于单个设备的能力(例如 HDFS 受限于 NameNode 的内存大小和处理速度),和树状存储固有的深层次目录、海量文件的索引消耗,已经不能满足需求。
在公有云时代,命名空间扁平化、扩展能力更好的对象存储成为主流,例如 Amazon S3、阿里云 OSS 等等。
Ozone 和 HDFS 中的一些概念类比
Ozone | HDFS |
---|---|
Volum | 一级目录,如 /volume1 |
Bucket | 二级目录,如 /volume1/bucket1 |
Object | 文件,如 /volume1/bucket1/obj1 |
无 | 多级目录 |
ListVolume | 获取一级目录列表 |
ListBucket | 获取二级目录列表 |
PutKey | 写文件 |
GetKey | 读文件 |
DeleteKey | 删除文件 |
无 | 修改文件内容 |
无 | 修改文件属性 |
无 | 重命名文件 |
Ozone 基本架构
两个工程
上图中出现了两个工程:hadoop-ozone-project 和 hadoop-hdds-project(hdds: Hadoop Distributed Data Store),实际上,这两个工程可以看做分别实现了 HDFS 中 NameNode 的个主要功能,在 HDFS 中,NameNode 有两个主要功能:
-
命名空间(即 FSNameSpace)管理
即管理 file -> blocks 的映射,在新架构下,类似的功能交给 OzoneManager 来负责,实现在 hadoop-ozone-project 中。 -
存储 block 管理
即管理 block -> datanodes 的映射,在新架构下,类似的功能交给 StorageContainerManager 来负责,实现在 hadoop-hdds-project 中。
在 HDFS 中,NameNode 作为核心管理节点,它的扩展性比较差,Federation 的方案实际使用的也不多,之所以造成这种情况,很大一部分原因就是它负责了太多的工作,在新架构下,为了提高扩展性,把 NameNode 的两个核心功能拆分出来,分别放在两个 project 里去做。
因此,实际上 hdds 并没有和 Ozone 绑定在一起,它只是提供了一个通用的存储管理层,Ozone 只是它的第一个用户而已,NameNode 经过改造后,也可以使用 Ozone 作为它的存储层支持,从而成为 hdds 的第二个用户,目前已经有相关的项目在推进了。
相关端口
角色 | 端口 | 用途 |
---|---|---|
OM | 9874 | OzoneManager Http 管理端口 |
OM | 9862 | OzoneManager RPC Server 端口 |
SCM | 9860 | StorageContainerManager RPC Server 端口 |
SCM | 9861 | StorageContainerManager 针对 DataNode 的 RPC Server 端口 |
SCM | 9863 | StorageContainerManager 针对 ScmBlockLocationProtocol 协议的 RPC Server 端口,该协议被 OM 使用,仅提供 block 的分配和删除功能 |
SCM | 9876 | StorageContainerManager http 管理端口 |
DN | 9880 | DataNode 数据 IO REST 端口 |
DN | 9858 | DataNode 数据 IO RPC 端口 |
Ozone 中的核心概念
hdds 中的几个核心概念
1. StorageContainerManager
作为 hdds 中的管理角色,它以独立进程的形式运行,需要管理所有 DataNode 上报的 container 信息,定期处理所有 DataNode 的心跳,并且还要响应来自 OzoneManager 的 RPC 请求(例如分配新的 block 等等),SCM 管理的数据主要包括每个 container 中的 block 信息以及每个 container replicate 在哪几个 DataNode 上等等,这些元信息都以本地数据库的形式保存(默认 RocksDB,可选 levelDB)。
2. DataNode
在 hdds 中,数据依然保存在 DataNode 上,每个 DataNode 上都需要运行一个相应的进程(类似于 HDFS 中的 DataNode 进程)来提供服务,目前这个进程名字叫做 HddsDatanodeService,它有两个职责:
- 向 SCM 注册自己,定期上报心跳,并接受 SCM 的管理。
- 和 client 之间,以 chunk 为单位进行数据读写。
3. container
hdds 中,DataNode 的基本切割单元变成了 container,默认大小为5G,这是一个更大粒度的划分,同时在 DataNode 之间也以 container 为单位进行多副本复制,DataNode 向 SCM 上报的基本单元也变成了 Container,这样一来,就大大的减少了 SCM 的管理压力(相对于 HDFS 中默认128M的管理粒度)。
4. block
container 又会划分为多个 block,在 OZone 中,和 HDFS 一样,文件也要被切割为一个个的 block,其中,文件的第一个 block 最大为 128M,后续的 block 最大为 256M。每当 Ozone 需要一个新的 block 时,都需要向 SCM 申请。
5. chunk
无论是5G 的 container,还是 256M 的 block,都不能作为 client 与 DataNode 之间的 IO 单位(因为粒度太大了),client 和 DataNode 之间进行 IO 的单位是 chunk,默认大小是 16M。
每一个 container 都需要保存自己目前写入了多少 chunk,每个 chunk 的名字、实际长度等信息也需要记录,这些元信息都以 RocksDB 的形式保存在每个 container 的存储目录下面,换句话说,在 hdds 中,container 自己就是一个缩小版的对象存储系统。
6. pipeline
pipeline 是一组 DataNode 的集合,假如系统配置三副本,那么一个 pipeline 就是三个 DataNode 的集合,每一个 container 都需要搭配一个 pipeline 来完成数据的写入和读取。
在 OZone 中,每个 DataNode 只能属于一个 Pipeline,假如系统是三副本并且只有三个 DataNode,那么实际上也就只存在一个 Pipeline,所有 container 都需要搭配这唯一的一个 pipeline 进行读写操作。
Ozone 中的 pipeline 相比 HFDS 中简单了不少,以默认的 RaftPipeline 为例,使用这种 PipeLine 写入和读取时,都按照 Raft 协议的读写方式来,即:
-
写
客户端将数据发送给 pipeline 中的 leader dn,leader dn 再将数据分发给所有的 follower dn,只有能达到大多数写成功,就认为此次写成功。 -
读
客户端直接从 pipeline 中的 leader dn 读取数据。
显而易见,这种方式可以很好的保证强一致性,使得 client 时刻能读到最新的数据,但是,读写都需要经过 leader dn 显然也会增大 leader 的压力(可以参照 ceph 中的 leader osd 做个类比)
Ozone 的几个概念
1. OzoneClient
类似于 HDFS 中的 DFSClient,是 Ozone 存储系统的客户端,目前,Ozone 提供 RPC 客户端和 REST 客户端,有相应的工厂方法获取对应的实现类。
2. OzoneManager
如上文所述,OzoneManager 负责命名空间管理工作,它负责的是一个 key -> blocks 的映射,以及 block 分配、删除等等工作,注意在 Ozone中,一个 block 和 必须从属于一个 container,他们有很强的绑定关系,即 blockId = containerId + localId,其中 localId 是一串随机字符。
OzoneManager 的元数据也以 rocksDB 的形式保存。
OZone 中典型操作时序图
两个前提
- 各个组件之间的 RPC 交互中,数据序列化使用 ProtoBuf,RPC 框架使用 gRPC,底层传输框架使用 netty,协议 http。
- 本文中的 client 特指 rpc client,使用 ozone 命令行时都是这个类型的 client,client 和 DataNode 之间的数据存取,同样是 Protobuf + gRPC + netty。
createVolume
listVolume
deleteVolume
createBucket
listBucket
deleteBucket
putKey
-
整个流程中,最重要的一步就是 allocateBlock,这是由 SCM 完成的,SCM 分三步来做这件事情:
-
找到一个可用的 pipeline
- 如果系统中有空余的 DataNode,那么优先选择空余的 DataNode,注意一个 DataNode 只能属于一个 pipeline。
- 如果没有,则选择一个现有的 pipeline(Round-Robin方式)
-
在该 pipeline 下,找到一个可用的 container
- 首先查看有没有预分配的 container 可用,SCM 默认一次分配 20 个 container。
- 如果没有,再看有没有正在写入的 container 可用,一个 container 写满 5G 后就会被关闭。
- 如果还没有,则新分配 20 个 container,返回其中一个。
-
从该 container 中分配一个 block
-
-
OM 向 SCM 申请 block 时,需指定这个 block 的 size,size 最大容量按照如下方式确定:
- 如果该 block 是文件的第一个 block,则其最大容量为 128M。
- 如果该 block 不是文件的第一个 block,则其最大容量为 256M.
-
client 向 DataNodes 写数据时
- IO 单位为 chunk,默认大小 16M。
- 通过 container 关联的 pipeline 写入,默认使用 Raft pipeline,传输层是 protobuf + gRPC + netty, Raft Pipeline 写入流程:
- client 将数据发送给 leader,一开始 client 并不知道 leader 是谁,因此会随机挑选一个 pipeline 中的 DataNode 发送数据,对方会回复他真正的leader 地址,接着 client 再重发一次,发给真正的 leader。
- leader 收到数据后,需要将数据分发给所有的 follower,只要能达到大多数,就认为此次写入成功。
- leader 回复 client 写入成功。
- client 并没有从零开始实现上面的 Raft 写入流程,而是集成了 Apache Ratis 这个项目,这是一个 Raft 协议的 Java 实现,Ozone 直接使用了它。
getKey
- 读取时存在预读机制,即 client 总是以 chunk 为单位从 DataNodes 读取数据。
- 读取时,client 直接从 leader dn 读取数据。
deleteKey
可以看到,deleteKey 是一个异步过程,client deleteKey 返回成功并不代表数据已经从 DataNode 上删除。
- OM 上有一个后台删除线程,定期扫描 OM DB,找出需要删除的 key,将 key 和相关的 block 发送给 SCM 进行删除。
- SCM 在追加一条本地删除日志,并且改写 SCM DB 后,向 OM 返回成功。
- SCM 上也有一个后台线程,定期扫描删除日志,并生成针对各个 DataNode 的删除 block 命令。
- SCM 上的心跳线程接收各个 DataNode 的心跳,并在回复中带上删除 block 命令,DN 收到命令后,真正删除数据。
网友评论