HDFS3核心特性之Router初识(一)
HDFS3.x诞生伴随着几个重要的新特性GA, 其中有一个就是Router(RBF)
, 让我们先来看看它的来龙去脉, 整体的了解一下, 然后上手使用看看是什么效果.
0x00. 简述
在说Router(RBF)之前, 得先说一下NN和DN之间的前世今生, 因为Router是站在它们的肩膀上构建的.
1. NN与DN的关系
简单说, 这里说的就是HDFS0.2X, 单个NN时期, 独占DN的模式, 每个NN进程和DN进程之间是1:n
的关系, 集群受到单NN限制. 其他参考官方federation设计文档即可
这个模式下NN很容易就成为瓶颈, 那具体是什么瓶颈呢, 文尾有说.
2. Federation
最早在HDFS-0.23时, 社区就提出了”多NN的扩展性”的主题, 在HDFS2.x完全GA, 它主要是在DN端完成的, 并随之引入了一个重要的概念”块池“.
备注: 因NN在开启HA后, 可能有多个备用NN. 为避免混淆, 先说明一下, 下面常用NS(namespace)代指不同的NN.
引入Federation是为了解决NN的扩展性问题, 但它实际并没有对NN做多少改动, 主要做的事其实就是利用块池这个新的抽象层, 使不同NN复用同一批DNs, 间接实现了横向的扩展, 每个DN都需要给所有NN发心跳和RPC, 并接受NN的指令, 但是NN之间仍然是互不交流的, 如官方图所示:
Block Pool(块池)就是DN能对应多个NN的核心桥梁, 每个块池有一个唯一的ID (bpID), 并与一个NN对应起来, DN内部的关系简图如下:
graph TD N1(NS1) --blockPool--> R(BlockPoolManager) -.对应NS1.-> a(BPOfferService1) --> a1(BPServiceActor-Acitve) a(BPOfferService1) -.备.-> a2(BPServiceActor-Standby) N2(NS2) --blockPool--> R -.对应NS2.-> b(BPOfferService2) --> b1(BPServiceActor-Acitve) b(BPOfferService2) -.备.-> b2(BPServiceActor-Standby) subgraph namenodes N1 N2 end subgraph datanodeA R NS1 NS2 end subgraph NS2 b b1 b2 end subgraph NS1 a a1 a2 end
总结一下它解决的3个主要问题:
- 每个NN完全独立, 不易于水平扩展
- 不同的NN无法共享DN(进程), 资源利用率可能很低
- (业务)资源隔离
裸federation的缺点:
- 并不是真正NN级别的扩展, 不同NN之间仍然是完全不感知的
- 引入新的NN, 并不能直接减轻原有NN的压力, 只相当于一个存储扩展
- 客户端访问不同的NN需要单独维护映射关系
由于这些问题的存在, 就引出了后续的ViewFS
(问题3)和RBF
特性.
3. ViewFS
ViewFS(视图文件系统)并不是一个复杂的新FS实现, 它更像是原有FS上加的一个逻辑/抽象层, 把多个NS的文件路径和自己做一个统一的映射绑定, 从而使得客户端能通过ViewFS快速访问不同的NS路径 (类似电话簿/路由表), 但对它来说看起来还是一个整体(NS), 下面是社区提供的一张架构图:
最常见的使用场景, 就是解决有federation之后的多个NS访问麻烦的问题, 可以把它想成一个映射器, 规定了某个/path/to
对应的具体NN地址, 画个简图举例:
graph TD C(client) --default.fs--> C1(viewfs:///) --viewFS--> R(/home) -.view1.-> a(/home/dir1) --等价于--> a1(hdfs://nn1:port/home/dir1) R -.view2.-> b(/home/dir2) --等价于--> b1(hdfs://nn2:port/home/dir2) R -.view3.-> c(/home/dir3) --等价于--> c1(hdfs://nn3:port/home/dir3) subgraph NN3 c c1 end subgraph NN2 b b1 end subgraph NN1 a a1 end
所以viewFS也被大家理解为是一种Unix中挂载表(mount table)的概念, 通过它可以把同一Federation的NN挂载到一个大的虚拟NS中, 让客户端感觉像是在访问一个NS(后面提到的Router也是类似的含义). 那先简单了解一下viewFS的用途和结构, 详细配置等后面实践说.
3. Router
首先需要说明的是, Router(路由器)并不是HDFS官方的标准称呼, 它一般使用RBF(Router-Based Federation)来代指这个方案, 也是告诉大家, 它的实现是在已有的Federation
模式基础之上的. 只不过RBF说起来比较陌生, 简单起见就常用Router代指RBF功能.
顺便特别说明的是, 之前在2.x的federation时, 社区把一个/组HA-NN称为一个NS(Namespace), 而在router中又起了一个新的名字SubCluster
(子集群), 本质是一个意思. 另外配置文件或UI界面中使用的Nameservice是对应配置文件中dfs.nameservices
的, 绝大部分时候意思和SubCluster/Namespace
也是一样的.
它的几个主要作用:
- 取代
ViewFS
, 这是第一步 - 让客户端访问多个子集群/NS实现均衡负载
- 实现跨子集群/NS的balance, 让热点子集群可以迁移数据到新/冷子集群
目前作用2/3还没有GA, 不过社区已经提出了详细的实现方案, 预计HDFS3.5.x左右会完成. (在下一篇Router的笔记里会细说)
补充: 字节在社区版router发布前, 也开源了一个相对简易的版本nnproxy, 主要是把viewFS的挂载信息存储到ZK中, 集中去管理访问, 解决第一个问题.
0x01. Federation使用
引入Federation之后, 多个NS(NN)组成一个大的联邦, 我们也可称之为集群(Cluster), 对应的它有一个ClusterId, 可以理解为federationID
(个人理解)
1. NN配置
先来动手试试, 开启Federation对NN而言并不复杂, 为了简便NN就都不开HA了, 这样两个NN(NN1, NN2) 对应两个不同的sc(subCluster)
.
1 | <!-- Edit nn1's hdfs-site.xml --> |
然后格式化, 启动NN1, 再同样配置NN2, 修改一下属性值就行, 格式化的时候带上NN1的ClusterID, 表明加入同一个大集群/federation中.
1 | # 在NN2上配置好后, 格式化指定NN1的cid (可自定义一个易区分的. 比如bj-c1) |
2. DN配置
设置启动好NN1/NN2的配置, 再来配置DN的注册同步, 也很简单, 只需要把刚才在NN1/2上的hdfs-site.xml
配置同步到所有DN就行, 它通过nameservices
的具体配置决定和哪些NN进行注册和汇报.
完成后, 分别像NN1和NN2各写入100M和200M的数据,
3. UI界面 (≤2.5)
1 | # HDFS2.5之前可以在任意nn的页面查看整个集群(federation)的状态信息 |
下图是小改了一下的网上找到的一张留存UI图, 简单说是一个汇总集群NN信息的界面, 在HDFS2.5之后就被移除了, 高版应该是用Router的前端UI代替了, 这里官方文档应该更新一下, 会误导普通用户… (之后和社区确认一下..)
每个DN进程需要与2*m个NN通信 (假设NN开启HA)
4. 小问题
A. 不同的NN版本, 不同的DN版本之间可以采用federation么?
测试了一下3.1.2
和3.4
两个小版本的跨度, 发现可以共存, 但是UI页面会有置顶提示如下, 而且日志里也会有版本不一致提示.其他影响待测试, 是否可跨大版本也待测试. 估计是有些隐患的, 不建议生产跨版本使用.
1 | There are 2 versions of datanodes currently live:3.1.2 (1) ,3.4.0-SNAPSHOT (1) |
然后, 虽然Federation的设计和实现很早就提出了, 但基本只有大集群才会使用, 对于独立的业务或者小集群来说, 单个Namespace+HA的模式足矣满足需求, 当NN还没有出现明显的瓶颈前, 是不必采用federation机制的
0x02. ViewFS使用
刚已经组建好了两个不同NN的federation集群, 但是我们会发现虽然它们可以共用一个DN进程, 但是访问的数据却是完全分离的, 下面再来看看这个问题
1. 旧版本访问NN
在说ViewFS+Federation的组合之前, 先来看看HDFS1.x中的FS访问配置, 因为只有1个NN, 所以映射很简单:
1 | <!--如果不配置此参数, 则需完整URI访问--> |
然后我们用FShell
访问一个目录有几种写法, 殊途同归:
1 | # 1.使用相对路径访问 |
那在有多个federation之后, 就等于有了多个NN可能会被访问, 最原始的做法可以是大家各自使用不同配置文件:
1 | <!--A业务访问的NN1,配置文件A为如下--> |
这样每个业务访问自己单独的NN, 本质和之前无federation是一样的, 没有问题, 但是如果此时业务A想访问业务B的文件, 那就得指定B的完整URI了, 如下:
1 | # 跨集群拷贝文件, 完整URI方式 |
而且还有一个问题是, 这样对客户端来说, 每个NN的目录树都是完全独立的, 业务如果想在一个视图里看到所有NN的目录结构也是没法做到的.
为了解决以上两个主要的问题, federation的作者就同时引入了一个client端的新特性 —— ViewFS
2. ViewFS访问NN
详细的ViewFS的配置参考官方文档, 简单起见就用3个NN组成federation, 如[1.3](#3. ViewFS)的简图一样去映射, 然后Client访问配置修改core-site.xml
, 具体的配置解释参考源码的枚举LinkType
, 关于多NN挂载到同一点的实现参考HADOOP-12077.
1 | <!--挂载NN多的时候, 可抽取一个xml单独存viewFS的映射 --> |
然后这里单独用个简图说明一下多NS挂载的方式, 从设计文档看, 它可用在主/备集群的场景下, 多份写文件:
graph TD C(client)--viewFS--> R(/backup) -.linkNfly.-> a(/backup) --等价于--> a1(hdfs://nn1:port/backup) R -.linkNfly.-> b(/backup) --等价于--> b1(hdfs://nn2:port/backup) R -.linkNfly.-> c(/backup) --等价于--> c1(hdfs://nn3:port/backup) subgraph NN3 c c1 end subgraph NN2 b b1 end subgraph NN1 a a1 end
小思考: 挂载ViewFS后的目录的用户和组默认显示是什么? 和原本一致, 还是以挂载客户端用户为准?
3. ViewFS的局限性
ViewFS的优缺点都比较明显. 优点是实现逻辑简单, 在客户端的配置文件里添加映射, 就构成了一个”路由”指向不同的NN, 缺点有:
- 对客户端的重度依赖, 更新配置非常麻烦 (可统一通过http获取, 但一旦存储服务挂掉, 所有客户端都会不可用)
- 默认情况viewFS挂载过的目录的其他目录也需要挂载, 挂载过的目录的所有子孙目录不可被重新挂载 (存疑, 待确认)
mv(rename)
类操作如果跨NN就会被禁止- 有隐患和明显的兼容问题 (
viewfs://
不同于hdfs://
写法, 还需单独适配)
补充: 关于ViewFS
的源码阅读和分析, 暂不是目前重点, 所以略去, 需要单独补充.
0x03. RBF整体结构
作者的设计文档已经写得很详细了, 推荐优先阅读, 我做一些抽取和理解, 它由两个核心的模块组成:
- Router (处理请求)
- StateStore (数据存储)
- NS/SubCluster 信息
- Mount Table 信息
- Router 信息
然后看一下官方的整体设计图:
Router是一个单独的进程, 就和DN/NN一样, 可以独立存在:
- Router自身不存储数据, 可以认为是无状态的.
- 官方推荐一个NS/子集群对应一个/组Router(s), 你也可以单独放置(考量点是?)
- Router负责接收Client请求, 然后去StateStore查询映射/挂载信息, 转发给对应NN
- 每个NN都会定时给一个/组Router(s)发心跳, 从而感知NN状态和基本信息, 然后Router向StateStore发送心跳, 简图如下:
graph LR A(Namenode) -.心跳.-> B(Router) -.心跳.-> C(StateStore)
下面是官方Slide的一张很好的时序图: (稍加工)
StateStore可先参考这张图: (待优化)
然后总结一个细节对比表格:
功能 | Router | ViewFS | WebHDFS | 备注 |
---|---|---|---|---|
scheme前缀 | hdfs:// | viewfs:// | wehbhdfs://ip:http_port | 仅router可默认兼容 |
挂载信息存储方式 | 多种 | 配置文件 | 配置文件 | 多种: 本地/DBMS/ZK |
客户端配置 | 无 | 重 | 轻 | 包括更新难度 |
调用耗时 | 中等? | 无 | 高 | 映射耗时 |
缓存映射表 | 支持 | 支持 | 不支持 | |
权限设置 | 支持 | 不支持 | 不支持 | |
Quota设置 | 支持 | 不支持 | 不支持 | |
多NS挂载 | 支持 | 支持(*) | 不支持 | viewFS有限支持 |
Nameservice管理 | 支持 | 不支持 | 不支持 | router可下线NS |
跨子集群的balance | 进行中 | 不支持 | ? | 有多个方案 |
跨子集群的cp/mv | 进行中 | 不支持 | 不支持 | 有多个方案s |
安全验证 | 支持 | 不支持 | ? | 完善中 |
第三方存储系统 | 不支持 | 支持 | ? | 与S3/Ceph搭配 |
0x04.RBF小结
说Router功能之前, 先得说说之前NN有什么不能承受的痛, 主要是这两个:
- 单点的内存瓶颈, 本质是某一NS文件数过多
- 单点的RPC瓶颈, 本质是所有(读写)请求都打到了一台机器
然后, 对应这两个痛点, Router(RBF)用以下四大特性来应对解决:
- 替代ViewFS, 实现高效快捷的NS增减
- 引入多挂载策略, 其中
HASH/SPACE
策略友好的实现了新增数据的跨NS负载均衡 - 配合Standby一致性读 & Observe的Stale读, 让RBF作为NN之上的一层分流器, 解决单NS内的RPC瓶颈.
- 引入跨NS的balance和mv, 同时解决NN单点的内存/RPC瓶颈
其中1 & 2特性已经基本完成了, 3 & 4特性的核心设计和实现也浮出水面, 等这四个特性全完成, RBF就可以说很好的解决了NN的瓶颈, 实现了真正意义上的NN水平扩展, 而不是之前仅在DN层面的复用. 值得大家关注和期待!
至此, 整个Router(RBF)的核心架构/背景说明就告一段落了, 下一篇来具体说说Router的实际配置使用, 第三篇说一下另一个核心功能—-跨NS的负载均衡和mv设计实现.
备注: 学习和上手整个Router, 大部分图和配置参考自官方文档 & HDFS社区的PR和设计文档, 向前辈们表示感谢和敬意(e.g: Sanjay Radia, Suresh Srinivas, Íñigo Goiri), 前两位是HA + Federation + ViewFS
的主要贡献者, 最后一位是Router
的).
参考资料: