kafka和zookeeperkafka

你好,Kafka

2020-12-27  本文已影响0人  tracy_668

[TOC]
大家好,我是 kafka, 可能很多人都听说过我,知道我是 2011 年出生在 LinkedIn 的, 从那会儿到现在我的功能越发强大了。作为一个优秀而又完整的平台,你可以在我上面冗余地存储巨大的数据量,我有一个具有高吞吐量 (数百万 / 秒) 的消息总线,你可以在这上面对经过我的数据进行实时流处理。
如果你认为我就只有上面的这些特点的话,那么你真的是太肤浅了。

上面虽然说的很好,但是并未触及到我的核心,这里我给你几个关键字:分布式,水平可扩展,容错,提交日志。

上面这些抽象的词语,我会一一解释它们的含义,并告诉你们我是如何工作的。

分布式

分布式系统由多个运行的计算机系统组成,所有这些计算机在一个集群中一起工作,对终端用户来讲只是一个单一节点。

image.png

kafka也是分布式的,因为它在不同的节点(又被称为broker)上存储,接受以及发送消息,这样做的好处是具有很高的可扩展性和容错性。

水平可扩展性

在这之前,先看看什么是垂直可扩展,比如你有一个传统的数据库服务器,它开始过度负载,解决这个问题的办法就是给服务器加配置(cpu,内存,SSD),这就叫做垂直扩展。但是这种方式存在两个巨大的劣势

  1. 硬件存在限制,不可能无限的添加机器配置
  2. 它需要停机时间,通常这是很多公司无法容忍的

水平可扩展就是通过添加更多的机器来解决同样的问题,添加新机器不需要停机,而且集群中也不会对机器的数量有任何的限制。问题在于并非所有系统都支持水平可伸缩性,因为它们不是设计用于集群中(集群中工作更加复杂)。

容错性

非分布式系统中容易最致命的问题就是单点失败,如果你唯一的服务器挂掉了,那么我相信你会很崩溃。

而分布式系统的设计方式就是可以以配置的方式来容许失败。在5个节点的kafka集群中,你仍然可以继续工作即使其中两个节点挂掉了。
需要注意的是,容错与性能直接相关,你的系统容错程度越高,性能就越差。

提交日志(commit log)

提交日志(也被称为预写日志或者事物日志)是仅支持附加的持久有序数据结构,你无法修改或者删除记录,它从左往右读并且保证日志的顺序。

image.png

是不是觉得kafka的数据结构如此简单?

是的,从很多方面来讲,这个数据结构就是kafka的核心。这个数据结构的记录是有序的,而有序的数据可以确保我们的处理流程。这两个在分布式系统中都是及其重要的问题。

kafka实际上将所有消息存储到磁盘并在数据结构中对它们进行排序,以便利用顺序磁盘读取。

  1. 读取和写入都是常量时间O(1)(当确定了record id),与磁盘上其他结构的O(log N)操作相比是一个巨大的优势,因为每个磁盘搜索都很耗时。
  2. 读取和写入不会相互影响,写不会锁住读,反之亦然。

这两点有着巨大的优势, 因为数据大小与性能完全分离。无论你的服务器上有100KB还是100TB的数据,Kafka都具有相同的性能

如何工作

应用程序(producer)发送消息(record)到kafka服务器(broker),这些消息会被其他应用程序(consumer)所处理,这些消息存储在主题(topic)中,并且消费者订阅该主题以接收新消息。是不是感觉很像你平时写的代码——生产者消费者模式。

image.png

随着主题变得非常大,它们会分成更小的分区(partition),以获得更好的性能和可伸缩性(比如存储了用户相互发送的消息,你可以根据用户名的第一个字母来进行拆分)。Kafka保证分区内的所有消息都按照它们的顺序排序,区分特定消息的方式是通过其偏移量(offset),你可以将其视为普通数组索引,即为分区中的每个新消息递增的序列号。

image.png

持久化到硬盘

kafka实际上是将所有记录存储到硬盘而不在RAM中保存任何内容。你想知道这个如何做出这个选择的,其实这背后有很多优化使得这个方案可行

  1. kafka有一个将消息分组的协议,这允许网络请求将消息组合在一起并减少网络开销,服务器反过来一次性保留大量消息,消费者一次获取大量线性块。

  2. 磁盘上线性读写非常快,现代磁盘非常慢的概念是由于大量磁盘寻址,但是在大量的线性操作中不是问题。

  3. 操作系统对线性操作进行了大量优化,通过预读(预取大块多次)和后写(将小型逻辑写入组成大型物理写入)技术。

  4. 操作系统将磁盘文件缓存在空闲RAM中。这称为pagecache,而kafka的读写都大量使用了pagecahce

    1. 写消息的时候消息先从java到page cache,然后异步线程刷盘,消息从page cache刷入磁盘
    2. 读消息的时候先从page cache找,有就直接转入socket,没有就先从磁盘load到page cache,然后直接从socket发出去
  5. 由于Kafka在整个流程(producer - >broker - >consumer)中以未经修改的标准化二进制格式存储消息,因此它可以使用零拷贝优化。那时操作系统将数据从pagecache直接复制到socket,有效地完全绕过了Kafka broker。

所有这些优化都使Kafka能够以接近网络的速度传递消息。

数据分发和复制

我们来谈谈Kafka如何实现容错以及它如何在节点之间分配数据。

为了使得一个borker挂掉的时候,数据还能得以保留,分区(partition)数据在多个broker中复制。

在任何时候,一个broker拥有一个partition,应用程序读取/写入都要通过这个节点,这个节点叫做----partition leader。它将收到的数据复制到N个其他broker,这些接收数据的broker叫做follower,follower也存储数据,一旦leader节点死掉的时候,它们就准备竞争上岗成为leader。

这可以保证你成功发布的消息不会丢失,通过选择更改复制因子,你可以根据数据的重要性来交换性能以获得更强的持久性保证

但是你可能会问:producer或者consumer怎么知道partition leader是谁?

对生产者/消费者对分区的写/读请求,它们需要知道分区的leader是哪一个,对吧?这个信息肯定是可以获取到的,Kafka使用zookeeper来存储这些元数据。


image.png

什么是ZooKeeper

Zookeeper是一个分布式键值存储。它针对读取进行了高度优化,但写入速度较慢。它最常用于存储元数据和处理群集的机制(心跳,分发更新/配置等)。

它允许服务的客户(Kafka broker)订阅并在发生变更后发送给他们,这就是Kafka如何知道何时切换分区领导者。ZooKeeper本身维护了一个集群,所以它就有很高的容错性,当然它也应该具有,毕竟Kafka很大程度上是依赖于它的。

zookeeper用于存储所有的元数据信息,包括但不限于如下几项:

  1. 消费者组每个分区的偏移量(现在客户端在单独的kafka topic上存储偏移量)
  2. ACL —— 权限控制
  3. 生产者/消费者的流量控制——每秒生产/消费的数据大小。
  4. partition leader以及它们的健康信息

那么produer/consumer是如何知道谁是partition leader的呢?

生产者和消费者以前常常直接连接ZooKeeper来获取这些信息,但是Kafka从0.8和0.9版本开始移除了这种强耦合关系。客户端直接从kafka broker直接获取这些元数据,而让kafka broker从zookeeper那里获取这些元数据。

什么时候使用kafka

正如我们已经介绍的那样,Kafka允许你通过集中式介质获取大量消息并存储它们,而不必担心性能或数据丢失等问题。
这意味着它非常适合用作系统架构的核心,充当连接不同应用程序的集中式媒体。Kafka可以成为事件驱动架构的中心部分,使你可以真正地将应用程序彼此分离.

image.png

小结

Apache Kafka是一个分布式流媒体平台,每天可处理数万亿个事件。Kafka提供低延迟,高吞吐量,容错的发布和订阅管道,并能够处理事件流。我们回顾了它的基本语义(生产者,代理,消费者,主题),了解了它的一些优化(pagecache),通过复制数据了解了它的容错能力

上一篇下一篇

猜你喜欢

热点阅读