大数据学习笔记-2020-10-13--kafka工作流程

本文深入探讨了Kafka的工作流程,包括生产者如何采用推的方式将消息发布到broker,消息的分区策略以及副本机制。每个分区具有顺序写入的效率优势,通过分区和副本提高了系统的可扩展性和可靠性。消费者采用拉模式从broker获取数据,支持消费者组实现负载均衡。Kafka的存储策略基于时间和大小删除消息,并在Zookeeper中存储元数据。
摘要由CSDN通过智能技术生成

kafka工作流程

生产过程
  • 写入方式:producer采用推(push)的方式将消息发布到broker,每条消息都被追加(append)到分区(partition)中,属于顺序写磁盘,效率高于随机写内存,提升了kafka的吞吐量

  • 分区:消息都发送到一个topic中,其本质是一个目录,而topic是由一个partition logs分区日志组成,其中每一个partition中的消息都是有序的,而消息是不断追加到partition log上,其中每一个消息都被赋予了一个唯一的offset。

    • 分区的原因:

      • 方便在集群中扩展,每个分区可以通过调整以适应它所在的机器,而一个topic由多个分区组成,因此可以适应不同规模的业务
      • 提高并发,可以以分区为单位进行读写
    • 分区的原则:

      • 指定了分区则直接使用

      • 未指定分区但是指定key则通过keyhash出一个分区

      • 如果分区和key都没有指定分区,则会轮询选出一个分区

      • *分区相关java源码:

        //DefaultPartitioner类
        public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
                List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
                int numPartitions = partitions.size();
                if (keyBytes == null) {
                    int nextValue = nextValue(topic);
                    List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
                    if (availablePartitions.size() > 0) {
                        int part = Utils.toPositive(nextValue) % availablePartitions.size();
                        return availablePartitions.get(part).partition();
                    } else {
                        // no partitions are available, give a non-available partition
                        return Utils.toPositive(nextValue) % numPartitions;
                    }
                } else {
                    // hash the keyBytes to choose a partition
                    return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;
                }
            }
        
  • 副本(replication):

    • 同一个partition可能会有多个副本,对应 server.properties 配置中的 default.replication.factor=N。
    • 一旦broker泵机,其上所有的分区的数据都将不可被读写,副本可以提高kafka数据的可靠性
    • 同一个分区会有多个副本,这些副本中会有一个被选为leader,producer和consumer都只会和这一个leader交互,而其他副本作为follower从leader中复制数据
  • 写入流程:

    • 首先,producer会从zookeeper的 "/brokers/…/state"节点找到该partition的leader

    • 然后producer会将消息发送给该leader

    • leader将消息写入本地log

    • follower从leader pull消息,写入本地log后发送ack给leader

    • leader搜到所有isr中的副本的ack后,增加HW(high watermark,最后commit 的offset)并向producer发送ack

broker保存消息
  • 存储方式

    • 物理上将topic分成一个或多个partition,每个partition物理上对应一个文件夹
  • 存储策略:不论消息是否被消费,kafka都会保留所有的消息,同时定期删除,一般有两种方法

    • 基于时间:通过设置log.retention.hours配置
    • 基于大小:通过设置log.retention.bytes配置
    • kafka是通过offset读取消息的,时间复杂度为O(1),所以删除过期文件与提高kafka性能无关
  • zookeeper中存储的kafka的元数据:有consumer的元数据如offset、ids等,一个admin节点存储了标记删除的topic节点,同时还储存了诸如broker中的topic及其分区等等数据(见下图:

在这里插入图片描述

kafka的消费过程
  • kafka提供了两套consumer的API:高级consumer API和低级consumer API

    • 高级API
      • 优点:高级API写起来简单,不需要管理offset、分区、副本等等
      • 缺点:它的优点同时就是它的缺点:高级api不能自行控制offset、不能细化控制分区、副本、zk等等
    • 低级API
      • 优点:能自行控制offset,自由的读取消息、自行控制分区,进行负载均衡、还降低了对zk的依赖性
      • 缺点:太过复杂,全都要自行实现
  • 消费者组

    • 消费者以消费者组(consumer group)的方式工作的,由一个或多个消费者组成一个组
    • 每个组共同消费一个topic
    • 每个分区在同一时间只能被group中的某一个消费者读取,但是多个group可以共同消费这个分区
    • 某个消费者读取某个分区,叫做某个消费者是某个分区的拥有者
    • 通过消费者组这种方法,消费者可以通过水平扩展的方式同时读取大量的消息。
    • 如果一个消费者失败了,其他group成员会自动负载均衡读取前失败的消费者读取的分区
  • 消费方式

    • consumer采用拉(pull)模式从broker中读取数据
    • push模式很难适应消费速率不同的消费者,因为消息发送的速率是由broker来决定的,他的目标是尽可能快的传递消息,但是这样很容易照成consumer来不及处理消息,而pull模式则可以根据consumer的消费能力以适当的速率消费消息
    • pull模式的不足之处在于,如果kafka没有数据,消费者会陷入循环中,一直等待数据到达。为了避免这种情况,我们在我们的拉请求中有参数,允许消费者请求在等待数据到达的“长轮询”中进行阻塞(并且可选地等待到给定的字节数,以确保大的传输大小)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值