面试问Kafka,这一篇全搞定

https://os.51cto.com/art/201911/606207.htm

图片来自 Pexels

Kafka 基础

消息系统的作用

大部分小伙伴应该都清楚,这里用机油装箱举个例子:

所以消息系统就是如上图我们所说的仓库,能在中间过程作为缓存,并且实现解耦合的作用。

引入一个场景,我们知道中国移动,中国联通,中国电信的日志处理,是交给外包去做大数据分析的,假设现在它们的日志都交给了你做的系统去做用户画像分析。

按照刚刚前面提到的消息系统的作用,我们知道了消息系统其实就是一个模拟缓存,且仅仅是起到了缓存的作用而并不是真正的缓存,数据仍然是存储在磁盘上面而不是内存。

Topic 主题

Kafka 学习了数据库里面的设计,在里面设计了 Topic(主题),这个东西类似于关系型数据库的表:

此时我需要获取中国移动的数据,那就直接监听 TopicA 即可。

Partition 分区

Kafka 还有一个概念叫 Partition(分区),分区具体在服务器上面表现起初就是一个目录。

一个主题下面有多个分区,这些分区会存储到不同的服务器上面,或者说,其实就是在不同的主机上建了不同的目录。

这些分区主要的信息就存在了 .log 文件里面。跟数据库里面的分区差不多,是为了提高性能。

至于为什么提高了性能,很简单,多个分区多个线程,多个线程并行处理肯定会比单线程好得多。

Topic 和 Partition 像是 HBase 里的 Table 和 Region 的概念,Table 只是一个逻辑上的概念,真正存储数据的是 Region。

这些 Region 会分布式地存储在各个服务器上面,对应于 Kafka,也是一样,Topic 也是逻辑概念,而 Partition 就是分布式存储单元。

这个设计是保证了海量数据处理的基础。我们可以对比一下,如果 HDFS 没有 Block 的设计,一个 100T 的文件也只能单独放在一个服务器上面,那就直接占满整个服务器了,引入 Block 后,大文件可以分散存储在不同的服务器上。

注意:

分区会有单点故障问题,所以我们会为每个分区设置副本数。

分区的编号是从 0 开始的。

Producer 生产者

往消息系统里面发送数据的就是生产者:

Consumer 消费者

从 Kafka 里读取数据的就是消费者:

Message 消息

Kafka 里面的我们处理的数据叫做消息。

Kafka 的集群架构

创建一个 TopicA 的主题,3 个分区分别存储在不同的服务器,也就是 Broker 下面。

Topic 是一个逻辑上的概念,并不能直接在图中把 Topic 的相关单元画出:

需要注意:Kafka 在 0.8 版本以前是没有副本机制的,所以在面对服务器宕机的突发情况时会丢失数据,所以尽量避免使用这个版本之前的 Kafka。

Replica 副本

Kafka 中的 Partition 为了保证数据安全,所以每个 Partition 可以设置多个副本。

此时我们对分区 0,1,2 分别设置 3 个副本(其实设置两个副本是比较合适的):

而且其实每个副本都是有角色之分的,它们会选取一个副本作为 Leader,而其余的作为 Follower。

我们的生产者在发送数据的时候,是直接发送到 Leader Partition 里面,然后 Follower Partition 会去 Leader 那里自行同步数据,消费者消费数据的时候,也是从 Leader 那去消费数据的。

Consumer Group 消费者组

我们在消费数据时会在代码里面指定一个 group.id,这个 id 代表的是消费组的名字,而且这个 group.id 就算不设置,系统也会默认设置:

  1. conf.setProperty("group.id","tellYourDream")

我们所熟知的一些消息系统一般来说会这样设计,就是只要有一个消费者去消费了消息系统里面的数据,那么其余所有的消费者都不能再去消费这个数据。

可是 Kafka 并不是这样,比如现在 ConsumerA 去消费了一个 TopicA 里面的数据:

  1. consumerA:
  2. group.id = a
  3. consumerB:
  4. group.id = a
  5. consumerC:
  6. group.id = b
  7. consumerD:
  8. group.id = b

再让 ConsumerB 也去消费 TopicA 的数据,它是消费不到了,但是我们在 ConsumerC 中重新指定一个另外的 group.id,ConsumerC 是可以消费到 TopicA 的数据的。

而 ConsumerD 也是消费不到的,所以在 Kafka 中,不同组可有唯一的一个消费者去消费同一主题的数据。

所以消费者组就是让多个消费者并行消费信息而存在的,而且它们不会消费到同一个消息。

如下,ConsumerA,B,C 是不会互相干扰的:

  1. consumer group:a
  2. consumerA
  3. consumerB
  4. consumerC

如图,因为前面提到过了消费者会直接和 Leader 建立联系,所以它们分别消费了三个 Leader,所以一个分区不会让消费者组里面的多个消费者去消费,但是在消费者不饱和的情况下,一个消费者是可以去消费多个分区的数据的。

Controller

熟知一个规律:在大数据分布式文件系统里面,95% 的都是主从式的架构,个别是对等式的架构,比如 ElasticSearch。

Kafka 也是主从式的架构,主节点就叫 Controller,其余的为从节点,Controller 是需要和 Zookeeper 进行配合管理整个 Kafka 集群。

Kafka 和 Zookeeper 如何配合工作

Kafka 严重依赖于 Zookeeper 集群,所有的 Broker 在启动的时候都会往 Zookeeper 进行注册,目的就是选举出一个 Controller。

这个选举过程非常简单粗暴,就是一个谁先谁当的过程,不涉及什么算法问题。

那成为 Controller 之后要做啥呢,它会监听 Zookeeper 里面的多个目录,例如有一个目录 /brokers/,其他从节点往这个目录上**注册(就是往这个目录上创建属于自己的子目录而已)**自己。

这时命名规则一般是它们的 id 编号,比如 /brokers/0,1,2。注册时各个节点必定会暴露自己的主机名,端口号等等的信息。

此时 Controller 就要去读取注册上来的从节点的数据(通过监听机制),生成集群的元数据信息,之后把这些信息都分发给其他的服务器,让其他服务器能感知到集群中其它成员的存在。

此时模拟一个场景,我们创建一个主题(其实就是在 Zookeeper 上 /topics/topicA 这样创建一个目录而已),Kafka 会把分区方案生成在这个目录中。

此时 Controller 就监听到了这一改变,它会去同步这个目录的元信息,然后同样下放给它的从节点,通过这个方法让整个集群都得知这个分区方案,此时从节点就各自创建好目录等待创建分区副本即可。这也是整个集群的管理机制。

加餐时间

Kafka 性能好在什么地方?

①顺序写

操作系统每次从磁盘读写数据的时候,需要先寻址,也就是先要找到数据在磁盘上的物理位置,然后再进行数据读写,如果是机械硬盘,寻址就需要较长的时间。

Kafka 的设计中,数据其实是存储在磁盘上面,一般来说,会把数据存储在内存上面性能才会好。

但是 Kafka 用的是顺序写,追加数据是追加到末尾,磁盘顺序写的性能极高,在磁盘个数一定,转数达到一定的情况下,基本和内存速度一致。

随机写的话是在文件的某个位置修改数据,性能会较低。

②零拷贝

先来看看非零拷贝的情况:

可以看到数据的拷贝从内存拷贝到 Kafka 服务进程那块,又拷贝到 Socket 缓存那块,整个过程耗费的时间比较高。

Kafka 利用了 Linux 的 sendFile 技术(NIO),省去了进程切换和一次数据拷贝,让性能变得更好。

日志分段存储

Kafka 规定了一个分区内的 .log 文件最大为 1G,做这个限制目的是为了方便把 .log 加载到内存去操作:

00000000000000000000.index00000000000000000000.log00000000000000000000.timeindex00000000000005367851.index00000000000005367851.log00000000000005367851.timeindex00000000000009936472.index00000000000009936472.log00000000000009936472.timeindex

这个 9936472 之类的数字,就是代表了这个日志段文件里包含的起始 Offset,也就说明这个分区里至少都写入了接近 1000 万条数据了。

Kafka Broker 有一个参数,log.segment.bytes,限定了每个日志段文件的大小,最大就是 1GB。

一个日志段文件满了,就自动开一个新的日志段文件来写入,避免单个文件过大,影响文件的读写性能,这个过程叫做 log rolling,正在被写入的那个日志段文件,叫做 active log segment。

如果大家有了解 HDFS 就会发现 NameNode 的 edits log 也会做出限制,所以这些框架都是会考虑到这些问题。

Kafka 的网络设计

Kafka 的网络设计和 Kafka 的调优有关,这也是为什么它能支持高并发的原因:

首先客户端发送请求全部会先发送给一个 Acceptor,Broker 里面会存在 3 个线程(默认是 3 个)。

这 3 个线程都是叫做 Processor,Acceptor 不会对客户端的请求做任何的处理,直接封装成一个个 socketChannel 发送给这些 Processor 形成一个队列。

发送的方式是轮询,就是先给第一个 Processor 发送,然后再给第二个,第三个,然后又回到第一个。

消费者线程去消费这些 socketChannel 时,会获取一个个 Request 请求,这些 Request 请求中就会伴随着数据。

线程池里面默认有 8 个线程,这些线程是用来处理 Request 的,解析请求,如果 Request 是写请求,就写到磁盘里。读的话返回结果。

Processor 会从 Response 中读取响应数据,然后再返回给客户端。这就是 Kafka 的网络三层架构。

所以如果我们需要对 Kafka 进行增强调优,增加 Processor 并增加线程池里面的处理线程,就可以达到效果。

Request 和 Response 那一块部分其实就是起到了一个缓存的效果,是考虑到 Processor 们生成请求太快,线程数不够不能及时处理的问题。

所以这就是一个加强版的 Reactor 网络线程模型。

总结

集群的搭建会再找时间去提及。这一篇简单地从角色到一些设计的方面讲述了 Kafka 的一些基础,在之后的更新中会继续逐步推进,进行更加深入浅出的讲解。

[转帖]面试问Kafka,这一篇全搞定的更多相关文章

  1. ELK集中化日志解决方案——看这一篇全搞定

    一.前言 在软件发开技术管理里有两个永恒经典的问题,适合我们初到一家软件企业或一家公司的科技团队,来判断自己该从哪里入手帮助整个团队提升科技水平和产能.问题一是"在我们团队里,只涉及一行代码 ...

  2. SpringBoot就这一篇全搞定

    Spring Boot从初识到实战 文章收集在 GitHub JavaEgg 中,欢迎star+指导 JavaEgg--<"Java技术员"成长手册>,包含Java基础 ...

  3. 一篇搞定RSA加密与SHA签名|与Java完全同步

    基础知识 什么是RSA?答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名. RSA加密中padding?答:padding即填充方式,由于RSA加密算法 ...

  4. 篇3 安卓app自动化测试-搞定界面元素

    篇3                 安卓app自动化测试-搞定界面元素 --lamecho辣么丑 1.1概要 大家好! 我是lamecho(辣么丑),今天是<安卓app自动化测试>的第三 ...

  5. 大数据之kafka-02.搞定kafka专业术语

    02.搞定kafka专业术语 在kafka的世界中有很多概念和术语是需要我们提前理解并且熟练掌握的,下面来盘点一下. 之前我们提到过,kafka属于分布式的消息引擎系统,主要功能是提供一套完善的消息发 ...

  6. 2021升级版微服务教程6—Ribbon使用+原理+整合Nacos权重+实战优化 一篇搞定

    2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 教程全目录「含视频」:https://gitee.c ...

  7. 如何快速全面掌握Kafka?这篇文章总结了

    Kafka 是目前主流的分布式消息引擎及流处理平台,经常用做企业的消息总线.实时数据管道,本文挑选了 Kafka 的几个核心话题,帮助大家快速掌握 Kafka,包括: Kafka 体系架构 Kafka ...

  8. Kafka【第一篇】Kafka集群搭建

    Kafka初识 1.Kafka使用背景 在我们大量使用分布式数据库.分布式计算集群的时候,是否会遇到这样的一些问题: 我们想分析下用户行为(pageviews),以便我们设计出更好的广告位 我想对用户 ...

  9. 【Kafka入门】Kafka入门第一篇:基础概念篇

    Kafka简介 Kafka是一个消息系统服务框架,它以提交日志的形式存储消息,并且消息的存储是分布式的,为了提供并行性和容错保障,消息的存储是分区冗余形式存在的. Kafka的架构 Kafka中包含以 ...

随机推荐

  1. css实现保持div的等宽高比

    这篇文章主要为回答这个问题:“做响应式网页,如何让一个div的高和宽保持比例放大或是缩小?”,这里不介绍媒体查询的实现. 那么css如何实现高度height随宽度width变化保持比例不变呢?即给定可 ...

  2. linq to js 用法

    /** * 排序汇总 * */ var result = Enumerable.From(vm.productList).GroupBy("$.goods_id", null, f ...

  3. WorkFlow三:CLASS事件触发工作流

    1.创建关键字段结构.这里没有新建,使用前面创建的结构: 2.SE24创建类:保存激活. 3.接口里添加IF_WORKFLOW并激活.(其他两个激活就出现了,不用管) 4.在属性页签中定义两个属性,其 ...

  4. `Java`中`abstract class`与`interface`区别

    abstract class Java中允许使用abstract修饰符声明方法,此时只定义方法但是不实现方法(abstract修饰的方法没有主体,只有一个签名和一个分号). 以下是abstract方法 ...

  5. Ubuntu18.04启动后一个光标在左上角闪动

    1.在实验室服务器上安装Ubuntu18.04后,启动后能够进入grub,但选择Ubuntu后出现只有左上角一个光标在闪但是进不去系统的现象. 2.重新启动选择进入recovery mode,出现如下 ...

  6. sublimeText3和phpstrom使用

    一.sublimtext3 下载地址:http://www.sublimetext.com/3 1.1      安装package control 插件,用来获取和管理插件(sublime包管理工具 ...

  7. computer networking ---------DNS

    [DNS]domain named system 域名解析系统,即相当于对www.baidu.com的类似的域名进行解析,对于人而言,记忆一些域名相比于记忆一些Ip地址来说简单的多,而对于计算机而言, ...

  8. CSP复习与模板

    P3366 [模板]最小生成树 Kruskal 算法因为只与边相关,则适合求稀疏图的最小生成树.而 Prim 算法因为只与顶点有关,所以适合求稠密图的最小生成树. Prim 是以更新过的节点的连边找最 ...

  9. Java多线程编程核心技术-第7章-拾遗增补-读书笔记

    第 7 章 拾遗增补 本章主要内容 线程组的使用. 如何切换线程状态. SimpleDataFormat 类与多线程的解决办法. 如何处理线程的异常. 7.1 线程的状态 线程对象在不同的运行时期有不 ...

  10. 三星固态Dell版的960g的sm863a硬盘

    smart参数 CrystalDiskMark测试 AS SSD 测试 HD Tune Pro测试 DiskGenius查看 总结: 按我的测试,性能比sm865的还好,不知道咋回事,按三星给的参数这 ...