一个消息系统负责将数据从一个应用传递到另外一个应用,应用只需关注于数据,无需关注数据在两个或多个应用间是如何传递的。

1.消息系统

一个消息系统负责将数据从一个应用传递到另外一个应用,应用只需关注于数据,无需关注数据在两个或多个应用间是如何传递的。

  1. 概述

    分布式消息传递基于可靠的消息队列,在客户端应用和消息系统之间异步传递消息。有两种主要的消息传递模式:点对点传递模式、发布-订阅模式。大部分的消息系统选用发布-订阅模式。Kafka就是一种发布-订阅模式

  2. 点对点传递模式

    在点对点消息系统中,消息持久化到一个队列中。此时,将有一个或多个消费者消费队列中的数据。但是一条消息只能被消费一次。当一个消费者消费了队列中的某条数据之后,该条数据则从消息队列中删除。该模式即使有多个消费者同时消费数据,也能保证数据处理的顺序。

  3. 发布-订阅模式

    在发布-订阅消息系统中,消息被持久化到一个 topic 中。与点对点消息系统不同的是,消费者可以订阅一个或多个 topic,消费者可以消费该topic中所有的数据,同一条数据可以被多个消费者消费,数据被消费后不会立马删除。在发布-订阅消息系统中,消息的生产者称为发布者,消费者称为订阅者。

2.Kafka

2.1.概述

Kafka 是分布式发布-订阅消息系统,它最初是由 LinkedIn 公司开发的,之后成为 Apache 项目的一部分,Kafka是一个分布式,可划分的,冗余备份的持久性的日志服务,它主要用于处理流式数据

2.2. 特征

  1. 支持多个生产者

    Kafka 可以无缝地支持多个生产者,不管客户端在使用单个主题还是多个主题。所以它很适合用来从多个前端系统收集数据,并以统一的格式对外提供数据。例如,一个包含了多个微服务的网站,可以为页面视图创建一个单独的主题,所有服务都以相同的消息格式向该主题写入数据。消费者应用程序会获得统一的页面视图,而无需协调来自不同生产者的数据流。

  2. 支持多个消费者

    Kafka 也支持多个消费者从一个单独的消息流上读取数据,而且消费者之间直不影响。这与其他队列系统不同,其他队列系统的消息一旦被一个客户端读取,其他客户端就无法再读取它。另外,多个消费者可以组成一个群组,它们共享一个悄息流,并保证整个群组对每个给定的消息只处理一次。

  3. 基于磁盘存储

    消费者可能会因为处理速度慢或突发的流量高峰导致无陆及时读取消息,而持久化数据可以保证数据不会丢失。消费者可以在进行应用程序维护时离线一小段时间,而无需担心消息丢失或堵塞在生产者端。消费者可以被关闭,但消息会继续保留在Kafka 里。消费者可以从上次中断的地方继续处理消息。

  4. 可伸缩,高性能

    通过横向扩展生产者、消费者和 broker, Kafka 可以轻松处理巨大的消息流。在处理大量数据的同时,它还能保证亚秒级的消息延迟。

2.3.应用场景

  • 日志收集

    一个公司可以用 Kafka 可以收集各种服务的 log,通过 Kafka 以统一接口服务的方式开放给各种consumer,例如 Hadoop、Hbase 等

  • 消息系统

    解耦和生产者和消费者、缓存消息等

  • 用户活动跟踪

    Kafka 经常被用来记录 web 用户或者 app 用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到 Kafka 的 topic 中,然后订阅者通过订阅这些 topic 来做实时的监控分析,或者装载到 Hadoop、数据仓库中做离线分析和挖掘

  • 运营指标

    Kafka 也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告

  • 流式处理

    比如 spark streaming 和 storm

3. 架构

一个典型的 Kafka 体系架构包括若干Producer [可以是服务器日志,业务数据,页面前端产生的page view等等],若干broker [Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高],若干Consumer (Group),以及一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,选举leader,以及在consumer group发生变化时进行rebalance。

Producer 使用 push[推] 模式将消息发布到broker

Consumer 使用 **pull[拉] **模式从broker订阅并消费消息。

Pull 模式下,consumer 可以自主决定是否批量的从 broker 拉取数据。Push 模式必须在不知道下游consumer 消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。如果为了避免consumer 崩溃而采用较低的推送速率,将可能导致一次只推送较少的消息而造成浪费。

Pull 模式下,consumer 就可以根据自己的消费能力去决定这些策略

Pull 模式有个缺点是,如果 broker 没有可供消费的消息,将导致 consumer 不断在循环中轮询,直到新消息到达。为了避免这点,Kafka 有个参数可以让 consumer 阻塞知道新消息到达[当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发]

3.1. Broker

Kafka 集群包含一个或多个服务器,服务器节点称为 broker。

broker 存储 topic 的数据。如果某 topic 有 N 个partition,集群有 N 个broker,那么每个broker 存储该 topic 的一个 partition。

  1. Topic

    每条发布到 Kafka 集群的消息都有一个类别,这个类别被称为 Topic。物理上不同 Topic 的消息分开存储,逻辑上一个 Topic 的消息虽然保存于一个或多个 broker 上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处类似于数据库的表名

  2. Partition

topic 中的数据分割为一个或多个 partition。每个 topic 至少有一个 partition。每个partition 中的数据使用多个 segment 文件存储。partition 中的数据是有序的,不同partition 间的数据丢失了数据的顺序。如果 topic 有多个 partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将 partition 数目设为1。

如果 Topic 不进行分区,而将 Topic 内的消息存储于一个 broker,那么关于该 Topic 的所有读写请求都将由这一个 broker 处理,吞吐量很容易陷入瓶颈,这显然是不符合高吞吐量应用场景的。

有了 Partition 概念以后,假设一个 Topic 被分为 10 个 Partitions,Kafka 会根据一定的算法将 10 个 Partition 尽可能均匀的分布到不同的 broker(服务器)上,当 producer 发布消息时,producer 客户端可以采用 random、key-hash 及 轮询 等算法选定目标 partition,若不指定,Kafka 也将根据一定算法将其置于某一分区上。Partiton 机制可以极大的提高吞吐量,并且使得系统具备良好的水平扩展能力。

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

如果某topic有N个partition,集群中broker数目少于N个,那么一个broker存储该topic的一个或多个partition。在实际生产环境中,尽量避免这种情况的发生,这种情况容易导致Kafka集群数据不均衡。

3.2.Producer

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

3.3.Consumer & Consumer Group

消费者可以从 Broker 中读取数据。消费者可以消费多个 topic 中的数据。

每个 Consumer 属于一个特定的 Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。这是 Kafka 用来实现一个 topic 消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个 topic 可以有多个 CG。topic 的消息会复制给 consumer。如果需要实现广播,只要每个 consumer 有一个独立的 CG 就可以了。要实现单播只要所有的 consumer 在同一个 CG。用CG还可以将 consumer 进行自由的分组而不需要多次发送消息到不同的topic。

3.4.Zookeeper

3.4.1. 概述

Zookeeper 是一个开放源码的、高性能的分布式协调服务,它用于 Kafka 的分布式应用。Zookeeper 主要用来跟踪 Kafka 集群中的节点状态, 以及 Kafka Topic, message 等等其他信息. 同时, Kafka 依赖于Zookeeper, 没有Zookeeper 是不能运行起来 Kafka 的.

Zookeeper 存储了一些关于 consumer 和 broker 的信息,那么就从这两方面说明 zookeeper 的作用。

  1. Broker 注册

    zookeeper 记录了所有 broker 的存活状态,broker 会向 zookeeper 发送心跳请求来上报自己的状态。

    zookeeper 维护了一个正在运行并且属于集群的 broker 列表。

  2. Topic 注册

    在 Kafka 中,同一个 Topic 的消息会被分成多个分区并将其分布在多个 Broker 上,这些分区信息及与 Broker 的对应关系也都是由 Zookeeper 在维护,由专门的节点来记录

  3. 控制器选举

    Kafka 集群中有多个 Broker,其中有一个会被选举为控制器。

    控制器负责管理整个集群所有分区和副本的状态,例如某个分区的 leader 故障了,控制器会选举新的 leader。

    从多个 broker 中选出控制器,这个工作就是 zookeeper 负责的。

  4. 记录 ISR 信息

    zookeeper 记录着 ISR 的信息,而且是实时更新的,只要发现其中有成员不正常,马上移除。

  5. topic 配置

    zookeeper 保存了 topic 相关配置,例如 topic 列表、每个 topic 的 partition 数量、副本的位置等等。

  6. consumer

    • offset

      kafka 老版本中,consumer 的消费偏移量是默认存储在 zookeeper 中的。

      新版本中,逐渐弱化了 zookeeper 的作用。新的 consumer 使用了 kafka 内部的group coordination 协议,也减少了对zookeeper的依赖,工作由 kafka 自己做了,kafka 专门做了一个 offset manager。

    • 注册

      和 broker 一样,consumer 也需要注册。

      consumer 会自动注册,注册的方式也是创建一个临时节点,consumer down 了之后就会自动销毁。

  7. 分区注册

    kafka 的每个 partition 只能被消费组中的一个 consumer 消费,kafka 必须知道所有 partition 与 consumer 的关系。

4.总结

Kafka 分区数可以增加或减少吗?为什么?

我们可以使用 bin/kafka-topics.sh 命令对 Kafka 增加 Kafka 的分区数据,但是 Kafka 不支持减少分区数。
Kafka 分区数据不支持减少是由很多原因的,比如减少的分区其数据放到哪里去?是删除,还是保留?删除的话,那么这些没消费的消息不就丢了。如果保留这些消息如何放到其他分区里面?追加到其他分区后面的话那么就破坏了 Kafka 单个分区的有序性。如果要保证删除分区数据插入到其他分区保证有序性,那么实现起来逻辑就会非常复杂。