大家都知道 Kafka 是一个非常牛逼的消息队列框架,阿里的 RocketMQ 也是在 Kafka 的基础上进行改进的。对于初学者来说,一开始面对这么一个庞然大物会不知道怎么入手。那么这篇文章就带你先了解一下 Kafka 的技术架构,让你从全局的视野认识 Kafka。了解了 Kafka 的整体架构和消息流程之后,脑海里就会有一个大致的结构,这时候再去学习每个部分就容易得多了。

我们先来看一下 Kafka 的整体架构图:

Kafka 的架构图可以分为四个部分:

  • Producer Cluster:生产者集群。一般由许多个实际的业务项目组成,其不断地往 Kafka 集群中写入数据。
  • Kafka Cluster:Kafka 服务器集群。这里就是 Kafka 作为重要的一部分,这里负责接收生产者写入的数据,并将其持久化到文件里,最终将消息提供给 Consumer Cluster。
  • Zookeeper Cluster:Zookeeper 集群。Zookeeper 负责维护整个 Kafka 集群的 Topic 信息、Kafka Controller 等信息。
  • Consumer Cluster:消费者集群。与 Producer Cluster 一样,其一般是由许多个实际的业务项目组成,不断地从 Kafka Cluster 中读取数据。

了解了 Kafka 的整体架构,那一个消息是怎么从生产者到 Kafka Server,又是如何从 Kafka Server 到消费者的呢?一般来说,一个消息的流转可以分为下面几个阶段:

  • 服务器启动阶段
  • 生产者发送消息阶段
  • Kafka存储消息阶段
  • 消费者拉取消息阶段

服务器启动阶段

首先,我们会启动 Zookeeper 服务器,作为集群管理服务器。接着,启动 Kafka Server。Kafka Server 会向 Zookeeper 服务器注册信息,接着启动线程池监听客户端的连接请求。最后,启动生产者和消费者,连接到 Zookeeper 服务器,从 Zookeeper 服务器获取到对应的 Kafka Server 信息[1]。

生产者发送消息阶段

当需要将消息存入消息队列中时,生产者根据配置的分片算法,选择分到哪一个 partition 中。在发送一条消息时,可以指定这条消息的 key,Producer 根据这个 key 和 Partition 机制来判断应该将这条消息发送到哪个 Parition。

Paritition 机制可以通过指定 Producer 的 paritition.class 这一参数来指定,该 class 必须实现 kafka.producer.Partitioner 接口。如果不实现 Partition 接口,那么会使用默认的分区算法,即根据根据 key 哈希后取余[2]。

随后生产者与该 Partition Leader 建立联系,之后将消息发送至该 partition leader。之后生产者会根据设置的 request.required.acks 参数不同,选择等待或或直接发送下一条消息。

  • request.required.acks = 0 表示 Producer 不等待来自 Leader 的 ACK 确认,直接发送下一条消息。在这种情况下,如果 Leader 分片所在服务器发生宕机,那么这些已经发送的数据会丢失。
  • request.required.acks = 1 表示 Producer 等待来自 Leader 的 ACK 确认,当收到确认后才发送下一条消息。在这种情况下,消息一定会被写入到 Leader 服务器,但并不保证 Follow 节点已经同步完成。所以如果在消息已经被写入 Leader 分片,但是还未同步到 Follower 节点,此时Leader 分片所在服务器宕机了,那么这条消息也就丢失了,无法被消费到。
  • request.required.acks = -1 表示 Producer 等待来自 Leader 和所有 Follower 的 ACK 确认之后,才发送下一条消息。在这种情况下,除非 Leader 节点和所有 Follower 节点都宕机了,否则不会发生消息的丢失。

Kafka存储消息阶段

当 Kafka 接收到消息后,其并不直接将消息写入磁盘,而是先写入内存中。之后根据生产者设置参数的不同,选择是否回复 ack 给生产者。之后有一个线程会定期将内存中的数据刷入磁盘,这里有两个参数控制着这个过程:

# 数据达到多少条就将消息刷到磁盘
#log.flush.interval.messages=10000
# 多久将累积的消息刷到磁盘,任何一个达到指定值就触发写入
#log.flush.interval.ms=1000

如果我们设置 log.flush.interval.messages=1,那么每次来一条消息,就会刷一次磁盘。通过这种方式,就可以达到消息绝对不丢失的目的,这种情况我们称之为同步刷盘。反之,我们称之为异步刷盘。

于此同时,Kafka 服务器也会进行副本的复制,该 Partition 的 Follower 会从 Leader 节点拉取数据进行保存。然后将数据存储到 Partition 的 Follower 节点中。

消费者拉取消息阶段

在消费者启动时,其会连接到 zk 注册节点,之后根据所连接 topic 的 partition 个数和消费者个数,进行 partition 分配。一个 partition 最多只能被一个线程消费,但一个线程可以消费多个 partition。其分配算法如下:

1. 将目标 topic 下的所有 partirtion 排序,存于PT
2. 对某 consumer group 下所有 consumer 排序,存于 CG,第 i 个consumer 记为 Ci
3. N=size(PT)/size(CG),向上取整
4. 解除 Ci 对原来分配的 partition 的消费权(i从0开始)
5. 将第i*N到(i+1)*N-1个 partition 分配给 Ci

我们用例子简单描述下这个算法的内容:假设我们连接的 topic 有 8 个 partition,此时有 3 个消费线程。那么 partition 的分配过程大致是这样的:

  • 8/3=2.667,向上取整就是3,也就是说每个consumer分配3个分区。
  • 那么给第一个消费者分配p0/p1/p2三个分区。
  • 给第二个消费者分配p3/p4/p5三个分区。
  • 给第三个消费者分配p6/p7两个分区。

接着消费者连接对应分区的 Kafka Server,并从该分区服务器拉取数据。

总结

这篇文章简单介绍了 Kafka 框架的技术架构以及消息流转过程,并介绍了其中的某些细节。通过这篇文章,相信大家对 Kafka 框架应该有个大致的了解。

参考资料

快速入门:弄懂Kafka的消息流转过程的更多相关文章

  1. 弄懂Kafka的消息流转过程

    原文地址:https://www.cnblogs.com/chanshuyi/p/quick_start_of_kafka.html 大家都知道 Kafka 是一个非常牛逼的消息队列框架,阿里的 Ro ...

  2. 一篇文章让你快速入门 学懂Shell脚本

    Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合. Shell可以直接使用在win/Unix/Linux上面 ...

  3. [Asp.net 开发系列之SignalR篇]专题一:Asp.net SignalR快速入门

    一.前言 之前半年时间感觉自己有点浮躁,导致停顿了半年多的时间没有更新博客,今天重新开始记录博文,希望自己可以找回初心,继续沉淀.由于最近做的项目中用到SignalR技术,所以打算总结下Asp.net ...

  4. kafka快速入门(官方文档)

    第1步:下载代码 下载 1.0.0版本并解压缩. > tar -xzf kafka_2.11-1.0.0.tgz > cd kafka_2.11-1.0.0 第2步:启动服务器 Kafka ...

  5. docker安装kafka快速入门

    docker安装kafka快速入门 1.安装zookeeper docker search zookeeperdocker pull zookeeperdocker run -d -v /home/s ...

  6. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

  7. 【转】快速理解Kafka分布式消息队列框架

     from:http://blog.csdn.net/colorant/article/details/12081909 快速理解Kafka分布式消息队列框架 标签: kafkamessage que ...

  8. 转载来自朱小厮博客的 一文看懂Kafka消息格式的演变

    转载来自朱小厮博客的 一文看懂Kafka消息格式的演变     ✎摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在 ...

  9. 快速入门分布式消息队列之 RabbitMQ(3)

    目录 目录 前文列表 前言 通道 Channel 一个基本的生产者消费者实现 消费者 生产者 运行结果 应用预取计数 应用 ACK 机制 最后 前文列表 快速入门分布式消息队列之 RabbitMQ(1 ...

随机推荐

  1. 使用MongoDB存储集合的一些问题

    这两天在工作中被Mongo集合存储给整得头大,当然也是我的认知太浅,所以下面我来分享下我所遇到的这个问题希望有大佬能给出更好的解决方案, 1.需求: 存储一个从前端接收未知数据类型的集合 例: 由于是 ...

  2. Windows10 Ubuntu bash 配置 LAMP+JDK+Tomcat

    Windows10的Bash省去了装ubuntu虚拟机的麻烦,而且可以直接用Windows下的浏览器去访问了,Exciting有没有,再也不用去忍受日常崩溃的chromium和慢慢的firefox了. ...

  3. Sublime中文编码问题

    1. 改配置 Preferences->Settings  三个全部加上 "default_encoding": "UTF-8" 2. 代码编写 2.1 ...

  4. react 高阶组件的 理解和应用

    高阶组件是什么东西 简单的理解是:一个包装了另一个基础组件的组件.(相对高阶组件来说,我习惯把被包装的组件称为基础组件) 注意:这里说的是包装,可以理解成包裹和组装: 具体的是高阶组件的两种形式吧: ...

  5. Netty_TCP拆包粘包解决方案

    一.问题 熟悉tcp编程的可能都知道,无论是服务器端还是客户端,当我们读取或者发送数据的时候,都需要考虑TCP底层的粘包/拆包机制. TCP是一个“流”协议,所谓流就是没有界限的遗传数据,大家可以想象 ...

  6. 基于java的ES开发

    3.1 环境配置 Jdk 1.8及以上 Elasticsearch.client 5.5.2(与服务器版本一致) Log4j 2.7及以下 maven工程必要的jar包依赖 <project x ...

  7. Linux的文本处理工具浅谈-awk sed grep

    Linux的文本处理工具浅谈 awk   老大 [功能说明] 用于文本处理的语言(取行,过滤),支持正则 NR代表行数,$n取某一列,$NF最后一列 NR==20,NR==30 从20行到30行 FS ...

  8. Python实现猜数字游戏1.0版

    本文由荒原之梦原创,原文链接:http://zhaokaifeng.com/?p=702 """ 功能: 随机生成一个数字,最多有3次猜测机会,如果第一次没有猜对,则从第 ...

  9. SpringMVC接口测试异常:Can not deserialize instance of int out of START_OBJECT token

    之前使用springmvc搭建了restful风格的接口服务,在使用mockmvc进行集成测试的时候出现了异常:Can not deserialize instance of int out of S ...

  10. log4j的配置与使用

    配置log4j的步骤如下: 1.导入jar包 如log4j-1.2.15.jar 2.在src下添加log4j.properties 使用时把下面内容中的注释去掉: //日志级别及位置 log4j.r ...