写点什么

Kafka.02 - Topic 介绍

用户头像
insight
关注
发布于: 2021 年 02 月 20 日
Kafka.02 - Topic 介绍

一个 topic 是对一组消息的归纳。对每个 topic,Kafka 都进行了分区,如下图所示:

它的特性是:

  1. 通过设置 partition 增加可扩展性,也加快了消费的速度。

  2. 多副本增加容错性,每个 partition 可以通过副本因子添加多个副本,每个副本保存在不同的 Broker 中,通过 Leader 来完成读写,当某个 Broker 出现故障时,可以选择其他 Broker 中的一个 Partition 做为 Leader,保证 Kafka 能继续提供服务。

  3. 通过顺序写入达到高吞吐。每个分区都由一系列有序的、不可变的消息组成,这些消息被连续的追加到分区中。分区中的每个消息都有一个连续的序列号叫做 offset,用来在分区中唯一的标识这个消息。

消息期限

在一个可配置的时间段内,Kafka 集群保留所有发布的消息,不管这些消息有没有被消费。比如,如果消息的保存策略被设置为 2 天,那么在一个消息被发布的两天时间内,它都是可以被消费的。之后它将被丢弃以释放空间。Kafka 的性能是和数据量无关的常量级的,所以保留太多的数据并不是问题。


offset

实际上每个 consumer 唯一需要维护的数据是消息在日志中的位置,也就是 offset.这个 offset 有 consumer 来维护:一般情况下随着 consumer 不断的读取消息,这 offset 的值不断增加,但其实 consumer 可以以任意的顺序读取消息,比如它可以将 offset 设置成为一个旧的值来重读之前的消息。


以上特点的结合,使 Kafka consumers 非常的轻量级:它们可以在不对集群和其他 consumer 造成影响的情况下读取消息。你可以使用命令行来"tail"消息而不会对其他正在消费消息的 consumer 造成影响。

将日志分区可以达到以下目的:首先这使得每个日志的数量不会太大,可以在单个服务上保存。另外每个分区可以单独发布和消费,为并发操作 topic 提供了一种可能。


分区的作用

相比传统的消息系统,Kafka 可以很好的保证有序性。


传统的队列在服务器上保存有序的消息,如果多个 consumers 同时从这个服务器消费消息,服务器就会以消息存储的顺序向 consumer 分发消息。虽然服务器按顺序发布消息,但是消息是被异步的分发到各 consumer 上,所以当消息到达时可能已经失去了原来的顺序,这意味着并发消费将导致顺序错乱。为了避免故障,这样的消息系统通常使用“专用 consumer”的概念,其实就是只允许一个消费者消费消息,当然这就意味着失去了并发性。


在这方面 Kafka 做的更好,通过分区的概念,Kafka 可以在多个 consumer 组并发的情况下提供较好的有序性和负载均衡。将每个分区分只分发给一个 consumer,这样一个分区就只被这个组的一个 consumer 消费,就可以顺序的消费这个分区的消息。因为有多个分区,依然可以在多个 consumer 组之间进行负载均衡。注意 consumer 组的数量不能多于分区的数量,也就是有多少分区就允许多少并发消费。


Kafka 只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。如果需要 topic 中所有消息的有序性,那就只能让这个 topic 只有一个分区,当然也就只有一个 consumer 组消费它。


主从同步

Kafka 允许 topic 的分区拥有若干副本,这个数量是可以配置的,你可以为每个 topci 配置副本的数量。Kafka 会自动在每个个副本上备份数据,所以当一个节点 down 掉时数据依然是可用的。


Kafka 的副本功能不是必须的,你可以配置只有一个副本,这样其实就相当于只有一份数据。


创建副本的单位是 topic 的分区,每个分区都有一个 leader 和零或多个 followers.所有的读写操作都由 leader 处理,一般分区的数量都比 broker 的数量多的多,各分区的 leader 均匀的分布在 brokers 中。所有的 followers 都复制 leader 的日志,日志中的消息和顺序都和 leader 中的一致。flowers 向普通的 consumer 那样从 leader 那里拉取消息并保存在自己的日志文件中。


许多分布式的消息系统自动的处理失败的请求,它们对一个节点是否活着(alive)”有着清晰的定义。Kafka 判断一个节点是否活着有两个条件:


  1. 节点必须可以维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每个节点的连接。

  2. 如果节点是个 follower,他必须能及时的同步 leader 的写操作,延时不能太久。


符合以上条件的节点准确的说应该是“同步中的(in sync)”,而不是模糊的说是“活着的”或是“失败的”。Leader 会追踪所有“同步中”的节点,一旦一个 down 掉了,或是卡住了,或是延时太久,leader 就会把它移除。至于延时多久算是“太久”,是由参数 replica.lag.max.messages 决定的,怎样算是卡住了,怎是由参数 replica.lag.time.max.ms 决定的。


只有当消息被所有的副本加入到日志中时,才算是“committed”,只有 committed 的消息才会发送给 consumer,这样就不用担心一旦 leader down 掉了消息会丢失。Producer 也可以选择是否等待消息被提交的通知,这个是由参数 request.required.acks 决定的。


Kafka 保证只要有一个“同步中”的节点,“committed”的消息就不会丢失。


Leader 的选择

Kafka 的核心是日志文件,日志文件在集群中的同步是分布式数据系统最基础的要素。


如果 leaders 永远不会 down 的话我们就不需要 followers 了!一旦 leader down 掉了,需要在 followers 中选择一个新的 leader.但是 followers 本身有可能延时太久或者 crash,所以必须选择高质量的 follower 作为 leader.必须保证,一旦一个消息被提交了,但是 leader down 掉了,新选出的 leader 必须可以提供这条消息。大部分的分布式系统采用了多数投票法则选择新的 leader,对于多数投票法则,就是根据所有副本节点的状况动态的选择最适合的作为 leader.Kafka 并不是使用这种方法。


Kafaka 动态维护了一个同步状态的副本的集合(a set of in-sync replicas),简称 ISR,在这个集合中的节点都是和 leader 保持高度一致的,任何一条消息必须被这个集合中的每个节点读取并追加到日志中了,才回通知外部这个消息已经被提交了。因此这个集合中的任何一个节点随时都可以被选为 leader.ISR 在 ZooKeeper 中维护。ISR 中有 f+1 个节点,就可以允许在 f 个节点 down 掉的情况下不会丢失消息并正常提供服务。ISR 的成员是动态的,如果一个节点被淘汰了,当它重新达到“同步中”的状态时,他可以重新加入 ISR.这种 leader 的选择方式是非常快速的,适合 kafka 的应用场景。


提出一个极端的场景:如果所有节点都 down 掉了怎么办?

Kafka 对于数据不会丢失的保证,是基于至少一个节点是存活的,一旦所有节点都 down 了,这个就不能保证了。


实际应用中,当所有的副本都 down 掉时,必须及时作出反应。可以有以下两种选择:

  • 等待 ISR 中的任何一个节点恢复并担任 leader。

  • 选择所有节点中(不只是 ISR)第一个恢复的节点作为 leader.


这是一个在可用性和连续性之间的权衡。如果等待 ISR 中的节点恢复,一旦 ISR 中的节点起不起来或者数据都是了,那集群就永远恢复不了了。如果等待 ISR 以外的节点恢复,这个节点的数据就会被作为线上数据,有可能和真实的数据有所出入,因为有些数据它可能还没同步到。Kafka 目前选择了第二种策略,在未来的版本中将使这个策略的选择可配置,可以根据场景灵活的选择。


这种窘境不只 Kafka 会遇到,几乎所有的分布式数据系统都会遇到。


副本管理

以上仅仅以一个 topic 一个分区为例子进行了讨论,但实际上一个 Kafka 将会管理成千上万的 topic 分区.Kafka 尽量的使所有分区均匀的分布到集群所有的节点上而不是集中在某些节点上,另外主从关系也尽量均衡这样每个几点都会担任一定比例的分区的 leader.


优化 leader 的选择过程也是很重要的,它决定了系统发生故障时的空窗期有多久。Kafka 选择一个节点作为“Controller”,Controller 的主要作用是在 Zk 的帮助下,管理和协调整个 Kafka 集群。当 Controller 发现有节点 down 掉的时候,它负责在有用分区的所有节点中选择新的 leader,这使得 Kafka 可以批量的高效的管理所有分区节点的主从关系。如果 Controller down 掉了,活着的节点会尝试在 zk 中创建 /controller 节点,哪一个节点成功创建了该节点,哪一个节点就会成为新的 Controller。


用户头像

insight

关注

不要混淆行动与进展、忙碌与多产。 2018.11.17 加入

永远都是初学者

评论

发布
暂无评论
Kafka.02 - Topic 介绍