Kafka

152 阅读7分钟

Kafka

  1. Kafka是一个高吞吐量,低延迟的分布式发布-订阅消息系统,单机吞吐量10万级,毫秒级延迟,用于大数据实时领域

    吞吐量:系统在单位时间内处理请求的数量

    GC吞吐量:用户程序执行的时间,GC时间越短,吞吐量越高

  2. Kafka术语概念

    1. Broker:Kafka 服务器,负责消息存储和转发
    2. Topic:消息类别,Kafka 按照 topic 来分类消息,类似于数据库的表
    3. Partition:topic 的分区,一个 topic 可以包含多个 partition,topic 消息保存在各个partition 上,每个分区都有副本
    4. offset:消息在日志中的位置,可以理解是消息在 partition 上的偏移量,也是代表该消息的唯一序号
    5. Producer:消息生产者,Consumer:消息消费者
    6. Consumer Group:消费者分组,每个 Consumer 必须属于一个Group,是Kafka实现单播和广播两种消息模型的手段。对于同一个topic,每个group都可以拿到同样的所有数据,但是数据进入group后只能被其中的一个consumer消费
    7. Controller:保存着broker、topic、partition等元数据;负责分区Leader选举,管理集群Broker的上下线
    8. Controller的管理都是依赖于Zookeeper
  3. Kafka中ZK的作用

    1. Kafka Broker集群的Controller选举,是通过ZK的临时节点争抢获得的(排他锁)
    2. ZK还保存着Kafka的元数据
    3. 在新版本里,Kafka把offset从ZK里移出来了
  4. 副本

    1. AR:分区中的所有副本
    2. ISR:所有与Leader副本保持一定程度同步的副本
    3. OSR:与Leader副本同步滞后过多的副本 AR = ISR + OSR
  5. Kafka是pull还是push

    用的Pull,因为不同的消费者有不同的消费能力,Push模式很难去适应这种情况,推的太快,Consumer可能撑不住,太慢,Consumer会有性能浪费,所以让Consumer根据自己的消费能力去拿数据,但是Broker没有消息的时候,Consumer会一直轮询,所以可以设置让Consumer阻塞直到有消息

  6. 消息中间件的作用

    1. 缓冲和削峰:有突发流量,下游可能扛不住,MQ在中间可以起到一个缓冲的作用,把消息暂存在队列中
    2. 解耦和扩展性:消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守接口约定,就可以进行扩展
    3. 冗余:一个生产者发布消息,可以被多个订阅topic的服务消费到
    4. 健壮性:消息队列可以堆积请求,所以消费端业务即使短时间down掉,也不会影响主要业务
    5. 异步通信:消息队列提供了异步处理机制,可以先把消息放队列里,需要的时候再去处理
  7. 为什么Kafka读写快

    1. 利用Partition实现并行处理:Kafka发布和订阅都要指定Topic,每个Topic又有多个Partition,不同的Partition又可以放到不同的节点上,其实是用的集群的优势去实现并行

    2. 顺序写:Kafka里的每个分区是一个有序的消息队列,编号从0开始,新消息是追加到Partition的末尾(就是一个文件)

    3. 顺序读:Consumer从Broker读数据的时候,他是带了偏移量的,他接着上次读的位置继续读

    4. 零拷贝:就是不需要CPU的参与,直接在内核Kernel里完成拷贝

      1. DMA:Direct Memory Access 直接存储器访问
      2. 不需要CPU参与,设备(硬盘,网卡)和系统内存(内核)之间数据传输的一个机制
    5. 比如这个消息生产过程(Producer->Broker),他是把网络数据持久化到磁盘上,传统模式下,是要经过4次拷贝

      1. 首先通过DMA Copy把网络数据拷贝到Socket缓存区
      2. 然后用户程序把Socket缓存里的数据拷贝到用户空间(CPU Copy)
      3. 接着用户程序再把这数据拷贝到内核缓存区(CPU Copy)
      4. 最后通过DMA Copy数据落盘

      零拷贝就是把中间这两次经过用户空间CPU Copy去掉了

      对Linux 操作系统而言,零拷贝技术依赖于底层的 sendfile() 方法实现。

      对应于 Java 语言,FileChannal.transferTo() 方法的底层实现就是 sendfile() 方法

      MMAP:将一个文件或者其它对象映射进内存,减少了一次CPU拷贝,直接Socket缓存区拷贝到内核缓存区

  8. Kafka中的消息是否会丢失和重复消费?

    1. 这个问题可以从三个方面来考虑

      1. 首先是Producer端

        1. 消息发送方式默认是异步的(producer.type),可以配置成同步,Producer就能实时知道消息发送的结果
        2. 添加异步回调函数来监听消息发送的结果,如果发送失败,可以在回调中重试

        image-20220411221814947.png

        1. Producer本身提供了一个重试参数Retries,如果发送失败,会自动重试
      2. 然后是Broker端,提供了两个机制来确保消息的可靠性

        1. Partition副本机制,是数据分区的高可用策略,每一个Paratition副本集会包含唯一的Leader和多个Follower,Leader专门去处理事务类型的请求,而Follower负责去同步Leader的数据

        2. ACKS(request.required.acks)消息发送确认机制,他有几个值可以去设置

          1. 0:消息发出去,不管成不成功,如果这时候网络有问题,会有消息丢失
          2. 1:消息发出去,分区Leader接收成功,不管有没有同步到Follower,这时候Leader挂了,也会有消息丢失
          3. 所以ACKS可以设置成-1,就是消息写入Leader并且同步到Follower所有ISR副本之后再确认消息发送成功,就可以避免消息丢失
      3. 最后是Consumer端,经过Producer和Broker的设置和一些本身的机制,就可以保证消息可靠,不丢失,Consumer不太可能出现消息丢失的问题,倒是会可能出现重复消费

        1. 重复消费的根本原因在于:已经消费了数据,但是offset没有成功提交,比如触发了分区的Rebalance
        2. Rebalance:再均衡,有新消费者加入消费者组,或者有消费者被剔除,就会触发
        3. 所以要避免重复消费,Consumer要实现消费幂等
        4. 落表,数据库里设置主键或者唯一索引的方式
        5. offset手动提交,或者自定义存储offset(实现ConsumerRebalanceListener)
      4. 幂等性:多次执行所产生的影响均与一次执行的影响相同

  9. Kafka事务

    1. Kafka有个组件Transaction Coordinator去实现事务,Producer就是通过跟这个组件交互获取一个全局唯一的事务TransactionID,将PID和TransactionID绑定,这样Producer重启,也没有影响;
    2. Transaction Coordinator 还把所有事务写入Kafka 的一个内部 Topic,这样即使整个服务重启,也可以恢复
  10. 为什么Kafka不支持读写分离?

    如果Kafka是这种模式,可能会造成数据不一致,还有延迟问题,因为数据从主节点Leader同步到从节点需要时间,比如这时候数据更新了,主从节点还没来得及同步,Consumer就在从节点消费了,数据可能不一致;所以Kafka写入消息,读取消息的操作都是跟Leader副本进行交互的

  11. Kafka中的选举

    1. Controller控制器选举

      通过ZK的临时节点来从多个Broker中选举出Controller,负责管理整个集群中所有分区和副本,如果某个分区的Leader副本出现故障了,控制器负责选举新的分区Leader

    2. 分区Leader选举

      优先副本选举策略,必须满足三个条件:是AR的第一个副本&&副本在线&&副本在ISR列表中