原文地址:https://www.cnblogs.com/chanshuyi/p/quick_start_of_kafka.html

大家都知道 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=1,那么每次来一条消息,就会刷一次磁盘。通过这种方式,就可以达到消息绝对不丢失的目的,这种情况我们称之为同步刷盘。反之,我们称之为异步刷盘。

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

消费者拉取消息阶段

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

我们用例子简单描述下这个算法的内容:假设我们连接的 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的消息流转过程

    大家都知道 Kafka 是一个非常牛逼的消息队列框架,阿里的 RocketMQ 也是在 Kafka 的基础上进行改进的.对于初学者来说,一开始面对这么一个庞然大物会不知道怎么入手.那么这篇文章就带你先 ...

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

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

  3. Kafka 异步消息也会阻塞?记一次 Dubbo 频繁超时排查过程

    线上某服务 A 调用服务 B 接口完成一次交易,一次晚上的生产变更之后,系统监控发现服务 B 接口频繁超时,后续甚至返回线程池耗尽错误 Thread pool is EXHAUSTED.因为服务 B ...

  4. 一文看懂Kafka消息格式的演变

    摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在不断的升级改进,从0.8.x版本开始到现在的1.1.x版本,Kaf ...

  5. Kafka的消息格式

    Commit Log Kafka储存消息的文件被它叫做log,按照Kafka文档的说法是: Each partition is an ordered, immutable sequence of me ...

  6. 彻底弄懂LSH之simHash算法

    马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说.这种说法同样适用于“经典”的计算机书籍. 最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂.最近看的 ...

  7. 彻底弄懂AngularJS中的transclusion

    点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...

  8. 彻底弄懂 JavaScript 执行机制

    本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我. 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定 ...

  9. Kafka分布式消息队列

    基本架构 Kafka分布式消息队列的作用: 解耦:将消息生产阶段和处理阶段拆分开,两个阶段互相独立各自实现自己的处理逻辑,通过Kafka提供的消息写入和消费接口实现对消息的连接处理.降低开发复杂度,提 ...

随机推荐

  1. linux bash 命令

    export:显示所有的环境变量,如果你想获取某个变量的详细信息,使用 echo $VARIABLE_NAMEv whereis:使用系统自动构建的数据库来搜索可执行文件,源文件和手册页面 which ...

  2. matlab绘图与可视化

    1.设置图形对象属性值 set(h,'属性名称','属性值') >> subplot(,,); h1=line([ ],[ ]); text(,0.5,'unchange'); subpl ...

  3. 解决Exception in thread "main" java.nio.BufferOverflowException报错

    学习bytebuffer时,写了简单的demo报错: 错误的提示:Exception in thread "main" java.nio.BufferOverflowExcepti ...

  4. mysql_pconnect 问题

    不同于mysql_connect的短连接,mysql_pconnect持久连接的时候,将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到,则返回此连接标识而不打开新连接 ...

  5. 关于查询中查询无果,也不报错,inpout标签中的value属性为‘ ’的判断问题

    首先当我们标签中vlue属性可能为' '时,我们一定要在后端进行判断过滤,不然查询会什么都查不出来的,遇到的问题如下 例子如下: 这是一个easyui 中的下拉选,效果如下 当我们默认查询全部时,后台 ...

  6. Vue-cli里面引用stylus遇到的问题总结

    1.stylus的调用 在vue-cli中用到stylus样式处理器的时候一定要引用两个对应的报stylus  stylus-loader 命令:cnpm install stylus stylus- ...

  7. C#杀掉进程的方法

    C#杀掉进程的方法 private static string CmdName = "cmd"; /// <summary> /// 关闭进程 /// </sum ...

  8. JavaScript作用域[[scope]]

    [[scope]] : 隐式的属性 每个JavaScript函数都是一个对象,对象中有些属性可以访问,而有些属性是不可以访问的,这些属性仅供JavaScript引擎存取, [[scope]]就是其中一 ...

  9. Eureka的初识

    在bili看完spring cloud eureka高可用注册中心的视频以后总结: 正常开发中,肯定有一个功能聚集服务中心,将功能方法全部写入其中,也就是一个springboot项目.该服务配置如下: ...

  10. linux 安装 ftp 实现文件共享

    转载:http://blog.sina.com.cn/s/blog_165e646820102xe1q.html 参考:1.http://www.cnblogs.com/mrcln/p/6179673 ...