那些年咱们用过的消息中间件-kafka

为什么须要音讯队列

周末无聊刷着手机,某宝网APP忽然蹦出来一条音讯“为了回馈老客户,女朋友买一送一,流动仅限明天!”。

买一送一还有这种坏事,那我可不能错过!忍不住立马点了去。于是选了两个最新款,下单、领取零打碎敲!满足的躺在床上,想着马上有女朋友了,居然幸福的失眠了……

第二天失常上着班,忽然接到快递小哥的电话:

小哥:“你是xx吗?你的女朋友到了,我当初在你楼下,你来拿一下吧!”。\
我:“这……我在下班呢,能够早晨送过来吗?“。\
小哥:“早晨可不行哦,早晨我也上班了呢!”。

于是两个人僵持了很久……

最初小哥说,要不我帮你放到楼下小芳便利店吧,你早晨上班了过去拿,难堪的场面这才得以缓解!

回到正题,如果没有小芳便利店,那快递小哥和我的交互图就应该如下:
  

会呈现什么状况呢?

1、为了这个女朋友,我销假回去拿(老板不批)。

2、小哥始终在你楼下等(小哥还有其余的快递要送)。

3、周末再送(显然等不及)。

4、这个女朋友我不要了(相对不可能)!

小芳便利店呈现后,交互图就应如下:
  

  在下面例子中,“快递小哥”和“买女朋友的我”就是须要交互的两个零碎,小芳便利店就是咱们本文要讲的-“消息中间件”。总结下来小芳便利店(消息中间件)呈现后有如下益处:

1、 解耦

快递小哥手上有很多快递须要送,他每次都须要先电话一一确认收货人是否有空、哪个时间段有空,而后再确定好送货的计划。这样齐全依赖收货人了!如果快递一多,快递小哥预计的忙疯了……如果有了便利店,快递小哥只须要将同一个小区的快递放在同一个便利店,而后告诉收货人来取货就能够了,这时候快递小哥和收货人就实现理解耦!

2、 异步

快递小哥打电话给我后须要始终在你楼下等着,直到我拿走你的快递他能力去送其他人的。快递小哥将快递放在小芳便利店后,又能够干其余的活儿去了,不须要期待你到来而始终处于期待状态。进步了工作的效率。

3、 削峰

假如双十一我买了不同店里的各种商品,而凑巧这些店发货的快递都不一样,有中通、圆通、申通、各种通等……更巧的是他们都同时到货了!中通的小哥打来电话叫我去北门取快递、圆通小哥叫我去南门、申通小哥叫我去东门。我一时慌手慌脚……

咱们能看到在零碎须要交互的场景中,应用音讯队列中间件真的是好处多多,基于这种思路,就有了丰巢、菜鸟驿站等比小芳便利店更业余的“中间件”了。

最初,下面的故事纯属虚构……

音讯队列通信的模式

通过下面的例子咱们引出了消息中间件,并且介绍了音讯队列呈现后的益处,这里就须要介绍音讯队列通信的两种模式了:

一、 点对点模式

如上图所示,点对点模式通常是基于拉取或者轮询的音讯传送模型,这个模型的特点是发送到队列的音讯被一个且只有一个消费者进行解决。生产者将音讯放入音讯队列后,由消费者被动的去拉取音讯进行生产。点对点模型的的长处是消费者拉取音讯的频率能够由本人管制。然而音讯队列是否有音讯须要生产,在消费者端无奈感知,所以在消费者端须要额定的线程去监控。

二、 公布订阅模式

如上图所示,公布订阅模式是一个基于音讯送的音讯传送模型,改模型能够有多种不同的订阅者。生产者将音讯放入音讯队列后,队列会将音讯推送给订阅过该类音讯的消费者。因为是消费者被动接管推送,所以无需感知音讯队列是否有待生产的音讯!然而consumer1、consumer2、consumer3因为机器性能不一样,所以解决音讯的能力也会不一样,但音讯队列却无奈感知消费者生产的速度!所以推送的速度成了公布订阅模模式的一个问题!假如三个消费者处理速度别离是8M/s、5M/s、2M/s,如果队列推送的速度为5M/s,则consumer3无奈接受!如果队列推送的速度为2M/s,则consumer1、consumer2会呈现资源的极大节约!

Kafka

下面简略的介绍了为什么须要音讯队列以及音讯队列通信的两种模式,接下来就到了咱们本文的配角——kafka闪亮退场的时候了!Kafka是一种高吞吐量的分布式公布订阅音讯零碎,它能够解决消费者规模的网站中的所有动作流数据,具备高性能、长久化、多正本备份、横向扩大能力………

基础架构及术语

话不多说,先看图,通过这张图咱们来捋一捋相干的概念及之间的关系:

如果看到这张图你很懵逼,木有关系!

咱们先来剖析相干概念

Producer:Producer即生产者,音讯的产生者,是音讯的入口。

kafka cluster

Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,咱们权且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不反复的编号,如图中的broker-0、broker-1等……

Topic:音讯的主题,能够了解为音讯的分类,kafka的数据就保留在topic。在每个broker上都能够创立多个topic。

Partition:Topic的分区,每个topic能够有多个分区,分区的作用是做负载,进步kafka的吞吐量。同一个topic在不同的分区的数据是不反复的,partition的表现形式就是一个一个的文件夹!

Replication:每一个分区都有多个正本,正本的作用是做备胎。当主分区(Leader)故障的时候会抉择一个备胎(Follower)上位,成为Leader。在kafka中默认正本的最大数量是10个,且正本的数量不能大于Broker的数量,follower和leader相对是在不同的机器,同一机器对同一个分区也只可能寄存一个正本(包含本人)。

Message:每一条发送的音讯主体。

Consumer:消费者,即音讯的生产方,是音讯的进口。

Consumer Group:咱们能够将多个消费者组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者生产。同一个消费者组的消费者能够生产同一个topic的不同分区的数据,这也是为了进步kafka的吞吐量!

Zookeeper:kafka集群依赖zookeeper来保留集群的的元信息,来保证系统的可用性。

工作流程剖析

  下面介绍了kafka的基础架构及基本概念,不晓得大家看完有没有对kafka有个大抵印象,如果对还比拟懵也没关系!咱们接下来再联合下面的结构图剖析kafka的工作流程,最初再回来整个梳理一遍我置信你会更有播种!

发送数据

咱们看下面的架构图中,producer就是生产者,是数据的入口。留神看图中的红色箭头,Producer在写入数据的时候永远的找leader,不会间接将数据写入follower!那leader怎么找呢?写入的流程又是什么样的呢?咱们看下图:

发送的流程就在图中曾经阐明了,就不独自在文字列出来了!须要留神的一点是,音讯写入leader后,follower是被动的去leader进行同步的!producer采纳push模式将数据公布到broker,每条音讯追加到分区中,程序写入磁盘,所以保障同一分区内的数据是有序的!写入示意图如下:

下面说到数据会写入到不同的分区,那kafka为什么要做分区呢?置信大家应该也能猜到,分区的次要目标是:

1、 不便扩大。因为一个topic能够有多个partition,所以咱们能够通过扩大机器去轻松的应答日益增长的数据量。

2、 进步并发。以partition为读写单位,能够多个消费者同时生产数据,进步了音讯的解决效率。

相熟负载平衡的敌人应该晓得,当咱们向某个服务器发送申请的时候,服务端可能会对申请做一个负载,将流量散发到不同的服务器,那在kafka中,如果某个topic有多个partition,producer又怎么晓得该将数据发往哪个partition呢?

kafka中有几个准则:

1、 partition在写入的时候能够指定须要写入的partition,如果有指定,则写入对应的partition。

2、 如果没有指定partition,然而设置了数据的key,则会依据key的值hash出一个partition。

3、 如果既没指定partition,又没有设置key,则会轮询选出一个partition。

保障音讯不失落是一个音讯队列中间件的根本保障,那producer在向kafka写入音讯的时候,怎么保障音讯不失落呢?其实下面的写入流程图中有形容进去,那就是通过ACK应答机制!在生产者向队列写入数据的时候能够设置参数来确定是否确认kafka接管到数据,这个参数可设置的值为01all

0代表producer往集群发送数据不须要等到集群的返回,不确保音讯发送胜利。安全性最低然而效率最高。

1代表producer往集群发送数据只有leader应答就能够发送下一条,只确保leader发送胜利。

all代表producer往集群发送数据须要所有的follower都实现从leader的同步才会发送下一条,确保leader发送胜利和所有的正本都实现备份。安全性最高,然而效率最低。

最初要留神的是,如果往不存在的topic写数据,能不能写入胜利呢?kafka会主动创立topic,分区和正本的数量依据默认配置都是1。

保留数据

  Producer将数据写入kafka后,集群就须要对数据进行保留了!kafka将数据保留在磁盘,可能在咱们的个别的认知里,写入磁盘是比拟耗时的操作,不适宜这种高并发的组件。Kafka初始会独自开拓一块磁盘空间,程序写入数据(效率比随机写入高)。

Partition 构造

  后面说过了每个topic都能够分为一个或多个partition,如果你感觉topic比拟形象,那partition就是比拟具体的货色了!Partition在服务器上的表现形式就是一个一个的文件夹,每个partition的文件夹上面会有多组segment文件,每组segment文件又蕴含.index文件、.log文件、.timeindex文件(晚期版本中没有)三个文件, log文件就理论是存储message的中央,而index和timeindex文件为索引文件,用于检索音讯。

  如上图,这个partition有三组segment文件,每个log文件的大小是一样的,然而存储的message数量是不肯定相等的(每条的message大小不统一)。文件的命名是以该segment最小offset来命名的,如000.index存储offset为0~368795的音讯,kafka就是利用分段+索引的形式来解决查找效率的问题。

Message构造
下面说到log文件就理论是存储message的中央,咱们在producer往kafka写入的也是一条一条的message,那存储在log中的message是什么样子的呢?音讯次要蕴含音讯体、音讯大小、offset、压缩类型……等等!咱们重点须要晓得的是上面三个:

1、 offset:offset是一个占8byte的有序id号,它能够惟一确定每条音讯在parition内的地位!

2、 音讯大小:音讯大小占用4byte,用于形容音讯的大小。

3、 音讯体:音讯体寄存的是理论的音讯数据(被压缩过),占用的空间依据具体的音讯而不一样。

存储策略

  无论音讯是否被生产,kafka都会保留所有的音讯。那对于旧数据有什么删除策略呢?

1、 基于工夫,默认配置是168小时(7天)。

2、 基于大小,默认配置是1073741824。

须要留神的是,kafka读取特定音讯的工夫复杂度是O(1),所以这里删除过期的文件并不会进步kafka的性能!

生产数据

  音讯存储在log文件后,消费者就能够进行生产了。与生产音讯雷同的是,消费者在拉取音讯的时候也是找leader去拉取。

  多个消费者能够组成一个消费者组(consumer group),每个消费者组都有一个组id!同一个生产组者的消费者能够生产同一topic下不同分区的数据,然而不会组内多个消费者生产同一分区的数据!!!是不是有点绕。咱们看下图:

  图示是消费者组内的消费者小于partition数量的状况,所以会呈现某个消费者生产多个partition数据的状况,生产的速度也就不迭只解决一个partition的消费者的处理速度!如果是消费者组的消费者多于partition的数量,那会不会呈现多个消费者生产同一个partition的数据呢?下面曾经提到过不会呈现这种状况!多进去的消费者不生产任何partition的数据。所以在理论的利用中,倡议消费者组的consumer的数量与partition的数量统一

  在保留数据的大节外面,咱们聊到了partition划分为多组segment,每个segment又蕴含.log、.index、.timeindex文件,寄存的每条message蕴含offset、音讯大小、音讯体……咱们屡次提到segment和offset,查找音讯的时候是怎么利用segment+offset配合查找的呢?如果当初须要查找一个offset为368801的message是什么样的过程呢?咱们先看看上面的图:

  1、 先找到offset的368801message所在的segment文件(利用二分法查找),这里找到的就是在第二个segment文件。

  2、 关上找到的segment中的.index文件(也就是368796.index文件,该文件起始偏移量为368796+1,咱们要查找的offset为368801的message在该index内的偏移量为368796+5=368801,所以这里要查找的绝对offset为5)。因为该文件采纳的是稠密索引的形式存储着绝对offset及对应message物理偏移量的关系,所以间接找绝对offset为5的索引找不到,这里同样利用二分法查找绝对offset小于或者等于指定的绝对offset的索引条目中最大的那个绝对offset,所以找到的是绝对offset为4的这个索引。

  3、 依据找到的绝对offset为4的索引确定message存储的物理偏移地位为256。关上数据文件,从地位为256的那个中央开始程序扫描直到找到offset为368801的那条Message。

  这套机制是建设在offset为有序的根底上,利用segment+有序offset+稠密索引+二分查找+程序查找等多种手段来高效的查找数据!至此,消费者就能拿到须要解决的数据进行解决了。

那每个消费者又是怎么记录本人生产的地位呢?在晚期的版本中,消费者将生产到的offset保护zookeeper中,consumer每距离一段时间上报一次,这里容易导致反复生产,且性能不好!在新的版本中消费者生产到的offset曾经间接保护在kafk集群的__consumer_offsets这个topic中!

起源:17coding技术博客
近期热文举荐:

1.600+ 道 Java面试题及答案整顿(2021最新版)

2.终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!

5.《Java开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!