背景
Observer NameNode 可以处理客户端的读请求,以此来分担 Active NameNode 的压力,从而整体上提升 NameNode 的处理能力,具体能提升多少,需要测试。
分场景性能测试
全写场景
这种情况下,所有 RPC 请求都会发送给 Active NameNode 处理,Observer NameNode 闲置,对性能无提升。
全读场景
这种情况下,所有 RPC 请求都会发送给 Observer NameNode 处理,Active NameNode 闲置,最终还是单 NN 处理了所有请求,同样对性能无提升。
混合读写场景
这是 OBNN 真正发挥作用的场景。
-
测试模拟
50线程并发 create+close 创建1500W 个文件 + 100线程并发 open+close 读取6000W 次文件
,统计耗时情况。这大致上模拟了一个极高负载的现网集群典型的一小时 NN RPC 吞吐量,即:- 总 RPC 处理量:7500W 左右。
- 读写比例 4:1 左右。
-
测试机器配置
使用现网三台空闲机器进行测试,其配置如下,另外,NN、JN 的 JVM 参数也和现网保持一致。项目 取值 CPU 80核 Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz 内存 376G 磁盘 1.3TB SATA * 2 网卡 50Gb(由两块 25Gb 的物理网卡聚合而成) NN handler count 256 NN Reader count 4 NN EditLog 目录、JN EditLog 目录 务必配置在不同的磁盘,减少互相影响 Hadoop 版本 Hadoop 3.2 -
测试结果
场景 耗时(分钟) 典型 HA 部署(一主一备) 36.46 min 典型 OBNN 部署(一主一备一OBNN) 26.20 min OBNN 相比 HA 性能提升 +28% 测试结论
在只设置一个 OBNN 的情况下,NameNode 整体吞吐量提升 28%,如果额外设置更多的 OBNN,则 NameNode 的吞吐量还会提升更多。
ObserverNamenode 部署细则
HDFS 集群配置项
- OBNN 特性需要 NN 和 JN 的配合,因此,下面的配置项需要同步到所有 NN 和 JN 机器上,并依次重启 JN、NN 进程。
- 启用 NameNode state id,这是 OBNN 的基础条件
示例如下:
<property>
<name>dfs.namenode.state.context.enabled</name>
<value>true</value>
</property>
- 启用 NN 和 JN 的 Fast tail EditLog 特性
示例如下:
<property>
<name>dfs.ha.tail-edits.in-progress</name>
<value>true</value>
</property>
- 配置 OBNN/SBNN 不间断从 JN 集群轮询 EditLog
示例如下:
<property>
<name>dfs.ha.tail-edits.period</name>
<value>0ms</value>
</property>
- 配置当 JN 集群暂无可用 EditLog 时,SBNN/OBNN 的最大指数退避时间,建议为10s
示例如下:
<property>
<name>dfs.ha.tail-edits.period.backoff-max</name>
<value>10s</value>
</property>
- 配置 JN 的 EditLog cache 大小,该值默认为 1M,根据现网机器性能和 JN 负载情况,这个值建议为 1G
示例如下:
<property>
<name>dfs.journalnode.edit-cache-size.bytes</name>
<value>1073741824</value>
</property>
计算集群配置项
- 重新配置
dfs.client.failover.proxy.provider.<nameservice>
这个选项针对每个 HDFS 集群分别配置,对于一个启用了 OBNN 的 HDFS 集群,需要配置为org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider
。
举例:在客户端侧,针对 ns1 集群进行配置:
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ObserverReadProxyProvider</value>
</property>
- 配置客户端随机选取 OBNN
在集群中有多个 OBNN 时,这个配置很关键,需要将dfs.client.failover.random.order
配置为 true。
举例如下,在客户端侧进行配置:
<property>
<name>dfs.client.failover.random.order</name>
<value>true</value>
</property>
- 打开客户端的自动 msync 机制,用来兜底客户端的等待时间。
这对客户端来说是一个兜底机制,用来限制最差情况下客户端需要等待多久,才能从 OBNN 读取到准确的内容。建议开启这个机制。同样,这个配置也需要针对每一个 HDFS 集群单独配置,配置项为dfs.client.failover.observer.auto-msync-period.<nameservice>
,建议配置为 10s。
举例:在客户端侧,针对 ns1 集群进行配置:
<property>
<name>dfs.client.failover.observer.auto-msync-period.ns1</name>
<value>10s</value>
</property>
Observer NameNode 和 Active NameNode 的距离
这个是我们特别关心的一个值,代表了 OBNN 追赶 ANN 所需要的耗时,即下面这个流程的耗时,它也直接决定了 OBNN 和 ANN 的距离:
ANN 执行写操作完成并将 EditLog 写到 JN 集群 -> OBNN 从 JN 集群拉取到 EditLog -> OBNN 将 EditLog 应用到自身
目前的话,在软件层面,通过各种措施和优化,这个间隔几乎已经被压缩到了极限。因此,这个间隔的最终值,基本取决于 NN 机器性能、JN 机器性能、网络性能等等硬件指标。
-
测试方式
- 客户端 create 一个文件。
- 根据 Active NN 的 StateChange 日志,确定 Active NN 关闭完毕这个文件的时间。
- 根据 Observer NN 的 EditLog apply 日志,确定 Observer NN 应用完这个文件的关闭操作的时间。
- 两个时间点的距离,就是 Observer NN 和 Active NN 的距离。
-
测试结果
-
正常情况下,这个距离在 1s 以内(实际在 10ms 左右),如下:
ANN 关闭文件时间点:
OBNN 应用 EditLog 时间点:
-
最差情况下,这个距离在 5s 以内(实际在 3s 左右),如下:
ANN 关闭文件时间点:
OBNN 应用 EditLog 时间点:
-
常见问题
3.x 的 NameNode,搭配 2.x 的 JournalNode,是否可以使用 OBNN 特性?
OBNN 需要 NN 和 JN 搭配使用,因此,只有等到 OBNN 特性合入 2.x,才能够与 3.x 的 NN 搭配启用 OBNN。集群中可以有几个 OBNN?
OBNN 和 SBNN 一样,都可以有任意多个,对于一个读负载非常重的集群,可以考虑设置2个或2个以上的 OBNN,此时,客户端将随机选择 OBNN 进行访问(需在客户端配置dfs.client.failover.random.order
为 true)。如果集群中 OBNN 出现问题(例如突然挂掉),客户端如何处理?
和 HA 模式一样,客户端需要根据错误类型,决定是直接失败,还是failover,还是 retry。但注意:在需要 failover 的情况下(例如因为网络问题导致调用失败),客户端最终会将 ANN 作为一个保底的对象,进行最后的尝试。-
假如客户端针对某个 HDFS 集群配置了 ObserverReadProxyProvider,但目标集群中并没有 Observer NameNode,此时会怎么样?
需要分情况:目标 HDFS 集群是 3.x 版本
客户端 fallback 到正常的 HA 模式。目标 HDFS 集群是 2.x 版本
出错,ObserverReadProxyProvider 不可避免地会使用一些 2.x 不支持的 RPC 请求(比如 msync ),从而导致客户端出错退出。