kafka简介一(初识kafka)


从这一章节开始,我们开始学习MQ kafka。

简介

Apache Kafka 是Apache软件基金会的开源的流处理平台,提供了消息的订阅与发布,是一种消息队列,一般的作用如下:

  • 系统间解耦
  • 异步通信
  • 削峰填谷

为了方便理解,举个例子:
现有一个系统,会员登录之后,如果发现当前是会员的生日,则通过邮件发送祝福。
在这里插入图片描述
很明显这个流程是有问题的:

  1. 将发送祝福的逻辑,与用户等了进行强耦合,是否合适?
  2. 如果用户等了成功,但是 短信/邮件 网关出现故障了,导致祝福没有发送出去,用户始终在等待登录结果,是否合适?

显然这两种情况都不合适,如果我们在中间加入消息队列:
在这里插入图片描述
用户登录即刻通知用户登录成功,同时将登录消息放入消息队列,通过异步方式通知后续的短信,邮件服务,在服务内部判断是否生日,然后再发送祝福。即便网关出现问题,并不影响用户的登录。

削峰填谷,主要是用在大数据的流处理中,避免同一时间的超大量请求打爆服务。

消息队列(MQ)

上面已经讲过了,kafka是一种消息队列,那消息队列又是啥呢?

消息队列,是一种在分布式和大数据开发中不可或缺的中间件,一般有下面两种大类:

  • 至多一次:生产者将消息写入队列系统后,由消费者负责去拉取消息,一旦确定消息被消费之后,消息队列系统需要主动删除队列中的数据,这种消费方式,一般只允许被一个消费者消费,并且队列中的数据,不允许被重复消费。
  • 没有限制:与上面不同,产生的消息,可以被多个消费者同时消费,并且同一个消费者可以多次消费消息服务器中的同一个记录。

kafka架构

先介绍几个名词:

  • Record:记录,即消息本身
  • Topic:消息的主题,Topic负责分类集群中的Record,每一个Record都会归属于一个Topic。它是消息存储的逻辑概念,是一类消息的集合,在物理上,不同的Topic的消息是分开存储的。
  • Partition:分区,每一个Topic可以划分为多个Partition,同一个Topic下的不同分区消息是不一样的,是将一个Topic下的数据进行了拆分存储进不同的Partition,Topic是逻辑存储概念,具体的磁盘存储是基于Partition。
  • Borker:即一个kafka的实例,Topic的每一个分区,都一定会有一个Borker担当该分区的leader,其他的Broker为该分区的follower。
    leader负责分区数据的读写,follower负责同步该分区的数据。如果该分区的leader宕机,其他的follower会选出一个新的leader。
  • zookeeper:监控集群中的leader,同时存储Topic的部分元数控

在这里插入图片描述
生产者,将每一个Record指定Topic之后,发送给kafka集群,消费者在订阅了Topic之后,kafka将相应的Record推送给消费者。

在kafka内部,针对一个Topic,消息是如何存储的呢?
在这里插入图片描述
上面我们已经提到过,每个Topic在存储时,是按照Partition进行的,当生产者产生出一个Record之后,是如何决定数据最终落在哪个Partition呢?
一个Recode一般包含key,value以及这条消息的时间戳。
对key进行hash后,对分区的数量进行取模,取模结果即为最终落的Partition。
假设现在一个topic下有3个分区,key的hash值为4,那最终落的Partition为4%3=1,即为第一个分区。

那kafka又是如何对一个Topic下的所有数据进行存储的呢?
假设现在kafka集群有3个Broker,针对该Topic,每个Broker都会持有该Topic下的3个分区,以第一个分区Partition0为例,Broker0为Partition0的leader,Broker1,Broker2t同样持有Partition0的数据,但是他们都是follower,一旦Broker0宕机了,Broker1和Broker2中的一台会成为新的leader,继续对Partition0提供读写。这块后面会详细介绍。

那如果集群中有5个Broker,是否每一个Broker都会有Partition0呢?并不是,一个Partition有多少个数据备份,是由 分区/副本 因子决定的,如果因子是3,则最多只会有3份

存储有序性

在这里插入图片描述
kafka保证每个Partition内的Record是有序的,每一个Record都被分配了一个唯一的编号offset,此即为单分区有序。

是不是注意到了一个问题呢,消息以Topic进行发送,但是一个Topic下可以有多个Partition,单个Partition是有序的,那多个Partition会怎么样呢?答案是无序的。

比如:生产者发出了4条消息,Record1进入分区1,Record2进入分区2,Record3进入分区1,Record4进入分区3,仅能保证在分区1内,Record1和Record2是有序存储的。
那如果4条消息,如何有序存储呢?将4条消息依次写入同一个Partition就可以了。或者该Topic只有一个分区,但是这个会影响消费的效率。

按照我们对于队列的理解,应该都是先进先出的,但是目前看起来,kafka只能局部保证消息先进先出,那为什么kafka要搞出个分区的概念来破坏消息的先进先出机制呢?试想一下,如果一个Topic有100个Partition,每个Partition容量一个T,那那个Topic下就可以存储100T的数据,而且有高可用的灾备,是不是很激动?

存储时效性

kafka会持久化Topic中的每个Record,持久化时间,默认是168小时,即7天时间。可以通过配置:log.retention.hours=168进行调整。
kafka会定期检测日志文件,将过期的数据从磁盘中移除。
之前很好奇为什么公司es的日志查询有效期是7天,大概率是因为这个。

消费者消费数据

消费者在消费数据时,每个消费者都会维护本次消费对应的Partition的偏移量offset,消费者在消费完一个批次的数据之后,会将偏移量offset提交各kafka集群。
可以看出,每个消费者是可以自定义消息的offset,有了从Topic的分区中任意位置拉取消息的能力,并且由于是各玩各的,故而每个消费者之间相互独立。
在这里插入图片描述

消费组 Consumer Group

既然是一个group,那肯定是一个消费者的集合了。

想象一下:

  1. 如果一个Topic下有1T的数据等待消费,如果只有一个消费者,每一消费需要50ms,那得消费到啥时候去?
  2. 现在有一个Topic,有3个消费者,任何这3个消费者都想订阅消费,咋通知呢?

这个时候,我们的Consumer Group便可以大显身手了。可以简单粗暴的理解为一个group为一个单独的业务线。

举一个简单的例子,不一定贴切:
现在有一个合同(Topic),有两家公司(Consumer group),每家公司下有10名员工(Consumer),两家公司都想要这份合同(消费消息),咋办呢?最后商议,两家公司各处一名员工来处理合同。
至此,可以简单的理解为,一个Topic下的消息,发送到多个group,从每个group中挑选出一个Consumer来消费该Record。感觉还是蛮形象的哈~

结合上文所讲,一个Topic有多个Partition,现在一个Consumer group下有多个Consumer,正好多对多,是不是可以建立联系呢?

在这里插入图片描述
一个Topic下的多个Partition,会均分到一个group中的每个customer,是不是没看懂呢?
已上图为例:
一个Topic下有4个Partition,group1有2个customer,group2下有4个customer,咋分呢?
对于group1,2个customer要接管4个Partition,很显然,一个customer负责消费2个Partition
对于group1,4个customer对4个Partition,正好,一对一。

还是上面这张图,如有下面几个问题:

  1. 一个Partition下的数据会不会同时被一个group下不同的customer消费:不能,这相当在一家公司A中,合同已经给了员工甲,但是员工乙偷偷地做,这种属于重复消费。
  2. 一个Partition下的数据会不会同时被不同group下的customer消费:能,这种就是上文例子中的,一份合同,同时给了AB两家公司的甲乙两名员工。
  3. 同一个topic,group1和group2谁消费会快?很明显是group2,group2中每一个customer只要消费处理一个Partition,而group1中每个customer却需要处理2个Partition
  4. 如果在group2中再添加一名customer,能加快速度吗?不能,因为已经没有多余的Partition能给这个新增者来消费了。

通过以上几个问题,我们可以得出结论,一般Partition的数量,等于group下的customer的数量,这种配比,效率是最高的。

高吞吐

kafka在普通机器上,都可以实现每秒百万级的写入,kafka是怎么实现的呢?

  • 顺序写入
    磁盘写入时IO费时间,主要是花在了”寻址“上面,机械硬盘需要不断移动磁头来写入文件,随机I/O会大大增加寻址的频率。
    kafka文件顺序写入,大大节省了寻址时间。
  • mmap,重复利用操作系统的分页存储,利用内存来提高I/O效率。Memory Mapped Files,内存映射文件。将物理内存直接映射到操作系统内存,由操作系统实现从内存直接写入磁盘。
  • 零拷贝:kafka在响应请求时,从磁盘读取数据后,不将数据copy进用户空间,而是直接在操作系统的内核空间直接将数据传出去。
    在这里插入图片描述
    经典的通讯模型如图,数据先从磁盘copy进内核空间,再从内核空间copy进用户空间,再从应用层copy进网卡等socket buffer,最后再copy出通过网络传输出去,中间经历了4次copy。

在这里插入图片描述
零拷贝,不经过应用层,直接在内核内存中copy进buffer,减少一次无意义的copy。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章