UDN-企业互联网技术人气社区

板块导航

浏览  : 1371
回复  : 0

[其它] Kafka和Twitter新开源的DistributedLog技术对比

[复制链接]
胭脂粉的头像 楼主
发表于 2016-10-14 10:45:04 | 显示全部楼层 |阅读模式
1.png



  我们在2016年五月开源了DistributedLog项目,引起了社区的广泛关注。大家常常问起的问题之一就是DistributedLog与ApacheKafka相对比,各有什么优劣。

  从技术上来讲DistributedLog并不是一个象ApacheKafka那么成熟的、有分区机制的广播/订阅系统。DistributedLog是一个复制日志流仓库,它用ApacheBookKeeper来做日志分区仓库。它关注的是构建可靠的实时系统所需要的持久性、副本和强一致性。可以把DistributedLog用于构建或尝试各种不同的消息通信模型,比如队列、广播/订阅等。

  因为两者都是处理日志,数据模型也类似,所以这篇文章主要从技术角度讨论ApacheKafka与DistributedLog的不同点。我们会尽量做到客观,但由于我们不是ApacheKafka的专家,因此我们可能会对ApacheKafka存在误解。如果发现有错,也请大家直接指出。

  首先,让我们简单地介绍一下Kafka和DistributedLog的概况。

  Kafka是什么?

  Kafka是最初由Linkedin开源出来的一套分布式消息系统,现在由Apache软件基金会管理。这是一套基于分区的发布/订阅系统。Kafka中的关键概念就是Topic。一个Topic下面会有多个分区,每个分区都有备份,分布在不同的代理服务器上。生产者会把数据记录发布到一个Topic下面的分区中,具体方式是轮询或者基于主键做分区,而消费者会处理Topic中发布出来的数据记录。所有数据都是发布给相应分区的主代理进程,再复制到从代理进程,所有的读数据请求也都是依次由主代理处理的。从代理仅仅用于数据的冗余备份,并在主代理无法继续提供服务时顶上。图一的左边部分显示了Kafka中的数据流。

  DistributedLog是什么?

  与Kafka不同,DistributedLog并不是一个基于分区的发布/订阅系统,它是一个复制日志流仓库。DistributedLog中的关键概念是持续的复制日志流。一个日志流会被分段成多个日志片段。每个日志片段都在ApacheBookKeeper中存储成ApacheBooKeeper中的一个账目,其中的数据会在多个Bookie(Bookie就是ApacheBookKeeper的存储节点)之间复制和均衡分布。一个日志流的所有数据记录都由日志流的属主排序,由许多个写入代理来管理日志流的属主关系。应用程序也可以使用核心库来直接追加日志记录。这对于复制状态机一类对于顺序和排他写有着非常高要求的场景非常有用。每个追加到日志流末尾的日志记录都会被赋予一个序列号。读者可以从任何指定的序列号开始读日志流的数据。读请求也会在那个流的所有存储副本上做负载均衡。图一的右半部分显示了DistributedLog中的数据流。

2.png


  图一:ApacheKafka与ApacheDistributedLog

  Kafka与DistributedLog有什么不同?

  因为同类事物才有可比较的基础,所以我们只在本文中把Kafka分区和DistributedLog流相对比。下表列出了两套系统之间最显著的不同点。

  KafkaDistributedLog

  数据分片与分布Kafka分区中的数据存储在若干个代理服务器上,每个代理服务器中的数据都在本地被切分成多个分区文件。一个DistributedLog流的数据被分成多个日志分片,日志分片被均匀分布在多个存储节点上。

  数据持久化数据在超过配置的保留时间之后会被删除,或都被压缩,即只保留单个主键的几个最新值。数据可以在超过配置的保留时间之后被删除,或者直接把某个位置之前的日志清除掉。

  写操作通过代理服务器可以并行写入。通过写入代理可以并行写入,通过核心库只能串行写入。

  读操作从主代理服务器上读出。可以从任何有数据的存储节点上读出。

  数据复制ISR(In-Sync-Replica,同步副本)复制:主和从都是代理服务器。Quorum投票复制:主是写入代理,从是Bookie。

  复制修复通过增加新的副本来从主代理服务器上拷贝所有数据。通过Bookie的自动恢复机制来保证复制因子。

  集群扩展增加新代理服务器时需要重新分配分区,以使得整个集群负载均衡。要严密跟进每个分区的状态,保证迁移操作不会占满网络和磁盘I/O。增加写入代理或Bookie时不需要做数据重分布,新的日志分区会自动分配到新加入的Bookie上。

  存储每个分区中存储文件(文件的集合)。交错存储格式。

  持久性只写到文件系统的页缓冲中。可以配置只等待主的确认,或者等待所有副本的确认,才认为写入是成功的。所有写入操作都是通过显式的fsync操作持久化到硬盘上的。等到超过配置数量的Bookie的确认之后才认为写入是成功的。

  I/O隔离没有物理I/O隔离,依靠文件系统缓冲。有物理I/O隔离,读写在不同磁盘上。

  数据模型

  Kafka分区是存储在代理服务器磁盘上的以若干个文件形式存在的日志。每条记录都是一个键-值对,但对于轮询式的数据发布可以省略数据的主键。主键用于决定该条记录会被存储到哪个分区上以及用于日志压缩功能。一个分区的所有数据只存储在若干个代理服务器上,并从主代理服务器复制到从代理服务器。

  DistributedLog流是以一系列日志分片的形式存在的虚拟流。每个日志分片都以一条BookKeeper账目的形式存在,并被复制到多个Bookie上。在任意时刻都只有一个活跃的日志分片接受写入请求。在特定的时间段过后,或者旧日志分片达到配置大小(由配置的日志分片策略决定)之后,或者日志的属主出故障之后,旧的日志分片会被封存,一个新的日志分片会被开启。

  Kafka分区和DistributedLog流在数据分片和分布的不同点决定了它们在数据持久化策略和集群操作(比如集群扩展)上的不同。

3.png


  图二显示了DistributedLog和Kafka数据模型的不同点

  图二:Kafka分区与DistributedLog流

  数据持久化

  一个Kafka分区中的所有数据都保存在一个代理服务器上(并被复制到别的代理服务器上)。在配置的有效期过后数据会失效并被删除。另外,也可以配置策略让Kafka的分区保留每个主键的最新值。

  与Kafka相似,DistributedLog也可以为每个流配置有效期,并在超时之后将相应的日志分片失效或删除。除此之外,DistributedLog还提供了显示的截断机制。应用程序可以显式地将一个日志流截断到流的某个指定位置。这对于构建可复制的状态机非常有用,因为可复制的状态机需要在删除日志记录之前先将状态持久化。Manhattan就是一个用到了这个功能的典型系统。

  操作

  数据分片和分布机制的不同也导致了维护集群操作上的不同,扩展集群操作就是一个例子。

  扩展Kafka集群时,通常现有分区都要做重新分布。重新分布操作会将Kafka分区挪动到不同的副本上,以此达到均衡分布。这就要把整个流的数据从一个副本拷到另一个副本上。我们也说过很多次了,执行重新分布操作时必须非常小心,避免耗尽磁盘和网络资源。

  而扩展DistributedLog集群的工作方式则截然不同。DistributedLog包含两层:存储层(ApacheBooKeeper)和服务层(写入和读出代理)。在扩展存储层时,我们只需要添加更多的Bookie就好了。新的Bookie马上会被写入代理发现,并立刻用于写入新的日志分片。在扩展数据存储层时不会有任何的重新分布操作。只在增加服务层时会有重新分布操作,但这个重新分布也只是移动日志流的属主权,以使网络代宽可以在各个代理之间均衡分布。这个重新分布的过程只与属主权相关,没有数据迁移操作。这种存储层和服务层的隔离不仅仅是让系统具备了自动扩展的机制,更让各种不同类型的资源可以独立扩展。

  写与生产者

  如图一所示,Kafka生产者把数据一批批地写到Kafka分区的主代理服务器上。而ISR(同步复制)集合中的从代理服务器会从主代理上把记录复制走。只有在主代理从所有的ISR集合中的副本上都收到了成功的响应之后,一条记录才会被认为是成功写入的。可以配置让生产者只等待主代理的响应,还是等待ISR集合中的所有代理的响应。

  DistributedLog中则有两种方式把数据写入DistributedLog流,一是用一个Thrift的瘦客户端通过写代理(众所周知的多写入)写入,二是通过DistributedLog的核心库来直接与存储节点交互(众所周知的单独写入)。第一种方式很适合于构建消息系统,第二种则适用于构建复制状态机。你可以查阅DistributedLog文档的相关章节来获取更多的信息和参考,以找到你需要的方式。

  日志流的属主会并发地以BookKeeper条目的形式向Bookie中写入一批记录,并等待多个Bookie的Quorum结果。Quorum的大小取决于BookKeeper账目的ack_quorum_size参数,并且可以配置到DistributedLog流的级别。它提供了和Kafka生产者相似的在持久性上的灵活性。在接下来的“复制”一节我们会对比两者在复制算法上的更多不同之处。

  Kafka和DistributedLog都支持端到端的批量操作和压缩机制。但两者之间的一点微妙区别是对DistributedLog的写入操作都是在收到响应之前都先通过fsync刷到硬盘上的,而我们并没发现Kafka也提供了类似的可靠性保证。

  读与消费者

  Kafka消费者从主代理服务器上读出数据记录。这个设计的前提就是主代理上在大多数情况下最新的数据都还在文件系统页缓存中。从充分利用文件系统页缓存和获得高性能的角度来说这是一个好办法。

  DistributedLog则采用了完全不同的方法。因为各个存储节点之间没有明确的主从关系,DistributedLog可以从任意存储着相关数据的存储节点上读出数据。为了获得可预期的低延迟,DistributedLog引入了一个推理式读机制,即在超出了配置的读操作时限之后,它会在不同的副本上再次尝试获取数据。这就可能会对存储节点导致比Kafka更高的读压力。不过,如果将读超时时间配成可以让99%的存储节点的读操作都不会超时,那就可以极大程度地解决延迟问题,只带来1%的额外读压力。

  对于读的考虑和机制上的不同主要源于复制机制和存储节点的I/O系统的不同,在下文会继续讨论。

  复制

  Kafka用的是ISR复制算法:将一个代理服务器选为主。所有写操作都被发送到主代理上,所有处于ISR集合中的从代理都从主代理上读取和复制数据。主代理会维护一个高水位线(HW,HighWatermark),即每个分区最新提交的数据记录的偏移量。高水位线会不断同步到从代理上,并周期性地在所有代理上记录检查点,以备恢复之用。在所有ISR集合中的副本都把数据写入了文件系统(并不必须是磁盘)并向主代理发回了响应之后,主代理才会更新高水位线。

  ISR机制让我们可以增加或减少副本的数量,在可用性和性能之间做出权衡。可是扩大或缩小副本的集合的副作用是增大了丢失数据的可能性。

  DistributedLog使用的是Quorum投票复制算法,这在Zab、Raft以及ViewstampedReplication等一致性算法中都很常见。日志流的属主会并发地把数据记录写入所有存储节点,并在得到超过配置数量的存储节点投票确认之后,才认为数据已成功提交。存储节点也只在数据被显式地调用flush操作刷入磁盘之后才会响应写入请求。日志流的属主也会维护一个日志流的最新提交的数据记录的偏移量,就是大家知道的ApacheBookKeeper中的LAC(LastAddConfirmed)。LAC也会保存在数据记录中(来节省额外的RPC调用开销),并不断复制到别的存储节点上。DistributedLog中复本集合的大小是在每个流的每个日志分片级别可配置的。改变复制参数只会影响新的日志分片,不会影响已有的。

  存储

  每个Kafka分区都以若干个文件的形式保存在代理的磁盘上。它利用文件系统的页缓存和I/O调度机制来得到高性能。Kafka也是因此利用Java的sendfileAPI来高效地从代理中写入读出数据的。不过,在某些情况下(比如消费者处理不及时、随机读写等),页缓存中的数据淘汰很频繁,它的性能也有很大的不确性性。

  DistributedLog用的则是不同的I/O模型。图三表示了Bookie(BookKeeper的存储节点)的I/O机制。写入(蓝线)、末尾读(红线)和中间读(紫线)这三种常见的I/O操作都被隔离到了三种物理上不同的I/O子系统中。所有写入都被顺序地追加到磁盘上的日志文件,再批量提交到硬盘上。在写操作持久化到磁盘上之后,它们就会放到一个Memtable中,再向客户端发回响应。Memtable中的数据会被异步刷新到交叉存取的索引数据结构中:记录被追加到日志文件中,偏移量则在分类账目的索引文件中根据记录ID索引起来。最新的数据肯定在Memtable中,供末尾读操作使用。中间读会从记录日志文件中获取数据。由于物理隔离的存在,Bookie节点可以充分利用网络流入带宽和磁盘的顺序写入特性来满足写请求,以及利用网络流出代宽和多个磁盘共同提供的IOPS处理能力来满足读请求,彼此之间不会相互干扰。

4.png


  图三:BookKeeper的I/O隔离

  小结

  Kafka和DistributedLog都是设计来处理日志流相关问题的。它们有相似性,但在存储和复制机制上有着不同的设计理念,因此有了不同的实现方式。希望这篇文章能从技术角度解释清楚它们的区别,回答一些问题。我们接下来也会再多写一些文章来讲讲DistributedLog的性能指标。

文章来源:大数据杂谈
文章作者:郭斯杰

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部