消息队列&Kafka | 青训营笔记

101 阅读4分钟

消息队列

保存消息的一个容器,本质是一个队列,需要支持高吞吐、高并发、高可用。

发展历程

  • 诞生于1985,服务于金融机构和新闻机构:TIB

  • 诞生于1993,商业消息队列平台市场主要玩家:IBM MQ/WebSphere

  • 微软发布于1997:MSMQ

  • 诞生于2001,本质上是一套Java API:JMS

  • 规范发布于2004年,同年RabbitMQ面市:AMQP/RabbitMQ

  • 2010年由Linked开源:kafka

    分布式、分区、多副本的日志提交服务,在高吞吐场景下出色

  • 2011年阿里中间件团队自研:RocketMQ

    低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性在一些实时场景中应用较广

  • 2012年诞生于Yahoo内部:Pulsar

    下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计

  • ByteDance:BMQ

    和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群

Kafka

  • 使用场景:搜索服务、直播服务、订单服务、支付服务

    用户行为:搜索、点赞、评论、收藏

    日志信息

    Metrics数据:记录服务器延迟

  • 使用:创建集群、新增Topic、编写生产者逻辑、编写消费者逻辑

  • 基本概念:image-20230520173925617

    topic:逻辑队列,不同topic可以建立不同的topic,每个topic中有多个partition分区

    cluster:物理集群,每个集群中可以建立多个不同的Topic

    producer:生产者,负责将业务消息发送到topic中

    consumer:消费者,负责消费topic中的消息

    consumerGroup:消费者组,不同组的consumer消费进度互不干涉

    image-20230520174213734

    Offset:每个消息在partition中的相对位置信息,可以理解为唯一ID,在partition内部严格递增

    image-20230520174335429

    Replica:partition下的副本,每个partition有多个replica,leader repilca会从ISR中选出

    ISR:in-sync repicas:follower应该尽量跟leader保持一致,差距过大则会被踢出ISR。leader和follower不在一个物理机器上,防止数据丢失

    Zookeeper:负责存储集群元信息,包括分区分配信息等

  • 优化方案:

    • producer批量发送+压缩到broker来减少IO和提高速度
    • broker采用顺序写进行写入,提高写入效率,避免移动磁头。同时采用消息索引和零拷贝提高速度
    • Consumer采用Rebalance
  • 具体过程总结:

    1. 生产者发布消息

      生产者是消息的发布者,可以是任何生成数据的系统。比如,一个用户的网页活动可能被一个服务记录下来,该服务充当生产者,将活动数据(消息)发布到Kafka。

    2. 将消息存储在Broker

      生产者将消息发送到Broker。Broker是Kafka中负责消息存储的服务实例。每个Broker都可以处理数百万或更多的消息。为了实现可伸缩性和容错性,Kafka通常在多个Broker上运行,这些Broker一起构成了一个Kafka集群。

    3. 消息分类到Topic

      生产者将消息发送到一个特定的Topic。Topic是消息的分类或流,可以将其视为消息的容器或桶。一个Topic可以跨多个Broker进行存储,以便在Broker间进行负载均衡。

    4. 消费者从Topic中读取消息

      消费者是订阅一个或多个Topic并处理其消息的系统或应用程序。消费者可以从他们之前停下的地方继续读取记录,因为每条记录都有一个与Topic关联的偏移量。因此,即使某些消费者宕机,他们也可以在重新启动时从中断处继续。

    5. Zookeeper的协调作用

      Zookeeper用于管理和协调Broker。它还帮助在消费者和Broker之间维护消息的偏移量。

      总的来说,生产者发布消息到Broker,Broker将消息存储在一个或多个Topic中,然后消费者订阅并消费这些Topic的消息。Kafka保证消息的顺序,并允许消费者在失败后从上次停下的地方继续读取。

  • 问题

    • 运维成本高
    • 对于负载不均衡的场景,解决方案复杂
    • 没有自己的缓存,完全依赖Page Cache
    • Controller和Coordinator和Broker在同一进程中时,大量IO会造成其性能下降