vlambda博客
学习文章列表

Apache Kudu在网易的实践

Java与大数据架构
7年老码农,10W关注者。【Java与大数据架构】全面分享Java编程、Spark、Flink、Kafka、Elasticsearch、数据湖等干货。
8篇原创内容
Official Account

本次的分享内容分成四个部分:


  1. 1.系统概述:认识kudu,理解Kudu的系统设计与定位

  2. 2.生产实践:分享网易内部的典型使用场景

  3. 3.遇到的问题:实际使用过程中遇到的问题和问题的排障过程

  4. 4.功能展望:对Kudu功能特性的展望

Kudu定位与架构

Kudu是一个存储引擎,可以接入Impala、Presto、Spark等Olap计算引擎进行数据分析,容易融入Hadoop社区。Kudu整合了随机读写和大数据分析能力,具有低延迟的随机读写能力和高吞吐量的批量查询能力。


与HBase、Casandra不同,Kudu要求声明Schema。Schema可以为上层计算引擎提供更多元数据,进行计算优化。Kudu的每个字段有主键、列名和列类型。拿到列类型信息后能够对不同列进行编码和压缩,优化存储空间,减少磁盘开销。Kudu支持bitshuffle、运行长度编码、字典编码等列编码方式,这些编码会根据列的类型不同做不同设计。比如对于重复值多、重复值变化不大的数据的压缩率很好。


Kudu使用列式存储给Kudu带来了如下特性:

1. 存储上可以节约空间

2. 可以对查询做更多优化,如将过滤条件下推到kudu执行,节约计算资源

3. 支持向量化操作


Kudu的Schema和列存

 

Apache Kudu在网易的实践

Kudu数据存储在Table中,Tablet是Kudu的读写单元,Table内的数据会划分到各个Tablet进行管理。


创建Table时,需要指定Table的分区方式。Kudu 提供了两种类型的分区方式range partitioning ( 范围分区 )  hash partitioning ( 哈希分区 ),这两种分区方式可以组合使用。分区的目的是把Table内的数据预先定义好分散到指定的片数量内,方便Kudu集群均匀写入数据和查询数据。范围分区支持查询时快速定位数据,哈希分区可以在写入时避免数据热点,可以适应各个场景下的数据。

Apache Kudu在网易的实践


Kudu有管理节点(Master)和数据节点(Tablet Server)。管理节点管理元数据,管理表到分片映射关系、分片在数据节点内的位置的映射关系,Kudu客户端最终会直接链接数据节点。

 

Apache Kudu在网易的实践


Kudu作为分布式系统,为了保障数据可用性和高可用,支持多副本。Kudu 使用 Raft 协议来实现分布式环境下副本之间的数据一致性。Raft算法数据不依赖其他存储和文件系统,优势在于可以保证服务高可用、服务可用性、一致性的均衡。

 

Kudu的update设计

 

Olap中对update的设计会影响到Olap性能。update操作可能引发数据多版本问题和update引发的数据merge问题。

 

Apache Kudu在网易的实践

Apache Kudu在网易的实践


Tablet是Kudu数据读写单元,Tablet下更细分的数据存储单元是 RowSet。RowSet有两种, 分别是MemRowSet 和 DiskRowSet,不同RowSet维护了不同组件范围内的数据。内存中的 MemRowSet 在到达一定大小后会刷盘成为DiskRowSet。


Apache Kudu在网易的实践

Apache Kudu在网易的实践

 

Kudu把更新操作当作一条新操作,而不是写一条新日志。更新操作是Undo/Redo记录,这些内存中的更新操作会被整合为DeltaMemstore持久化。Base数据、Undo数据、Redu数据写在同一个RowSet中。这样的存储设计优点是可以在更新时候快速找到数据,缺点是查询时需要确认查询的主键在哪个RowSet位置中。

 

Kudu也使用了LSM的结构。Kudu的comopaction有多种:MinorDeltaCompaction、MajorDeltaCompaction、MergingCompaction。

 

Apache Kudu在网易的实践

 

Kudu的update是一个多版本操作,目的是写入和读取时互相不干扰、不需要读时额外加锁。

小结


Kudu Update设计特点:

 

• ** 更新已经flush的数据和写入新数据走不通的处理逻辑,原始数据和更新位于同一个Rowset,不用跨Rowset进行merge**


• **通过base数据的RowID和更新时间戳作为REDO/UNDO数据的key**,读取更新高效


• Key大小固定,存储和比较效率高

• 不需要查询出主键数据也能获取更新数据


• 在大多数使用场景下能够实现更高效的读取


• 如果返回的结果不要求顺序,直接从RowSet中读出数据,不用merge


• 如果更新较少,REDO会快速merge到base数据,这时在读取最新数据时,可以不进apply REDO的操作

生产实践

实时数据采集场景


实时数据分析中,一些用户行为数据有更新的需求。没有引入Kudu前,用户行为数据会首先通过流式计算引擎写入HBase,但HBase不能支撑聚合分析。为了支撑分析和查询需求,还需要把HBase上的数据通过Spark读取后写入其他OLAP引擎。使用Kudu后,用户行为数据会通过流式计算引擎写入Kudu,由Kudu完成数据更新操作。Kudu可以支持单点查询,也可以配合计算引擎做数据分析。


Apache Kudu在网易的实践


维表数据关联应用

 

有些场景中,日志的事件表还需要和MySQL内维度表做关联后进行查询。使用Kudu,可以利用NDC同步工具,将MySQL中数据实时同步导入Kudu,使Kudu内数据表和MySQL中的表保持数据一致。这时Kudu配合计算引擎就可以直接对外提供结果数据,如产生报表和做在线分析等。省去了MySQL中维度表和数据合并的一步,大大提升了效率。

 

Apache Kudu在网易的实践

实时数仓ETL


Kudu作为分布式数据存储引擎,可以和Hadoop生态更好结合,因此在生产中我们采用了使用Kudu替换Oracle的做法,提升了扩展性。

 

Apache Kudu在网易的实践


ABTEST


在我们的ABTest业务中有两种日志,行为日志和用户分流日志。

 

 

Apache Kudu在网易的实践


架构升级前,我们采用了比较传统的模式,将用户行为日志和用户分流日志分别写入HDFS作为存储的ODS层,通过Spark做清洗、转换后导入HDFS作为存储的DWD层,再通过Spark进行一步清洗、按照时间或其他纬度做简单聚合后写入DWS层。

 

这个架构的问题是数据产出时间比较长,数据延迟在天级别。业务方需要更及时地拿到ABTest结果。

 

Apache Kudu在网易的实践

 

架构升级后,使用Kafka作为ODS、DWD层存储。Flink在ODS层数据的基础上继续做一层整理和过滤,写入DWD形成明细表数据;DWD层在Flink中做简单聚合后写入DWS层,Kudu在DWS层作为数据存储。

 

Flink开窗口实时修正实验数据,这一操作在Kudu完成;超出了Flink时间窗口的数据更新则由离线补数据的操作在Kudu中完成修正。

 

架构升级后,数据延迟大大降低,能够让ABTest业务方更实时地拿到结果。

我们遇到的问题

 

问题1: 节点负载不均衡

 

一些大表场景下会有负载不均衡问题。Kudu不会把range下的哈希分片当作一张表,而是把整个表的分片当成了平等的表进行处理。而在真实使用场景中,range基本是时间字段;需要让range的hash分片更均匀地分布在各节点上,防止数据倾斜。下图是数据倾斜的情况展示:

 

Apache Kudu在网易的实践


 

我们的解决方案是实现了一套优化版本的负载均衡算法,这个算法能够把range表当作单独的表做负载均衡,解决了数据倾斜。下图是优化后效果:

 

 


问题2: 表结构设计复杂


问题3: 没有二级索引,只能通过控制主键顺序和分区键来优化某几种查询模式


问题4: 创建表时需要根据业务场景专门设计表结构

 

问题2-4,对业务方要求比较高,经常需要专人介入引导业务方导入数据。为了解决问题,我们内部设计了二级索引来解决上述问题。二级索引可以满足查询性能的要求,同时减少用户设计表时候的复杂度:

 

  • 通过支持二级索引来优化包含非主键列过滤的查询

  • 支持二级索引能够降低业务设计表结构的复杂度

  

社区对二级索引的支持进度KUDU-2038:Add b-tree or inverted index on value field

Kudu功能展望

BloomFilter


BloomFilter成本较低、效率较高。Join场景下,小表动态生成BloomFilter下推到存储层,防止大表在Join层做数据过滤。最近的Kudu中已经支持了BloomFilter作为过滤条件。

灵活分区哈希


Kudu每个range的hash bucket数量是固定的。考虑到时间和业务增长,在项目实施前期阶段要给Kudu哈希桶数量设置略大,但是数据量较小的场景下过大的分片个数对资源是一种浪费,社区也不推荐hash bucket设置得比较大。期望后续Kudu可以更灵活地适配hash bucket数。

 > KUDU-2671:Change hash number for range partitioning 

多行事务


Kudu暂时不能支持多行事务。目前更新主键需要业务自己实现逻辑检测。

> KUDU-2612:Implement multi-row transactions

Flexible Schema


一些业务场景下业务没有唯一主键,但只希望利用Kudu的大批量写入、聚合分析查询的特性。接入业务时Kudu对Schema的要求比较高,一些业务场景无法支持。

> KUDU-1879:Support table without a primary key

 

嘉宾介绍:

闵涛,网易资深数据开发工程师。拥有多年分布式存储系统设计和开发经验,现负责网易大数据平台分布式存储系统的开发。

编辑整理:张德通

Java与大数据架构
7年老码农,10W关注者。【Java与大数据架构】全面分享Java编程、Spark、Flink、Kafka、Elasticsearch、数据湖等干货。
8篇原创内容
Official Account