kafka进阶1

102 阅读4分钟

1、为什么要用消息队列(MQ:kafka/rabbitMQ)

  • 解耦。A只管发,B只管拿
  • 异步通信。有些没必要的操作,可以kafka先给A,B再慢慢处理
  • 削峰
  • 发布订阅 Kafka中消息都是面向 topic的,为了提高并行度,每个topic有多个partition(leader),各partition有各自的副本follower。

2、生产者->kafka:

指定了partitoin就放指定的地方,没指定但有key就hash取余决定partition,没有指定也没有key就轮询。默认副本全部同步完才ack(而不是半数同步完成)但有follower迟迟备份不好,那就就被踢出ISR,等该follower赶上了才再进入ISR,ISR内整体还是全部同步完了再ack。

  • 对于某些不重要的信息,也不需要ISR里全部同步完再ack,可以使用0/1/-1应答机制,但都不是精准一次性生产,之前都是消费者自己去重,但若消费者多了,下游压力也大,所以想办法要转到上游进入kafka时就去重。0.11版本后加入幂等性,At least once+幂等性=Exactly Once,但幂等性没办法保证跨分区跨会话。
  • 在 0.11 版本以前的 Kafka,对此是无能为力的,只能保证数据不丢失,再在下游消费者对数据做全局去重。对于多个下游应用的情况,每个都需要单独做全局去重,这就对性能造成了很大影响。0.11 版本的 Kafka,引入了一项重大特性:幂等性。所谓的幂等性就是指 Producer 不论向 Server 发送多少次重复数据,Server 端都只会持久化一条。幂等性结合 At Least Once 语义,就构成了 Kafka 的 Exactly Once 语义。即:At Least Once + 幂等性 = Exactly Once。要启用幂等性,只需要将 Producer 的参数中enable.idompotence 设置为 true 即可。Kafka的幂等性实现其实就是将原来下游需要做的去重放在了数据上游。开启幂等性的 Producer 在初始化的时候会被分配一个 PID,发往同一 Partition 的消息会附带 Sequence Number。而Broker 端会对<PID, Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker 只会持久化一条。
  • 然而生成环境中,更多的是采用下游去重,即消费时去重。

3、kafka->消费者

  • 拉取,partition分配采用轮询/平均,记录读取offset(0.9版本前保存在zk,0.9后保存在kafka内置topic)默认情况不能保证精准一次性消费,因为默认消费者从kafka拉取到数据先更新偏移量(每5s)再落盘,这时若还没落盘就挂掉了,就丢失了数据;若改为先落盘,再更新偏移量,那可能还没更新就挂掉了,重复读取
  • 解决方案①将落盘和更新偏移量放在一个事务里。但是,这就得要求数据库支持事务(非关系型不支持,而mysql又支持不了大规模的数据写入,分布式事务也麻烦复杂,不适合,企业中一般将分布式事务编程本地事务的单线程,eg:Executor数据通过rdd.collect算子提取到Driver端,由Driver端同一写入数据库)===》适合少量数据
  • 解决方案②手动提交偏移量+幂等性。肯定优先选择At least once,即先落盘再修改偏移量,这样就要修改默认顺序,其次,落盘数据可能会重复,那就采用幂等性落盘(存入ES,put天生的幂等性去重,有此key就覆盖;存入Redis,set天生的幂等性去重,有此key就过滤掉),落盘后提交偏移量

4、HW

  • HW是关键,告诉leader现在整体都接受到哪个信息了,leader给producer确认commit,producer发送下一条数据;同时,consumer最多只能消费到HW。
  • 当然,也不一定要所有的成员达到HW再commit,request.required.acks有三种参数来设置数据可靠性级别
    • 1=>leader接受到就确认,确认后发下一条。leader宕机就会丢失数据
    • 0=>不用确认就发下一条。可靠性最低 AtMost Once
    • -1=>等待ISR中所有的follower收到再确认。不丢数据,但会重复。若ISR都踢完了,只剩leader就相当于级1,所有还要配置min.insync.replicas这个参数设定ISR中的最小副本数是多少,默认值为1