消息队列之Kafka

1. 什么是消息队列

队列相信大家应该都不陌生,它是一种先进先出的数据结构,基本结构如下图。

img

队列

在java中已经实现了各种各样的队列了,那为什么还需要消息队列MQ(Message Queue)这种中间件呢?我们可以先尝试思考一下消息队列存在的意义,它能满足我们项目中的什么需求。

消息队列可以简单理解为,我们把想要传输的数据放到队列中(其结构与普通队列是一样的)

img

消息队列

我们将把数据放入到队列的那一方叫做生产者 ;将从消息队列中取数据的一方叫做消费者

2. 使用消息队列的好处

使用消息队列可以为我们系统带来解耦异步削峰/限流等好处,具体应用场景如下。

2.1 应用解耦

场景说明: 用户下单后,订单系统需要通知库存系统。

传统的做法为:订单系统调用库存系统的接口。如下图所示:

img

传统方式:调用库存接口

传统方式具有如下缺点:

  • 假设库存系统访问失败,则订单减少库存失败,导致订单创建失败。

  • 订单系统同库存系统过度耦合 。

如何解决上述的缺点呢?需要引入消息队列,引入消息队列后的架构如下图所示:

img

引入消息队列,实现应用解耦

  • 订单系统:用户下单后,订单系统进行数据持久化处理,然后将消息写入消息队列,返回订单创建成功。
  • 库存系统:使用拉/推的方式,获取下单信息,库存系统根据订单信息,进行库存操作。

假如在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其后续操作了。由此实现了订单系统与库存系统的应用解耦。

2.2 异步处理

场景说明:用户注册后,需要发送注册邮件和发送注册信息,传统的做法有两种:串行方式、并行方式 。

  • 串行方式: 将注册信息写入数据库成功后,发送注册邮件,然后发送注册短信,而所有任务执行完成后,返回信息给客户端

img
串行方式

  • 并行方式: 将注册信息写入数据库成功后,同时进行发送注册邮件和发送注册短信的操作。而所有任务执行完成后,返回信息给客户端。同串行方式相比,并行方式可以提高执行效率,减少执行时间。

    img
    并行方式

    上面的比较可以发现,假设三个操作均需要50ms的执行时间,排除网络因素,则最终执行完成,串行方式需要150ms,而并行方式需要100ms。 因为cpu在单位时间内处理的请求数量是一致的,假设:CPU每1秒吞吐量是100此,则串行方式1秒内可执行的请求量为1000/150,不到7次;并行方式1秒内可执行的请求量为1000/100,为10次。

    由上可以看出,传统串行和并行的方式会受到系统性能的局限,那么如何解决这个问题?我们需要引入消息队列,将不是必须的业务逻辑,异步进行处理,由此改造出来的流程为 :

    img
    引入消息队列,异步处理消息

    根据上述的流程,用户的响应时间基本相当于将用户数据写入数据库的时间,发送注册邮件、发送注册短信的消息在写入消息队列后,即可返回执行结果,写入消息队列的时间很快,几乎可以忽略,也有此可以将系统吞吐量提升至20QPS,比串行方式提升近3倍,比并行方式提升2倍。

2.3 流量削峰

场景说明:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

  • 可以控制参与活动的人数;
  • 可以缓解短时间内高流量对应用的巨大压力;

流量削峰处理方式系统图如下:

img
流量削峰

  • 服务器在接收到用户请求后,首先写入消息队列。这时如果消息队列中消息数量超过最大数量,则直接拒绝用户请求或返回跳转到错误页面;
  • 秒杀业务根据秒杀规则读取消息队列中的请求信息,进行后续处理。
3. Kafka简介

3.1 消息传递模式

常见的消息传递模式有两种、分别是:

  • 点对点模式 :在点对点消息系统中,消息持久化到一个队列中。此时,可以有一个后多个消费者消费队列中的数据,但是一条消息只能被消费一次。当一个消费者消费了队列中的某条数据之后,该条数据则从消息队列中删除。该模式下,既有多个消费者同时消费数据,也能保证数据处理的顺序。如下图所示。
    点对点传递模式
    点对点传递模式

  • 发布-订阅消息传递模式 :在发布-订阅消息系统中,消息将被持久化到一个topic中,与点对点消息系统的区别是,消费者可以订阅一个或多个topic,消费者可以消费该topic中所有的数据,同一条数据可以被多个消费者消费,且数据消费后不会立马删除,且发布者发送到topic中的消息,只有订阅了topic的订阅者才会收到。在发布-订阅消息系统中,消息的生产者成为发布者,消费者称为订阅者。其中发布-订阅模式中又可以细分为两种模式( 消费者主动拉取数据 队列主动推送数据)如下图所示。
    发布-订阅模式
    发布-订阅模式

3.2 概述

Kafka最初由LinkedIn公司开发,是一种高吞吐量的 基于消费者主动拉取数据的分布式发布-订阅消息系统 ,常见可以用于web/nginx日志、访问日志,消息服务等,LinkedIn于2010年贡献给了Apache基金会并成为顶级开源项目。

Kafka主要设计目标如下:

  • 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间的访问性能;
  • 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒100K条消息的传输;
  • 支持Kafka Server间的消息分区,及分布式消费,同时保证每个partition内的消息顺序传输;
  • 同时支持离线数据处理和实时数据处理;
  • Scale out:支持在线水平扩展。
4. Kafka中常用的术语

我们通过下图的Kafka简单示例架构来熟悉Kafka中的术语。

img

Kafka架构示例

我们先解释图中出现的术语,最后再对整个图的内容做一个详细解释。

4.1 Topic

每天发布到Kafka集群的消息都有一个主题类别( 消息分类 ),这个主题类别称为 Topic 。物理上不同的Topic的消息可能存储在同一broker中,也有可能不在同一broker中,但逻辑上只要用户指定消息的topic即可消费关于该topic 的有关数据,而不必关心数据的物理存储。

4.2 Partition

Topic中的数据分割为一个或多个分区( partition )。partition有以下特性:

  • 每个Topic至少有一个partition;
  • 每个partition中的数据使用多个segment文件存储;
  • partition中的数据是有序的,而不同partition间的数据丢失了数据的顺序(即我们无法知道哪个partition的数据是最先的或最后的);
  • 如果topic有多个partition,消费数据时就不能保证数据的顺序。因此,在需要严格保证消息的消费顺序的场景下,需要将partition的数目设置为1。
4.3 Broker

在上图中我们可以在 Kafka Cluster (即Kafka集群)中看到,集群里包含了一个或多个服务器,这些服务器节点称为 Broker 。Broker存储着topic的数据,常见的存储数据方式如下:

  • 如果某topic有N个partition,集群有N个Broker,那么每个Broker存储该topic的一个partition;

  • 如果某topic有N个partition,集群有N+M个Broker,那么其中有N个broker存储该topic的一个partition,剩下的M个Broker不存储该topic的partition数据;

  • 如果某topic有N个partition,集群的Broker数目少于N个,那么一个Broker存储该topic的一或多partition

    注意:实际生产环境中,一般会尽量避免这种情况发生,因为这种情况容易导致Kafka集群数据不均衡)。

4.4 Producer

Producer即数据的发布者,该角色将消息发布到Kafka的topic中。Broker接收到生产者发送的消息后,将该消息 追加到当前用于追加数据的segment文件中。生产者发送的消息,可以存储到每一个partition中,也可以指定数据存储的partition。

4.5 Consumer

Consumer即为消费数据的一方,消费者可以从Broker中读取数据。消费者可以消费多个topic中的数据。

4.6 Offset

Offset即偏移量(位置),标识分区每条记录的位置,是分区当中每条记录的唯一标识。消费者通过记录当前消费到的偏移量来记录消费情况。

img

偏移量

4.7 Consumer Group

Consumer Group即为消费者组,用于占用式消费。我们可以为每个Consumer指定Group name,若不指定Group name则属于默认的Group。消费者组有以下特性:

  • 对于同一个topic的同一个partition,消费者消费时,会按消费者组来记录消费偏移,即一个组内只维护一个消费偏移。假设消费者1和消费者2同属一组,消费者1消费了一部分数据,那么消费者2此时再来消费数据的话,是无法消费到消费者1消费了的那部分数据的。如下图:

img

消费者组消费示例

  • 不同的group之间记录不同的offset,这样在不同程序读取同一个topic时,才不会因为offset互相影响。
4.8 Leader

每个partition有多个副本,其中 有且仅有一个作为 Leader,Leader是当前负责数据读写的partition。

4.9 Follower

Follower跟随Leader,即与Leader数据保持一致。其特性如下:

  • 所有写请求都通过Leader来路由,即Leader数据的变更会广播给所有Follwer;
  • Follwer与Leader保持数据同步;
  • 如果Leader失效,则从Follower中选举出一个新的Leader;
  • 当Follower挂掉、卡住或同步太慢,Leader会把这个Follower从"in sync replicas"(ISR)列表中删除,重新创建一个Follower。
4.10 架构示例图详细解释

img

Kafka架构示例

  • 我们可以看到,图中主要分为四个部分。分别是 Producer Kafka Cluster Consumer Group Zookeeper注册中心

  • Producer中有两个生产者A和B。Kafka Cluster中有3个Broker(即3台服务器)。Consumer Group中有3个消费者,其中1和2消费者属于同一个消费者组,消费者3属于默认消费者组。Zookeeper主要负责统一管理Kafka Cluster中的所有注册的Broker、消费者组中的消费者。

  • 某个主题消息(Topic A)设置了两个分区,分别是 partition 0 partition 1,每个partition都有其备份分区。其中存储在Broker 1中的partition 0为partition 0的Leader(生产者生产消息与消费者消费消息时主要是与Leader交互),partition 0的备份存储在Broker 2中(图中绿色部分)。存储在Broker 2中的partition 1为partition 1的Leader,partition 1的备份存储在Broker 1中(图中浅蓝色部分)。

  • 首先,最左边的是两个生产者A、B。生产者A生产了 message-A这个消息,将消息分别发送至两个partition的Leader中。生产者B将生产的消息发送到只有一个分区的Topic B的partition 0分区中。

  • 然后在消费阶段,Consumer 1消费Topic A的partition 0中的消息。Consumer 2由于和Consumer 1属于一个消费者组(对相同partition属于占用式消费,但消费不同partition时可以同时进行消费),所以此时Consumer 2可以消费Topic A的partition 1中的消息。Consumer 3 消费Topic B中的partition 0中的消息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值