大白话带你认识Kafka

大白话带你认识Kafka

Kafka是一种高吞吐量的分布式发布订阅消息系统,它能够处理消费者在网站中的全部动做流数据。react

Kafka基础面试

消息系统的做用算法

应该大部份小伙伴都清楚,用机油装箱举个例子。数据库

因此消息系统就是如上图咱们所说的仓库,能在中间过程做为缓存,而且实现解耦合的做用。 1.png缓存

引入一个场景,咱们知道中国移动,中国联通,中国电信的日志处理,是交给外包去作大数据分析的,假设如今它们的日志都交给了你作的系统去作用户画像分析。 2.png安全

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

Topic 主题markdown

Kafka学习了数据库里面的设计,在里面设计了topic(主题),这个东西相似于关系型数据库的表。 3.png网络

此时我须要获取中国移动的数据,那就直接监听TopicA便可。架构

Partition 分区

kafka还有一个概念叫Partition(分区),分区具体在服务器上面表现起初就是一个目录,一个主题下面有多个分区,这些分区会存储到不一样的服务器上面,或者说,其实就是在不一样的主机上建了不一样的目录。这些分区主要的信息就存在了.log文件里面。跟数据库里面的分区差很少,是为了提升性能。 4.png

至于为何提升了性能,很简单,多个分区多个线程,多个线程并行处理确定会比单线程好得多。

Topic和partition像是HBASE里的table和region的概念,table只是一个逻辑上的概念,真正存储数据的是region,这些region会分布式地存储在各个服务器上面,对应于Kafka,也是同样,Topic也是逻辑概念,而partition就是分布式存储单元。这个设计是保证了海量数据处理的基础。咱们能够对比一下,若是HDFS没有block的设计,一个100T的文件也只能单独放在一个服务器上面,那就直接占满整个服务器了,引入block后,大文件能够分散存储在不一样的服务器上。

注意:

分区会有单点故障问题,因此咱们会为每一个分区设置副本数; 分区的编号是从0开始的。

Producer - 生产者

往消息系统里面发送数据的就是生产者。 5.png

Consumer - 消费者

从Kafka里读取数据的就是消费者。 6.png

Message - 消息

Kafka里面的咱们处理的数据叫作消息。

Kafka的集群架构

建立一个TopicA的主题,3个分区分别存储在不一样的服务器,也就是broker下面。Topic是一个逻辑上的概念,并不能直接在图中把Topic的相关单元画出。 7.png

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

Replica - 副本

Kafka中的partition为了保证数据安全,因此每一个partition能够设置多个副本。

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

并且其实每一个副本都是有角色之分的,它们会选取一个副本做为leader,而其他的做为follower,咱们的生产者在发送数据的时候,是直接发送到leader partition里面,而后follower partition会去leader那里自行同步数据,消费者消费数据的时候,也是从leader那去消费数据的。 9.png

Consumer Group - 消费者组

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

conf.setProperty("group.id","tellYourDream")
复制代码

咱们所熟知的一些消息系统通常来讲会这样设计,就是只要有一个消费者去消费了消息系统里面的数据,那么其他全部的消费者都不能再去消费这个数据。但是Kafka并非这样,好比如今consumerA去消费了一个topicA里面的数据。

consumerA:
group.id = a
consumerB:
group.id = a

consumerC:
group.id = b
consumerD:
group.id = b
复制代码

再让consumerB也去消费TopicA的数据,它是消费不到了,可是咱们在consumerC中从新指定一个另外的group.id,consumerC是能够消费到topicA的数据的。而consumerD也是消费不到的,因此在Kafka中,不一样组可有惟一的一个消费者去消费同一主题的数据。

因此消费者组就是让多个消费者并行消费信息而存在的,并且它们不会消费到同一个消息,以下,consumerA,B,C是不会互相干扰的。

consumer group:a
consumerA
consumerB
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),省去了进程切换和一次数据拷贝,让性能变得更好。 12.png

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

00000000000000000000.index
00000000000000000000.log
00000000000000000000.timeindex

00000000000005367851.index
00000000000005367851.log
00000000000005367851.timeindex

00000000000009936472.index
00000000000009936472.log
00000000000009936472.timeindex
复制代码

这个9936472之类的数字,就是表明了这个日志段文件里包含的起始offset,也就说明这个分区里至少都写入了接近1000万条数据了。Kafka broker有一个参数,log.segment.bytes,限定了每一个日志段文件的大小,最大就是1GB,一个日志段文件满了,就自动开一个新的日志段文件来写入,避免单个文件过大,影响文件的读写性能,这个过程叫作log rolling,正在被写入的那个日志段文件,叫作active log segment。

若是你们有看前面的两篇有关于HDFS的文章时,就会发现NameNode的edits log也会作出限制,因此这些框架都是会考虑到这些问题。

Kafka的网络设计 Kafka的网络设计和Kafka的调优有关,这也是为何它能支持高并发的缘由。 13.png

首先客户端发送请求所有会先发送给一个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网络线程模型。

※部分文章来源于网络,若有侵权请联系删除;更多文章和资料|点击后方文字直达 ↓↓↓ 100GPython自学资料包 阿里云K8s实战手册 [阿里云CDN排坑指南]CDN ECS运维指南 DevOps实践手册 Hadoop大数据实战手册 Knative云原生应用开发指南 OSS 运维实战手册 云原生架构白皮书 Zabbix企业级分布式监控系统源码文档 10G大厂面试题戳领

相关文章
相关标签/搜索