kafka学习笔记

Kafka 学习笔记

  • Kafka (part one)
    • 1.消息
    • 2.分区
      • 分区分配策略
    • 3,生产者
    • 4.消费者
      • 消费者group的rebalance
  • 深入kafka
    • 集群与成员
      • 高可用
      • 请求处理
        • 生产请求
        • 消费请求
      • 可靠性
        • 可靠的消费者

Kafka (part one)

1.消息

kafka的数据单元称为消息,类比数据库中的一行记录,为了提升效率,在向kafka写入消息的时候,是采用批次处理的方式(当然,如果此时只有一条消息,也是会被发送的),即属于同一个topic的同一个partition的一组消息会同时写入kafka,否则单条消息频繁地在网络间传输会造成大量的开销。kafka的消息通常有两部分组成,key和value,而key是可选的,不设置就默认为null,此时,消息就会按照分区规则落到不同的分区。key有两个用途,一是作为消息的附加消息,二是决定消息将被写到哪个分区,拥有相同key的消息将会被写到同一个分区

2.分区

kafka的可以topic可以被分成若干个partition,partition是一个消息队列,保证先进先出,如果一个topic包含多个parition,则该topic里的消息无法保证消息的有序性,但是同一个partition的消息是可以保证有序性的,如果想保证有序性,可以指定消息保存的parition。值得注意的是,如果使用消息的key来映射分区,同时topic的分区数目不变,那么同一个相同key的消息一定会被写到同一个分区,但是,当topic的分区数发生变化是,可能会出现同一个key的消息前后落在不同的分区这种情况。

分区分配策略

  • Round Robin
    Round Robin将一个消费者组所订阅的所有topic的所有分区排序,同时将该消费者组里的所有消费者排序。然后将所有分一对一地依次分配给消费者,当分配到最后一个消费者时,再从第一个消费者开始继续一次分配。
    此时,考虑两种情况,一是该消费者内的消费者订阅的都是相同的topic,二是不同的消费者订阅的是不同的topic。
    case one:
    kafka学习笔记_第1张图片
    case two
    kafka学习笔记_第2张图片
    在这个case中,按照RoundRobin分配策略,T1的P1会分配给C2进行消费,但实际上P1分配给C1消费才更加均衡。
    所以,RoundRobin策略适用于组内所有消费者都订阅了相同的topic
  • Range
    先计算数量,在按数量依次分配。Range 策略是以Topic为维度的分配方式,对于某一个topic,将该topic所包含的分区排列,然后将所有订阅该topic的所有消费者排序,先计算出每个consumer需要消费几个partition,然后按照partition的顺序按数量一次分配个consumer。
    例如,某个topic有7个分区,但是只有三个consumer,则每个consumer至少都需要消费7/3=2个分区,而第一个consumer需要多消费一个分区,即计算结果为第一个consumer消费3个partition,第二,三个consumer分别消费两个分区。
    kafka学习笔记_第3张图片
    在消费者内所有消费者订阅相同的topic时,range和Round策略的性能是一样的。但是,当消费者分别订阅不同的topic时,RoundRobin的策略会更加均衡,如下图。
    kafka学习笔记_第4张图片
  • Sticky
    Sticky分配策略有两个目标,一是尽可能保证分区分配均衡,二是当发生rebalance时,尽可能多的保留现有的分配结果,但是第一目标的优先级高于第二个目标。
    三个consumer C0, C1, C2均订阅了四个topic T0, T1, T2, T3, 每个topic都有两个分区。
    由三个消费者消费四个topic变成C1下线,只有C0与C1继续消费的情况下,分配变化如下:
    kafka学习笔记_第5张图片
    两种分配策略都保证了分配的均衡,每个消费者都消费四个partition,但是StickyAssignor保证了之前已经分配的分区不去发生变动。
    另一个case
    三个消费者C0,C1,C2,三个topic T0,T1,T2,分别有1,2,3个分区,C0订阅T0,C1订阅T0,T1,C2订阅T0,T1,T2
    分配结果变更如下:
    kafka学习笔记_第6张图片
    stickyAssignor的分配方式会更加均衡,实现方式待学习。

3,生产者

生产者发送消息的方式有三种,发送并忘记,同步发送,异步发送
发送并忘记:把消息发送给broker,不关心消息的发送结果,大多数情况下,消息是可以正常发送的,因为kafka是高可用的,而且生产者有自动重发机制(生产者通常会发生两个错误,一类可以重试:如失去连接,无leader, 一类不可重试,如:消息体过大)
同步发送:同步等待结果
异步发送:指定回调函数异步等待结果

4.消费者

需要注意的是,kafka的消费者都是主动轮询去拉取消息,kafka broker不会主动向消费者发送消息, 通常情况下,消息的生产速度是要远远大于消息的消费速度的,因此单个消费者往往是不够用的,kafka的消费者属于一个消费者组,采用消费者组的形式来消费消息,一个group里的消费者订阅的是同一个topic,每个消费者接收topic的部分分区消息。
kafka学习笔记_第7张图片
往消费者group里怎加消费者数量是横向扩展消费者能离的主要方式,加入更多的消费者以降低每个消费者的负担,但是,如果消费者数量大于分区数量,则会出现消费这被闲置的情况。

消费者group之间是隔离的,即使不同的消费者group消费相同的topic,他们是互不影响的,就好像其他的消费者group不存在一样。

消费者group的rebalance

当一个消费者group的成员发生变更时,如加入新成员或剔除死去的消费者,都会触发更改原先的分区与消费者的分配关系。分区的所有权从一个消费者转到另一个消费者,这样的行为被称之为rebalance

深入kafka

集群与成员

kafka的集群实际上就是broker的集合,kafka使用Zookeeper来维护以及管理集群成员,在broker启动时,它通过创建Zookeeper 临时节点来把自己的ID注册到Zookeeper。
kafka的集群中的众多broker包含一个controller, 该controller是第一个加入集群的broker,它除了正常的broker功能外,还负责partition的首领的选取(涉及到partition的复制)。倘若,就的controller失效,则其他的broker会竞选成为新的broker,每个新选出的controller通过Zookeeper的条件递增操作获得一个全新的,数值更大的controller epoch,其他的broker在知道当前的controller epoch后,如果收到由控制器发出的包含较旧的epoch的消息,就会忽略他们。

高可用

复制功能是kafka架构的核心,它可以在个别节点失效时仍能保证Kafka的可用性和持久性。kafka的每个分区都有多个副本, 包含一个首领副本和多个跟随者副本
所有的消费者和生产者的请求都会经过首领副本,跟随者副本不处理来自客户端的请求,他们会从首领副本复制消息,以便在首领副本奔溃的时候,替代首领副本,需要注意的是, 只有消息与首领副本同步的跟随者副本,即同步副本(可配置最小同步副本数,如果同步副本数小于最小同步副本,者broker不会接受新的消息,但是可以发送消息,即变成制只读),才有可能在适当的时候晋升为首领副本。因为,由于网络堵塞等原因,不一定是所有的跟随者副本消息都与首领副本消息保持一致。
kafka通过复制系数来配置副本的数量,kafka的默认复制系数是3,即有一个首领副本,两个跟随者副本,通常情况下,就可以保证高可用。一般不建议复制系数为2,因为当一个broker失效时可能会导致集群不稳定,迫使controller broker重启,而这个broker是唯一的broker,重启的这段时间里,集群是不可用的。
正常情况下,kafka集群有可用的同步副本,在首领副本出现问题时,即使晋升为新的首领副本,保证kafka集群的高可用,但是倘若,集群的跟随者副本都还不是同步副本,如果此时,首领副本出现奔溃,要不要将尚未同步的跟随者副本晋升为同步副本呢,如果晋升,就可能会出现消息丢失的情况,这种就是不完全的首领选举,如果不选举,一直等待首领副本恢复,就会导致kafka一段时间不可用,这就是要在kafka的高可用和数据一致性之前权衡。一般,比如银行系统,宁愿选择在几分钟或者几小时内不处理事务,也不会冒险处理错误的消息。

请求处理

正如前面所说,kafka的生产消息的请求和消费消息的请求都只发送给首领副本, 客户端会发送元数据请求来确定首领副本是在哪个分区,通常情况下,客户端会把服务端返回的元数据缓存起来,但是当服务端broker发生变化,首领副本所在的broker发生变化时,缓存下来的元数据就会过期失效,这时客户端就会重新发送元数据请求来获取元数据。
kafka学习笔记_第8张图片

生产请求

kafka可以通过acks参数来指定需要多少个broker确认才可以认为一个消息写入是成功的,如果acks=1,则认为首领副本收到消息就是写入成功,如果acks=0,则生成这发出消息够,完全不需要broker返回响应,就认为消息的写入是成功的,如果acks=all,则必须所有的跟随者副本全部同步完消息后才认为消息是写入成功的。同时,可以通过配置重试参数来保证生产者发送消息出现错误时,实现高可用。

消费请求

正如前面提到的,为了节省网络开销,broker想消费者发送消息是批次处理的,即数据量达到**下限(可配置)**才会像消费者返回消息,但是在没有达到下限的时候,又不可能让消费者一致等待,所有可以配置超时时间,即到达这个时间后,即使数据量不够,也要向消费者返回消息。
kafka学习笔记_第9张图片

可靠性

可靠的消费者

消费者从partition读取数据时,会获取一批次时间,检查出这批事件里最大的偏移量,然后从这个偏移量开始读取另外一批事件,这样可以保证消费者总能一正确的顺序获取新数据,不会错过任何事件。
如果一个消费者退出,kafka会进行rebalance,该退出的消费者之前负责的分区会有其他的消费者来接管,那么它需要知道这个退出的消费者在退出之前处理的最后一个偏移量是多少。
为了保证消费者的可靠,需要注意4个极其重要的配置参数

  • group.id
  • auto.offset.rest
  • enable.auto.commit
  • auto.commit.interval.ms
    group.id 同一个消费者group的消费者具有相同的group i的;
    auto.offset.reset 指定了当没有偏移量可以提交时(如消费者第一次启动)或者请求的偏移量在broker上不存在时,消费者做何反应。有两个取值:earliest与latest,顾名思义,消费者从分区的开始位置或者从分区的末尾开始(从该consumer创建开始,后生产的数据)读取数据。
    enable.auto.commit 是否自动提交
    auto.commit.interval.ms 自动提交的间隔

有时候,消费者在进行轮询的时候,有时候需要暂停消费者的消费, 可以使用pause()来暂停消费者,但是pause的使用必须有一个前提,就是消费者订阅topic的方式必须是Assign,即指定分区,这种方式的消费者group里的消费者数量发生变化时不会发生rebalance,因为pause的行为是客户端行为,其状态是记录在客户端的,kafka 客户端本地维护一个消费者订阅分区的状态列表,key为分区,value为分区消费者状态,属性pause为true或fause,如果采用subscribe的方式订阅topic,则发生rebalance时,这个消费者订阅分区状态列表就会失效,原来的pause状态位就会消失。

参考:添加链接描述

你可能感兴趣的:(kafka)