Kudu 很多情况下会被安装在现有的 Hadoop 集群上
尽管 Kudu 本身对 Hadoop 的任何其他组件没有依赖性,但 Kudu 几乎总是和 Impala 一起使用。Impala 依赖于 Hive,而 Hive 依赖于 HDFS,也就是说,如果要将 Kudu 和 Impala 放在一起使用,还要配上 Hive 和 HDFS。不过只要能正确配置好环境,Kudu 和 HDFS 是可以和谐共存的。
表会将其数据分成多个分区来存储,它们叫做 tablet。
表被分解成 tablet 后,会在多个 tablet 服务器上复制,这样表就被进一步分散到各个节点上。复制到各节点的 tablet 被称为副本(replica)。默认的复制因子为 3,也就是会保留 3 个副本。
master 服务器用于维护用户所创建所有表的元数据或目录信息。Kudu 创建了一个系统目录表以处理在 Kudu 中创建的各种对象的元数据。此表被设计为只有一个分区,也就是只有一个 tablet。
master 服务器之间和 tablet 服务器之间都根据 Raft 一致性算法以投票决策的方式选举各自的 leader。Raft 一致性算法是著名的 Paxos 一致性算法的一种变体。
由于 master 服务器的 tablet 只存元数据,所以它不会像存储用户数据的 tablet 服务器一样有很重的负载。它不会像将数据载入 tablet 服务器那样频繁地执行 DDL,它的表也不会像用户数据表一样增长到很大。因此 master 服务器对存储、内存和 CPU 的要求比 tablet 服务器小得多。
master 服务器的数目必须是奇数,这样可以保证最多在 (n-1)/2 个服务器发生故障时仍能提供服务。
一般配置 3 台或 5 台 master 服务器就完全足够。
系统目录表由 entry_type、entry_id 和 metadata 这三列组成。目录管理器将此表加载到内存中,并构造 3 个哈希表来支持目录信息的快速查找。
规划多少台 tablet 服务器可视情况而定。Kudu 使用各种编码和压缩策略,用类似于 Parquet 的列格式来存储数据。因此,从存储容量的角度,可以计算数据在 HDFS(或其他文件系统中)以 Parquet 格式存储时占用的空间,作为粗略测算 Kudu 存储容量的依据。
传统的 Hadoop 相关技术并不是为了有效地使用固态硬盘(SSD)而从头开始构建的。Kudu 则能有效利用 SSD 的性能,还可以使用 NVM Express(NVMe,一种快速的 PCIe 闪存适配器)。SSD 目前存储密度仍然不如硬盘驱动器(HDD),也就是说,在 SSD 的硬件配置情况下,整体的每节点存储密度是要低于 HDD 的。
较为合理的默认配置是,每个 tablet 服务器的磁盘容量应该规划为不多于 10 TB(包括 tablet 的所有副本存储)。tablet 服务器的数量最多为几千个。从容量角度来看,以下公式可用于测算所需 tablet 服务器的数量:
假设有以下一组数据
d = 120 TB # 以 Parquet 格式存储的数据集大小
k = 8 TB # 预计每个 tablet 服务器的最大磁盘容量
p = 25% # 预留的额外开销比例
r = 3 # tablet 的复制因子
那么计算方法为
t = (d / (k * (1 - p))) * r
t = (120 / (8 * (1 - 0.25))) * 3
t = 20
每次对表做的修改,最后都会导致 tablet 和其副本的修改,也会在 tablet 的预写日志(WAL)中写入一条条目(entry)。
Kudu 有一整套用于控制预写日志各属性的参数,包括日志段的大小以及与预分配存储相关的一些属性,比如是否异步分配存储。还有一些参数包括选用压缩编解码器、日志段最小保存段数和最大保存段数,保留的日志可用于其他副本在落后时同步数据。
WAL 是一个仅支持追加写的日志,然而 master 服务器或 tablet 服务器上的每个 tablet 都有自己的 WAL。如果有多个表要写入,从磁盘角度来看,对 WAL 的写操作更像是随机写模式。
如果从随机写负载的角度比较 HDD 和 SSD 的性能特征,SSD 有巨大的优势。HDD 每秒 I/O 操作数(IOPS)只有几百,而 SSD 则有数千到数万。SSD 的读/写延迟低于 100 μs,而 HDD 的延迟在 10 ms 范围内。这是巨大的差距。
因此,考虑到负载的类型,最好为 WAL 配置快速 SSD NVMe 的方案。
在容量方面,默认的日志段大小为 8 MB,最少要有 1 个,最多为 80 个。假设每台 tablet 服务器包含 2000 个 tablet。如果所有的 tablet 都同时写入,在最坏情况下,可能产生的日志段数据量为:
8 MB/日志段 * 最多 80 个日志段 * 2000 个 tablet = 1.28 TB
因此为此准备 1.3 TB 的快速存储器是比较合理的方案。
对于大型生产环境的部署,不建议将 WAL 设置到专用的 HDD 上或更糟的与其他服务共享的 HDD 上,因为这样会影响写入性能和故障的恢复时间。
各种存储介质性能差异很大,以下是对比:
存储介质 | IOPS | 吞吐率(MB/s) |
---|---|---|
HDD | 55-180 | 50-180 |
SSD | 3000-40000 | 300-2000(SAS 最大能达到 2812 MB/s) |
NVMe PCIe 闪存 | 150000-1000000 以上 | 最大为 6400(6.4 GB/s) |
上面的有些范围很宽,是因为有许多因素在起作用,例如快大小、读负载与写负载等。但可以确定的是,PCI 接口的存储在 IOPS 和吞吐率上都占有极大优势,适合作为 Kudu 的负载。
当涉及到用户数据的存储时,事情就更加简单。在服务器上提供尽可能多的可用 HDD 用来存储,当然有 SSD 更好。服务器可以随意地进行水平扩展,但目前数据还不能自动分布到集群新添加的服务器中。
如果希望在已经部署了 HDFS 的大数据集群中启用 Kudu,则可以把 Kudu 的存储目录配置在与 HDFS 完全相同的挂载点上。比如,有一个已分区和已格式化文件系统的磁盘挂载在 /disk1 上,其下有一个名为 /disk1/dfs 的目录,用来安装 HDFS 的 DataNode。那么你可以继续为 Kudu 数据创建一个名为 /disk1/tserver 的目录。
有些人会考虑是否要在服务器上专门为 Kudu 保留几个磁盘,然后将其他的磁盘用于 HDFS。这样虽然可行,甚至实际上还能提高性能,但并不建议这样做,因为这样会带来管理上的开销,需要处理扩展问题并检查哪些磁盘真正被有效利用了。
除了副本数据(即用户数据)之外,tablet 服务器还存储了元数据。元数据的写入目录是可配置的,将它们放置在具有高吞吐率和低延迟的性能最高的驱动器(如 SSD)上非常重要。在 Kudu 1.7 版本前,元数据写在 tablet 服务器数据目录列表的第一个目录;从 Kudu 1.7 版本开始,默认写入元数据的目录是由 WAL 目录指定的目录。但有一个新参数 --fs_metadata_dir
,用于给用户指定放置元数据的位置。
将元数据放在 WAL 或者非数据盘上是有好处的,因为这些数据会随着时间推移而增长,如果放在数据盘,则数据盘将随着这些数据的增长而变得不均衡。
为给定的表指定复制因子后,tablet 服务器将努力确保该表中的所有 tablet 采用该复制因子。
如果一个 tablet 服务器出现故障,副本的数据量可能会从 3 个减少到 2 个,Kudu 将迅速修复这些 tablet。
Kudu 主要采用被称为“3-4-3”的复制策略,即:如果一个 tablet 服务器出现故障,在剔除该失败的副本前,Kudu 会先添加替换的副本,然后再剔除失败的副本。
另一种策略被称为“3-2-3”。这种策略会立即剔除失败的副本,然后再添加新的副本。对于那种定期下线然后重新上线的系统,这样做会造成节点重新上线后要经过很长一段时间才能重新成为集群的成员。
在可能出现频繁服务器故障的环境中,复制策略对于维持集群稳定性很重要。只有在少数情况下 Kudu 会执行 3-2-3 策略,前提是其中一个 tablet 服务器经历的故障是不可恢复的。