Kafka和DistributedLog技术对比

  数据持久化

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

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

  操作

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

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

  而扩展DistributedLog集群的工作方式则截然不同。DistributedLog包含两层:存储层(Apache BooKeeper)和服务层(写入和读出代理)。在扩展存储层时,我们只需要添加更多的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,High Watermark),即每个分区最新提交的数据记录的偏移量。高水位线会不断同步到从代理上,并周期性地在所有代理上记录检查点,以备恢复之用。在所有ISR集合中的副本都把数据写入了文件系统(并不必须是磁盘)并向主代理发回了响应之后,主代理才会更新高水位线。