Kafka系列——基本概念和术语

Kafka中的消息由消息头、Key和Value组成,Key决定分区,Value存储实际数据。Message以紧凑的二进制格式存储以节省空间。生产者发送消息,消费者接收并处理。消费者组允许多消费者共享订阅的Topic分区。每个Topic由多个Partition组成,每个Partition有唯一Offset。副本(Replica)用于高可用性,ISR确保与Leader同步的Replica集合。
摘要由CSDN通过智能技术生成
组件定义/作用
消息(Message)基本的数据单元
生产者(Producer)向kafka发送消息
消费者(Consumer)从kafka获取消息
主题(Topics)消息在broker中存储位置的逻辑名称
分区(Partition)存储消息的有序队列,一个Topics可以有多个Partition
位移(Offset)topic partition 下的每条消息都被分配一个位移值
副本(Replica)每个partition都可以一定数副本,用以保证高可用
ISR处理提交日志(消息如何存储在磁盘上)

Message

kafka的消息由消息头部、key和value组成。

消息头部包括消息的CRC码、消息版本号、属性、时间戳、键长度和消息体长度等信息。
对于普通用户来说,掌握以下3个字段的含义就足够了:

  • Key:消息键,对消息做partition时使用,即决定消息被保存在某topic下的哪个partition。
  • Value:消息体,保存实际的消息数据。
  • Timestamp:消息发送时间戳,用于流式处理及其他依赖时间的处理语义。如果不指定则取当前时间。

Message的存储

为了节省空间,Kafka 使用紧凑的二进制字节数组来保存上面这些字段,也就是说没有任何多余的比特位浪费。

原因
试想如果我们使用Java对象来保存上面的消息格式,会将Java对象保存到堆上,会添加额外的字节用于对齐,同时运行 Java 的操作系统通常都默认开启了页缓存机制,也就是说堆上保存的对象很有可能在页缓存中还保留一份,这造成了极大的资源浪费。

因此 Kafka在消息设计时特意避开了繁重的 Java堆上内存分配,直接使用紧凑二进制字节数组 ByteBuffer 而不是独立的对象,我们至少能够访问多一倍的可用内存。

按照 Kafka 官网的说法,在一台32GB内存的机器上,Kafka几乎能用到28~30GB的物理内存,同时还不必担心GC的糟糕性能。如果使用ByteBuffer来保存同样的消息,只需要24字节,比起纯Java堆的实现减少了40%的空间占用。这种设计的好处还包括加入了扩展的可能性。

同时,大量使用页缓存而非堆内存还有一个好处——当出现 Kafka broker进程崩溃时,堆内存上的数据也一并消失,但页缓存的数据依然存在。下次 Kafka broker重启后可以继续提供服务,不需要再单独“热”缓存。

生产者和消费者

生产者,也就是发送消息的一方。生产者负责创建消息,并将其发送到 Kafka 中。

消费者,也就是接收消息的一方。消费者连接 Kafka 并接收消息,进而进行相应的业务逻辑处理。

消费组
同时kafka还提供了消费者组(Consumer group)的概念):consumer group 是 Kafka 提供的可扩展且具有容错性的消费者机制。
同一个组内可以有多个消费者,它们共享一个公共的 id,即 group id;组内的所有消费者协调在一起来消费订阅主题的所有分区。
当然,每个分区只能由同一个消费组内的一个消费者来消费。

consumer group 主要需要记住下面这三个特性:

  • consumer group 下可以有一个或多个 consumer instance,consumer instance可以是一个进程,也可以是一个线程。
  • group.id 是一个字符串,唯一标识一个 consumer group
  • consumer group 订阅的 topic 下的每个分区只能分配给某个 group 下的一个 consumer 消费。当然该分区还可以被分配给其他 consumer group。(因此,consumer group内consumer instance不要过多,如果超过了分区数就浪费了)

Topic和Partition

从概念上来说,topic 只是一个逻辑概念,代表了一类消息,也可以认为是消息被发送到的地方。
通常我们可以使用topic来区分实际业务,比如业务A使用一个topic,业务B使用另外一个topic。

Kafka中的 topic通常都会被多个消费者订阅,因此出于性能的考量,Kafka并不是 topic-message的两级结构,而是采用了 topic-partition-message的三级结构来分散负载。
从本质上说,每个Kafka topic都由若干个partition组成,如下图所示:
image.png
这张图非常清楚地表明了它们二者之间的关系:topic是由多个partition组成的。
而Kafka的partition是不可修改的有序消息序列,也可以说是有序的消息日志。每个 partition 有自己专属的 partition 号,通常是从0开始的。

Partition内的offset

用户对partition 唯一能做的操作就是在消息序列的尾部追加写入消息。partition 上的每条消息都会被分配一个唯一的序列号——按照Kafka的术语来讲,该序列号被称为位移(offset)。

该位移值是从0开始顺序递增的整数。位移信息可以唯一定位到某partition下的一条消息。

最后,Kafka 的 partition 没有太多的业务含义,引入他就是单纯地为了提升系统的吞吐量,因此在创建 Kafkatopic 的时候可以根据集群实际配置设置具体的partition数,实现整体性能的最大化

Offset

topic partition 下的每条消息都被分配一个位移值。
实际上,Kafka 消费者端也有位移(offset)的概念,但一定要注意这两个offset属于不同的概念。

消费者端的位移如图所示:
image.png

可以看出,消息在某个 partition的位移是固定的,但消费该partition的消费者的位移会随着消费进度不断前移
因此以后在讨论位移的问题时一定要给出清晰的上下文环境,这样才能明确要讨论的是哪个位移。

综合之前说的 topic、partition 和 offset,我们可以断言 Kafka中的一条消息其实就是一个**<topic,partition,offset>**三元组(tuple),通过该元组值我们可以在 Kafka 集群中找到唯一对应的
那条消息。

副本(Replica)

由于partition 存储序消息日志,那么为了高可用,肯定不会只保存这一份日志,否则一旦保存 partition 的 Kafka 服务器挂掉了,其上保存的消息也就都丢失了。

由于分布式系统必然要实现高可靠性,而目前实现的主要途径还是依靠冗余机制——就是备份多份日志。
这些备份日志在Kafka中被称为副本(replica),它们存在的唯一目的就是防止数据丢失(而不是为了吞吐量之类的,因为吞吐量是partition支持的),这一点一定要记住!

副本分为两类:领导者副本(leader replica)和追随者副本(follower replica)。

follower replica 不会提供服务给客户端的,也就是说不负责响应客户端发来的消息写入和消息消费请求。

它只是被动地向领导者副本(leader replica)获取数据,而一旦leader replica 所在的broker宕机,Kafka会从剩余的 replica中选举出新的 leader继续提供服务。

目前领导者(leader)和追随者(follower)这种角色设定几乎完全取代了过去的主备的做法(Master-Slave)。
和传统主备系统(比如MySQL)不同的是,在这类 leader-follower系统中通常只有 leader对外提供服务,follower只是被动地追随 leader 的状态,保持与 leader 的同步
follower存在的唯一价值就是充当 leader的候补:一旦 leader 挂掉立即就会有一个追随者被选举成为新的 leader 接替它的工作。
Kafka就是这样的设计,Kafka保证同一个partition的多个replica一定不会分配在同一台broker上
毕竟如果同一个broker上有同一个partition的多个replica,那么将无法实现备份冗余的效果。

ISR(副本同步集?)

ISR的全称是in-sync replica,翻译过来就是与leader replica保持同步的replica集合。这是一个特别重要的概念。前面介绍过Kafka 的副本机制,比如一个 partition 可以配置N个replica,那么这是否就意味着该 partition可以容忍N-1个replica失效而不丢失数据呢?
并不是!
Kafka为partition动态维护一个replica集合

该集合中的所有replica保存的消息日志都与leader replica保持同步状态。只有这个集合中的 replica才能被选举为 leader,也只有该集合中所有replica都接收到了同一条消息,Kafka才会将该消息置于“已提交”状态,即认为这条消息发送成功。

Kafka 承诺只要这个集合中至少存在一个 replica,那些“已提交”状态的消息就不会丢失——记住这句话的两个关键点:

  • ISR 中至少存在一个“活着的”replica;
  • “已提交”消息。有些 Kafka用户经常抱怨:我向 Kafka发送消息失败,然后造成数据丢失。其实这是混淆了

Kafka 的消息交付承诺(message delivery semantic)

Kafka 对于没有提交成功的消息不做任何交付保证,它只保证在ISR存活的情况下“已提交”的消息不会丢失。

正常情况下,partition的所有replica(含leader replica)都应该与leader replica保持同步,即所有 replica都在 ISR中。
因为各种原因,一小部分 replica开始落后于 leader replica的进度。当滞后到一定程度时,Kafka会将这些replica“踢”出 ISR。
相反,当这些 replica重新“追上”了 leader的进度时,那么 Kafka会将它们加回到 ISR中。
这一切都是自动维护的,不需要用户进行人工干预,因而在保证了消息交付语义的同时还简化了用户的操作成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值