Kafka

Posted by 盈盈冲哥 on March 5, 2020
  • 流程

    1: 第一步心跳请求,客户端启动以后,主动链接castle,请求需要往哪个集群上生产和消费

    2: 第二步心跳响应,castle返回客户端,“你往192.168.1.1” 这个broker上生产消息或拉取消息。

    3: 第三步,客户端链接Broker,生产消息到broker上,或从broker上拉取消息消费。

    4: 以后第一步和第二步会一直重复,这就是所谓的“Mafka心跳”,客户端会始终和Castle保持一个“请求/响应”循环,目的是为了接收服务端的调度和控制指令。

  • 名词

    Broker: 存储实际消息的地方,一台服务器,多个服务器(broker)组成一个集群。

    Castle: 中控调度,调度客户端从哪个机器上拉取消息,或把消息生产到哪台机器上去。

    ClientSDK: 业务使用的api,来生产或消费消息。

    Topic: 主题、队列

    生产者、上游

    消费者、下游,多台相同的消费者组成消费组

    Partition、主题分区、消息分片、分片:设想你发给Mafka 一万条消息,Mafka保存的时候,把它切成了4块,每块2500条消息,分别放到了四个不同的机器上。

    消息副本、replica、消息复制

    Topic的Ack属性:3个副本(一个主本,两个副本),如果Ack设为-1表示3个副本都接受到消息才算成功,如果是1表示主本收到消息就算成功,存在消息丢失风险(主本刚接收到消息返回给发送端成功,同步线程还未将消息复制给副本,此时主本机器宕机了,副本机器转换为主本,消息丢失)。同步线程会保证消息主本和副本复制时延在1秒内,所以Ack设置为1的极端情况下最大可能会丢失1秒内的消息。

    死信:某条消息无法消费成功,一直卡在这条消息处,无法消费后面的消息。解决方法:在topic管理页面里打开死信,处理消息如果失败会扔进死信队列,先消费后面的消息,过一段时间再消费。

  • Kafka 的消息模型知道吗?

    发布-订阅模型:Kafka 消息模型

    发布订阅模型(Pub-Sub) 使用主题(Topic) 作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的。

  • Kafka 的多副本机制了解吗?带来了什么好处?

    还有一点我觉得比较重要的是 Kafka 为分区(Partition)引入了多副本(Replica)机制。分区(Partition)中的多个副本之间会有一个叫做 leader 的家伙,其他副本称为 follower。我们发送的消息会被发送到 leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进行同步。

    生产者和消费者只与 leader 副本交互。你可以理解为其他副本只是 leader 副本的拷贝,它们的存在只是为了保证消息存储的安全性。当 leader 副本发生故障时会从 follower 中选举出一个 leader,但是 follower 中如果有和 leader 同步程度达不到要求的参加不了 leader 的竞选。

    Kafka 的多分区(Partition)以及多副本(Replica)机制有什么好处呢?

    Kafka 通过给特定 Topic 指定多个 Partition, 而各个 Partition 可以分布在不同的 Broker 上, 这样便能提供比较好的并发能力(负载均衡)。

    Partition 可以指定对应的 Replica 数, 这也极大地提高了消息存储的安全性, 提高了容灾能力,不过也相应的增加了所需要的存储空间。

  • Zookeeper 在 Kafka 中的作用知道吗?

    ZooKeeper 主要为 Kafka 提供元数据的管理的功能。

    从图中我们可以看出,Zookeeper 主要为 Kafka 做了下面这些事情:

    1. Broker 注册 :在 Zookeeper 上会有一个专门用来进行 Broker 服务器列表记录的节点。每个 Broker 在启动时,都会到 Zookeeper 上进行注册,即到/brokers/ids 下创建属于自己的节点。每个 Broker 就会将自己的 IP 地址和端口等信息记录到该节点中去
    2. Topic 注册 : 在 Kafka 中,同一个Topic 的消息会被分成多个分区并将其分布在多个 Broker 上,这些分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护。比如我创建了一个名字为 my-topic 的主题并且它有两个分区,对应到 zookeeper 中会创建这些文件夹:/brokers/topics/my-topic/Partitions/0、/brokers/topics/my-topic/Partitions/1
    3. 负载均衡 :上面也说过了 Kafka 通过给特定 Topic 指定多个 Partition, 而各个 Partition 可以分布在不同的 Broker 上, 这样便能提供比较好的并发能力。 对于同一个 Topic 的不同 Partition,Kafka 会尽力将这些 Partition 分布到不同的 Broker 服务器上。当生产者产生消息后也会尽量投递到不同 Broker 的 Partition 里面。当 Consumer 消费的时候,Zookeeper 可以根据当前的 Partition 数量以及 Consumer 数量来实现动态负载均衡。
    4. ……
  • Kafka 如何保证消息的消费顺序?

    我们在使用消息队列的过程中经常有业务场景需要严格保证消息的消费顺序,比如我们同时发了 2 个消息,这 2 个消息对应的操作分别对应的数据库操作是:更改用户会员等级、根据会员等级计算订单价格。假如这两条消息的消费顺序不一样造成的最终结果就会截然不同。

    我们知道 Kafka 中 Partition(分区)是真正保存消息的地方,我们发送的消息都被放在了这里。而我们的 Partition(分区) 又存在于 Topic(主题) 这个概念中,并且我们可以给特定 Topic 指定多个 Partition。

    每次添加消息到 Partition(分区) 的时候都会采用尾加法,如上图所示。Kafka 只能为我们保证 Partition(分区) 中的消息有序,而不能保证 Topic(主题) 中的 Partition(分区) 的有序。

    所以,我们就有一种很简单的保证消息消费顺序的方法:1 个 Topic 只对应一个 Partition。这样当然可以解决问题,但是破坏了 Kafka 的设计初衷。

    Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data(数据) 4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同一个 key 的消息可以保证只发送到同一个 partition,这个我们可以采用表/对象的 id 来作为 key 。

    总结一下,对于如何保证 Kafka 中消息消费的顺序,有了下面两种方法:

    1. 1 个 Topic 只对应一个 Partition。
    2. (推荐)发送消息的时候指定 key/Partition。
  • Kafka 如何保证消息不丢失

    生产者丢失消息的情况

    生产者(Producer) 调用send方法发送消息之后,消息可能因为网络问题并没有发送过去。

    所以,我们不能默认在调用send方法发送消息之后判断消息发送成功了。为了确定消息是发送成功,我们要判断消息发送的结果。

    消费者丢失消息的情况

    我们知道消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。偏移量(offset)表示 Consumer 当前消费到的 Partition(分区)的所在的位置。Kafka 通过偏移量(offset)可以保证消息在分区内的顺序性。

    当消费者拉取到了分区的某个消息之后,消费者会自动提交了 offset。自动提交的话会有一个问题,试想一下,当消费者刚拿到这个消息准备进行真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被自动提交了。

    解决办法也比较粗暴,我们手动关闭闭自动提交 offset,每次在真正消费完消息之后之后再自己手动提交 offset 。 但是,细心的朋友一定会发现,这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。

  • kafka是如何保证消息不被重复消费的

    kafka有个offset的概念,当每个消息被写进去后,都有一个offset,代表他的序号,然后consumer消费该数据之后,隔一段时间,会把自己消费过的消息的offset提交一下,代表我已经消费过了。下次我要是重启,就会继续从上次消费到的offset来继续消费。

  但是当我们直接kill进程了,再重启。这会导致consumer有些消息处理了,但是没来得及提交offset。等重启之后,少数消息就会再次消费一次。

通过保证消息队列消费的幂等性来保证消息不被重复消费。