消息队列-kafka基础

outline

  • kafka是什么
  • 基本概念和整体架构
  • producer端
  • 消息的存储机制
  • consumer端
  • Kafka高吞吐率的保证

kafka是什么

  • 分布式的消息系统
  • Scala编写
  • 可水平扩展
  • 高吞吐率
消息投递的三种语义
语义投递类型 含义
At most once 最多一次,消息可能会丢失,但不会重复
At least once 最少一次,消息不会丢失,可能会重复
Exactly once 只且一次,消息不丢失不重复,只且消费一次。

基本概念和整体架构

基本概念

概念名称 作用
broker 一个kafka实例
topic 相当于数据库中的表
partition
segment 段文件,最小的数据存储单位
Replica partition的副本
Offset 消息在分区中的偏移量,用来在分区中唯一地标识这个信息。
producer 生产者,写入消息
consumer 消费者
ConsumerGroup 每个Consumer属于一个特定的Consumer Group,一条消息可以发送到多个不同的Consumer Group,但是一个Consumer Group中只能有一个Consumer能够消费该消息
AR(Assigned Replica) 所有副本
ISR(In-Sync Replicas) 同步副本列表
OSR(Outof-Sync Replicas) 非同步副本列表
LEO(LogEndOffset) 表示每个partition的log最后一条Message的位置
HW(HighWatermark,高水位) 取一个partition对应的ISR中最小的LEO作为HW,避免数据不一致
zookeeper 存储集群的 meta 信息

AR=ISR+OSR

整体架构

消息队列-kafka基础_第1张图片
image

leader/follower是对于partition来说的
producer和consumer只跟leader交互

消息的存储机制

topic

topic是一个逻辑概念
每个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它是唯一标记一条消息。它唯一的标记一条消息。kafka并没有提供其他额外的索引机制来存储offset,因为在kafka中几乎不允许对消息进行“随机读写”。


消息队列-kafka基础_第2张图片
image

partition

物理概念,物理结构上是一个文件夹,partition的名称规则为:topic名称+有序序号
每个partition都由一些列有序的、不可变的消息组成

消息队列-kafka基础_第3张图片
image

Kafka在Zookeeper中为每一个partition动态的维护了一个ISR,这个ISR里的所有replica都跟上了leader,只有ISR里的成员才能有被选为leader的可能(unclean.leader.election.enable=false)。在这种模式下,对于f+1个副本,一个Kafka topic能在保证不丢失已经commit消息的前提下容忍f个副本的失败
在ISR中至少有一个follower时,Kafka可以确保已经commit的数据不丢失


消息队列-kafka基础_第4张图片
image

segment

消息队列-kafka基础_第5张图片
image

存储策略

基于时间:log.retention.hours=168
基于大小:log.retention.bytes=1073741824

producer端

写入和复制过程

producer 采用 push 模式将消息发布到 broker,每条消息都被 append 到 patition 中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 吞吐率)。
1.根据key进行hash,选择partition--消息路由
2.producer将消息给该partition的leader,leader写日志
3.followers从leader pull消息(复制),写入本地log后 leader发送ACK
4.leader 收到所有ISR(in-sync replicas)中的replica的ACK后,增加HW(high watermark,最后commit offset)并向producer发送ACK
对于leader新写入的消息,consumer不能立刻消费,leader会等待该消息被所有ISR中的replicas同步后更新HW,此时消息才能被consumer消费。

消息队列-kafka基础_第6张图片
image

Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。
同步复制要求所有能工作的follower都复制完,这条消息才会被commit,这种复制方式极大的影响了吞吐率。
异步复制方式下,follower异步的从leader复制数据,数据只要被leader写入log就被认为已经commit,这种情况下如果follower都还没有复制完,落后于leader时,突然leader宕机,则会丢失数据。
Kafka的这种使用ISR的方式则很好的均衡了确保数据不丢失以及吞吐率。

消息的语义投递

目前默认情况下一条消息从 producer 到 broker 是确保了最多一次,可通过设置 producer 异步发送实现最少一次

参数 含义 默认值 设定值
request.required.acks 数据可靠性的级别 1(仅leader拿到数据) -1
min.insync.replicas ISR中的最小副本数 1 > 1

要保证数据写入到Kafka是安全的,高可靠的,需要如下的配置:

  • topic的配置:replication.factor>=3,即副本数至少是3个;2<=min.insync.replicas<=replication.factor
  • broker的配置:leader的选举条件unclean.leader.election.enable=false
  • producer的配置:request.required.acks=-1(all),producer.type=sync
发送模式

Kafka的发送模式由producer端的配置参数producer.type来设置

  • 同步的方式,即producer.type=sync
  • 异步的模式,即producer.type=async,可以是producer以batch的形式push数据,这样会极大的提高broker的性能,但是这样会增加丢失数据的风险。如果需要确保消息的可靠性,必须要将producer.type设置为sync。

consumer端

partition和consumer的个数关系
  • kafka的设计原理决定,对于一个topic,同一个group中不能有多于partitions个数的consumer同时消费,否则将意味着某些consumer将无法得到消息.
  • Kafka只能保证一个分区内消息的有序性,在不同分区之间无法保证


    消息队列-kafka基础_第7张图片
    image
消息的语义投递
  • 读完消息之后先commit再处理消息 --> 最多一次
  • 读完消息先处理再commit --> 最少一次

consumer从broker中读取消息后,可以选择commit,该操作会在Zookeeper中存下该consumer在该partition下读取的消息的offset。
该consumer下一次再读该partition时会从下一条开始读取。如未commit,下一次读取的开始位置会跟上一次commit之后的开始位置相同。

  • autocommit,即consumer一旦读取到数据立即自动commit。
消息去重

只且一次就需要引入消息去重机制
GUID(Globally Unique Identifier)

consumer API
  1. The high-level Consumer API
    high-level consumer API 提供了 consumer group 的语义,一个消息只能被 group 内的一个 consumer 所消费,且 consumer 消费消息时不关注 offset,最后一个 offset 由 zookeeper 保存。
  2. The SimpleConsumer API
  • 多次读取一个消息
  • 只消费一个 patition 中的部分消息
  • 使用事务来保证一个消息仅被消费一次

Kafka高吞吐率的保证

  • Sequence I/O
  • sendfile技术---“零拷贝”
  • pagecache
磁盘I/O的性能

引用一组Kafka官方给出的测试数据(Raid-5,7200rpm0):
Sequence I/O: 600MB/s
Random I/O: 100KB/s

sendfile
消息队列-kafka基础_第8张图片
image

上图整个过程共经历两次Context Switch,四次System Call。


消息队列-kafka基础_第9张图片
image
pagecache

Kafka重度依赖底层操作系统提供的PageCache功能。当上层有写操作时,操作系统只是将数据写入PageCache,同时标记Page属性为Dirty。当读操作发生时,先从PageCache中查找,如果发生缺页才进行磁盘调度,最终返回需要的数据。
实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。
使用PageCache功能同时可以避免在JVM内部缓存数据
避免GC

参考资料

kafka数据可靠性深度解读
kafka学习笔记:知识点整理
kafka高性能解密 pagecache sendfile
kafka入门:简介、使用场景、设计原理、主要配置及集群搭建(转)

你可能感兴趣的:(消息队列-kafka基础)