Apache Kudu 对频繁更新数据场景下的大数据实时分析最佳用例
由于最近两次在大数据项目中使用Apache Kudu,写一篇文章谈谈对Kudu的一些看法和使用心得。
一.对大规模数据实时分析的商业价值
几乎所有的企业都有随着时间推移贬值的资产。直观地说,延长使用设备会降低设备的价值,如我们日常生活中的汽车、电子产品等。然而,数据通常不被视为随时间失去价值的资产,这种想法是错误的。
虽然可能不是会计部门可以支付的费用,但是在可能导致更好的行动过程的时间段内,业务数据将失去价值。无论数据是否告诉您进行预测性维护,利用市场机会,甚至防止各种欺诈,机会对数据采取行动的窗口往往都可能很小。这就是为什么实时数据和对实时数据的分析对于确保您的业务充分发挥潜力至关重要。
考虑到随着时间的推移,数据贬值的点,有一组用例依赖于实时分析所提供的洞察力,以便在机会仍然存在时采取行动。这些用例是时间序列数据,机器数据分析和在线报告等。
Kudu 是 Cloudera 开源的结构化数据的开源数据存储引擎,是 Apache Hadoop 生态圈的新成员之一,支持低延迟随机访问的数据查询以及高效的批量扫描数据的数据分析。 Kudu使用水平分区分发数据,并使用 Raft协议复制每个分区,提供较低的平均恢复时间和较低的尾部延迟。 Kudu 是在 Hadoop生态系统的环境中设计的,并通过诸如Apache Impala ,Apache Spark 和 MapReduce 等工具支持多种访问模式。
三.Apache Kudu诞生的背景
在Cloudera官方网站上,对于Kudu的描述是:一个弥补HDFS和HBase之间的缺口的新型的数据存储引擎,它能够更有效的利用现代硬件的CPU和IO资源,既能够支持分析,又能够支持更新、删除和实时查询。
在Apache Kudu出现之前,大数据主要以两种方式存储:
静态类型数据:通常以Parquet/Carbon/Avro形式直接存放在HDFS中,适用于高吞吐量的离线大数据分析场景。但无论以哪种方式存在于HDFS中,都难以支持单条记录级别的更新,随机读取也并不高效。
动态类型数据:以 HBase、Cassandra等作为数据存储引擎,因为它们能够支持记录级别的高效随机读写。但这种存储却并不适合离线分析场景,因为它们在大批量数据获取时的性能较差。
从上面分析可知,这两种数据在存储方式上完全不同,进而导致使用场景完全不同,但在真实的场景中,边界可能没有那么清晰,面对既需要随机读写,又需要批量分析的大数据场景,该如何选择呢?这个场景中,单种存储引擎无法满足业务需求,大部分公司经常通过多种大数据工具组合来满足这一需求,一个常见的方案是:
该方案可以满足数据更新+随机查询+批量分析的业务需求。
如上图所示,数据实时写入 HBase,实时的数据更新也在 HBase 完成,为了应对 OLAP 需求,我们定时(通常是 T+1 或者 T+H)将 HBase 数据写成静态的文件(如:Parquet)导入到 OLAP 引擎(如:HDFS)。这一架构能满足既需要随机读写,又可以支持 OLAP 分析的场景,但存在如下缺点:
(1)如何处理某一过程失败?
(2)从HBase将数据导出到文件,频率多少比较合适?
(3)当生产报表时,最近的数据如何体现在查询结果上?
(4)维护集群时,如何保证关键任务不失败?
(5)Parquet 是 immutable 的,因此当HBase 中数据变更时,往往需要人工干预同步。
(6)架构复杂。从架构上看,数据在 HBase、消息队列、HDFS 间流转,涉及环节太多,运维成本很高。并且每个环节需要保证高可用,都需要维护多个副本,存储空间也有一定的浪费。最后数据在多个系统上,对数据安全策略、监控等都提出了挑战。
(3)在线报告
传统上,在线报告(如操作数据存储)受到数据量和分析能力的限制。保持数据的悠久历史是非常昂贵的,分析能力是数据仓库的领域。对于在线报告,Kudu可以实时存储,保存所有历史数据,并提供低延迟随机查询与批量扫描数据分析。
二.Apache Kudu的概要介绍
Kudu 是 Cloudera 开源的结构化数据的开源数据存储引擎,是 Apache Hadoop 生态圈的新成员之一,支持低延迟随机访问的数据查询以及高效的批量扫描数据的数据分析。 Kudu使用水平分区分发数据,并使用 Raft协议复制每个分区,提供较低的平均恢复时间和较低的尾部延迟。 Kudu 是在 Hadoop生态系统的环境中设计的,并通过诸如Apache Impala ,Apache Spark 和 MapReduce 等工具支持多种访问模式。
三.Apache Kudu诞生的背景
在Cloudera官方网站上,对于Kudu的描述是:一个弥补HDFS和HBase之间的缺口的新型的数据存储引擎,它能够更有效的利用现代硬件的CPU和IO资源,既能够支持分析,又能够支持更新、删除和实时查询。
在Apache Kudu出现之前,大数据主要以两种方式存储:
静态类型数据:通常以Parquet/Carbon/Avro形式直接存放在HDFS中,适用于高吞吐量的离线大数据分析场景。但无论以哪种方式存在于HDFS中,都难以支持单条记录级别的更新,随机读取也并不高效。
动态类型数据:以 HBase、Cassandra等作为数据存储引擎,因为它们能够支持记录级别的高效随机读写。但这种存储却并不适合离线分析场景,因为它们在大批量数据获取时的性能较差。
从上面分析可知,这两种数据在存储方式上完全不同,进而导致使用场景完全不同,但在真实的场景中,边界可能没有那么清晰,面对既需要随机读写,又需要批量分析的大数据场景,该如何选择呢?这个场景中,单种存储引擎无法满足业务需求,大部分公司经常通过多种大数据工具组合来满足这一需求,一个常见的方案是:
该方案可以满足数据更新+随机查询+批量分析的业务需求。
如上图所示,数据实时写入 HBase,实时的数据更新也在 HBase 完成,为了应对 OLAP 需求,我们定时(通常是 T+1 或者 T+H)将 HBase 数据写成静态的文件(如:Parquet)导入到 OLAP 引擎(如:HDFS)。这一架构能满足既需要随机读写,又可以支持 OLAP 分析的场景,但存在如下缺点:
(1)如何处理某一过程失败?
(2)从HBase将数据导出到文件,频率多少比较合适?
(3)当生产报表时,最近的数据如何体现在查询结果上?
(4)维护集群时,如何保证关键任务不失败?
(5)Parquet 是 immutable 的,因此当HBase 中数据变更时,往往需要人工干预同步。
(6)架构复杂。从架构上看,数据在 HBase、消息队列、HDFS 间流转,涉及环节太多,运维成本很高。并且每个环节需要保证高可用,都需要维护多个副本,存储空间也有一定的浪费。最后数据在多个系统上,对数据安全策略、监控等都提出了挑战。
(7)时效性低。数据从HBase导出成静态文件是周期性的,一般这个周期是一天或一小时,在时效性上不是很高。
(8)难以应对后续的更新。真实场景中,总会有数据是「延迟」到达的。如果这些数据之前已经从 HBase 导出到 HDFS,新到的变更数据就难以处理了,一个方案是把原有数据应用上新的变更后重写一遍,但这代价又很高。
为了解决上述架构存在的问题,Cloudera公司开发了Kudu,kudu 的定位不是取代HBase,而是Fast Analytics on Fast Data,是一个既支持随机读写数据查询的业务、又支持批量扫描数据的实时分析的大数据存储引擎。
四.基于Apache Kudu 对频繁更新数据场景下的大数据实时分析
(1)为什么有了HBase还需要Kudu?
首先,清楚以下几点是很重要的。
1)Kudu的定位绝不是取代HBase,而是以降低写的性能为代价,提高了批量扫描数据的性能,使其能够实现快速在线分析业务。
2)一个大数据存储引擎设计的初衷都是源于具体的业务场景,用来解决具体业务问题,没有能应对所有业务场景的大数据存储引擎。
3)HBase,可以进行高效随机读写,却并不适用于基于SQL的数据分析方向,大批量数据获取时的性能较差。
4)HBase不适合做批量扫描数据分析的原因是:HBase本身的设计并不适合批量获取数据,都说HBase是列式数据库,其实从底层存储的角度来说它并不是列式的,获取指定列数据时是会读到其他列数据的。相对HBase而言,Parquet格式针对分析场景就做了很多优化。HBase是LSM-Tree架构的数据库,这导致了HBase读取数据路径比较长,从内存到磁盘,可能还需要读多个HFile文件做版本合并。LSM 的中心思想就是将随机写转换为顺序写来大幅提高写入操作的性能,但是牺牲了部分读的性能。
5)Kudu不及HDFS批处理快,也不及HBase随机读写能力强,但是反过来它比HBase批处理快(适用于OLAP的分析场景),而且比HDFS随机读写能力强(适用于实时写入或者更新的场景),这就是Kudu存在的根本意义。
(2)为什么不能想办法改进HBase呢?
Kudu 的很多特性跟 HBase 很像,它支持索引键的查询和修改。 Cloudera公司也曾经想过基于 HBase 进行修改,将HBase修改成既合适随机访问数据的查询,又合适做批量数据扫描的数据分析平台,然而结论是对 HBase 的改动非常大, Kudu 的数据模型和磁盘存储都与 HBase 不同。 HBase 本身成功的适用于大量的其它场景,因此修改 HBase 很可能吃力不讨好。最后 Cloudera 决定开发一个全新的存储系统。
(3)技术路线
1)Single DataProcess RealTime System
2)Complex DataProcess Mixed System
(4)Kudu使用最佳实践
Kudu表结构设计最佳实践
1)字段设计
①字段数量最好不要超过300个。
②除主键外,其他字段可以为空。
③每一个字段均可以设置自己的编码以及压缩方式。
④Kudu1.7.0及其高版本,已经支持Decimal字段类型,适用于金融和特定的算数运算场景。
2)主键设计
①建表必须包含主键,主键字段必须列在Schema的最前端。
②建表后,主键无法更改,只能重建表。
③不支持自增列。
④主键不能为空,并且不能为boolean、float或者double类型。
⑤主键的值无法被更新,但是可以被DELETE后,re-INSERT。
⑥主键即索引,tablet中的所有行都按照主键排序。查询时,对主键指定相等或范围的谓词,Kudu扫描表的时候会过滤掉不满足条件的行。
3)分区设计
①不允许您更改创建后如何分区表,但可以添加或删除范围分区。
②分区方式:哈希分区、范围分区以及多级分区。
③根据自身业务场景,选择合适的分区方式,让读与写操作在所有tablet server上均匀分布。
④根据应用查询的语句,设计合理的主键以及分区,保证读取数据时扫描最小的数据集。
⑤分区数量的设置,根据官方文档,每个分区的大小尽量控制在4G左右(单个tablet server最大存储8T/管理的tablets数量最大2000个≈4G),
如果你的表数据量未来估算会在40G左右,那么你的分区数量可以设置10个。
Impala与KuduClient场景选择最佳实践
①就查询来说,Impala 的查询速度要快于 Kudu Client 的 Scan数据扫描,建议使用Impala。
②insert 的速度都很快 upsert/update/delete 如果用主键的话也都很快,但Impala的并发性能比较差,所以这种操作尽量用 Kudu Client 的原生API进行操作。
③Kudu Client原生 API中update、delete、upsert 只能根据主键操作,如果需要其他条件则需要查询一下,拿到主键再进行操作,所以不如impala写sql方便,如果同时使用Impala和Kudu Client最好做资源隔离。
④Kudu Client原生 API 在操作上有些不方便,我们可以自己封装了一个基础调用层。
Kudu随机写压力场景最佳实践
对于写压力比较大的业务场景,最重要的一点是把写压力均匀分担到不同的tablet分片中,这种场景下切片设计通常采用hash partitioning,hash切片拥有良好的随机性。相比HBase而言,Kudu的架构可以轻松应对随机写的场景。
Kudu随机读压力场景最佳实践
对于随机读压力比较大的业务场景并不是很建议使用Kudu,通常情况下HBase是一个更好的选择,不过Kudu也拥有不错的随机读性能。Kudu官方的性能测试,在读压力分布符合齐夫定律时,HBase有读性能优势,随机分布下,Kudu和HBase的的随机读性能相当。不过通常情况下业务场景的读分布符合齐夫定律,也就是我们常说的28原则,80%的读集中在20%的数据上。如果用Kudu的业务场景确实随机读压力较大,则通常采用hash partitioning。
Kudu小范围Scan场景最佳实践
对于拥有大量小范围Scan的业务场景,比如扫描一个店铺的所有商品,比如找到一个用户看过的所有商品,诸如此类的业务场景最好将同一个Scan所需要的数据放置在同一个tablet里面。比如按店铺id做hash,可以把同一个店铺的所有信息放置在同一个tablet里。按userid做hash,可以把一个用户的所有信息放置在同一个tablet里面。
Kudu大范围Scan场景最佳实践
如果业务场景的Scan所需要扫描的数据量比较大,又想这类Scan跑的快,则需要把这类Scan所需要的数据分布到多个tablets里面,充分利用多机分布式计算能力。假设我们有一个表存储了最近12个月的数据,一个设计方案是按照月来切片,一共12个tablet,但如果大部分BI查询对应的Scan只需要最近1个月的数据,则这种设计便不合理,因为Scan的压力全部集中到了一个tablet之中。这种情况下一个更好的设计方案是按月切片再按hash切片,具体方案后续再详细分析。
(5)Kudu的性能优化
Kudu API性能调优
1)尽量采用 MANUAL_FLUSH, 性能最好, 如果有写入Kudu错误, flush()函数就会抛出异常, 逻辑非常清晰。 2)在性能要求不高的情况下, AUTO_FLUSH_SYNC 也是一个很好的选择。 3)仅仅在测试环境下使用 AUTO_FLUSH_BACKGROUND, 不考虑异常处理时候代码可以很简单, 性能也很好. 在生产环境下不推荐使用的原因是: 插入数据可能会是乱序的, 一旦考虑捕获异常代码就很冗长。
(6)Kudu使用过程中遇到的坑点
1)时钟服务NTP配置不合理,会导致Kudu服务直接崩溃,建议根据官方的推荐来配置NTP,另外可以通过修改参数max_clock_sync_error_usec值,来提高Kudu对时间偏差的容忍程度。
2)在Impala中对Kudu表进行alter table A rename to B,只会更改impala的元数据,而不会更改任何Kudu的元数据,可以通过先修改Impala元数据alter table A rename to B 后,再修改Kudu元数据alter table A set TBLPROPERTIES(’kudu.table_name’=’B’)。
3)没有Rebalance功能,需要手工来做balance。
4)在Kudu1.6.0之前,如果tablet server的某个磁盘坏了,那么整个tablet server就要重新format了,如果你的集群版本大于等于1.6.0并且损坏的盘并非WAL/Meta盘,那么你可以通过kusu fs update_dirs。