Kafka--消息队列、架构

概述

1.kafka简介

kafka最初是由Linkedin公司开发,是一个分布式支持分区的(partition)、多副本的(replication),基于zookeeper协调的分布式消息系统。2010年贡献给了Apache基金会。

它是开源的流处理平台,该平台提供了消息的订阅与发布的消息队列,一般用作系统间解耦异步通信削峰填谷等作用。

1.1 为什么要用kafka
在一些业务中,比如用户注册的业务。用户进行注册时会进行短信验证。
在普通情况下,用户注册信息填写完成,发送短信验证时,用户会等待着短信验证成功后,注册才会成功。但是,用户注册和短信验证时两个模块,在用户的角度下,只需要注册的数据存入数据库即可,并不需要管短信是否验证成功。所以,这种情况用户注册和短信验证之间存在着强耦合。

用了kafka后,可以把短信验证的消息存入消息队列中,这时短信服务只需要到消息队列中抓取消息,并将通知返回用户即可,大大加快了效率。

1.2 消息队列
消息队列是一种在分布式和大数据开发中不可或缺的中间件。在分布式或者大数据开发中通常使用消息队列进行缓冲、系统间解耦合和削峰填谷等业务场景,常见的消息队列服务工作模式大致分为两大类:
1)点对点模式(一对一,消费者主动拉取消息,收到消息后消息清除)

  • 至多一次:消息生产者将数据写入消息系统,然后由消费者负责去拉取消息服务器中的消息,一旦消息被确认消费之后,由消息服务器主动删除队列中的数据,只允许被一个消费者消费,并且消息队列中的数据不允许被重复消费。
    2)发布/订阅模式(一对多,消费者消费消息后不会清除)
  • 没有限制:同上述消费形式不同,生产者发布完数据以后,该消息可以被多个消费者同时消费,并且同一个消费者可以多次消费消息服务器中的同一个记录。主要是因为消息服务器一般可以长时间存储海量消息。

1.3 消息队列的好处
1)解耦
允许独立的修改和扩展两边的处理过程,只要确保遵守同样的接口约束。
2) 可恢复性
系统的一部分组件失效时,不会影响整个的系统。即使一个处理消息的进程挂掉,也会在恢复后再处理。
3)缓冲
解决生产速度和消费速度不一致的问题。
4)灵活性、削峰处理
5)异步通信

2.kafka

1.kafka特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失。
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)。
  • 高并发:支持数千个客户端同时读写。

2.kafka的使用场景

  • 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
  • 消息系统:解耦和生产者和消费者、缓存消息等。
  • 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。

基础架构

日志、分区

Kafka集群以Topic形式负责分类集群中的Record,每一个Record属于一个Topic,生产者发送数据到Kafka集群中的某一个Topic中,同时消费者可以订阅kafka集群中的Topic。
在这里插入图片描述
每个Topic底层都会有一组分区日志,用来持久化Topic中的Record。每个分区日志中都会有一个Borker担当该分区的Leader,其他的Broker担当该分区的follower,**Leader负责分区数据的读写操作,follower负责同步改分区的数据。**这样如果分区的Leader宕机,改分区的其他follower会选取出新的leader继续负责该分区数据的读写。

在其中还有zookeeper集群,用来监控Leader和存储Topic的元数据信息。

总结:kafka集群是以Topic来进行记录的分类。而每个Topic中存在着分区日志,作用是持久化Topic的记录。为了数据的执行效率,可以将分区设置为多个,同时防止一个机器宕机导致数据丢失,可以设置副本数(副本数不能超过broker的数量,多出的没有意义)。每一个分区都会有一个Leader,其他的Broker担当该分区的follower。Leader负责分区的读写,follower负责同步分区的数据。而zookeeper会监控Leader和存储Topic的元数据信息。

在这里插入图片描述

生产者

生产者将数据发布到他们选择的Topic。生产者负责选择将哪个记录分配给Topic中的哪个Partition。可以以round-robin(轮询)方式完成此操作,仅是为了平衡负载,也可以根据某些语义分区功能(例如基于记录中的Key)进行此操作

Kafka中所有消息是通过Topic为单位进行管理,每个Kafka中的Topic通常会有多个订阅者,负责订阅发送到该Topic中的数据。每个在Kafka 集群中的Topic,Kafka负责管理该Topic的一组日志分区:
在这里插入图片描述
每组日志分区是一个有序的不可变的的日志序列,分区中的每一个Record都被分配了唯一的序列编号称为是offset,Kafka 集群会持久化所有发布到Topic中的Record信息,改Record的持久化时间是通过配置文件指定,默认是168小时。

**注意:**在分区中的Record是有序的,而在一个Topic中的分区的顺序是不确定的。相当于一个大管子中有三个小管子,它们可以一起出去,也可以一个一个出去。是不确定的。

Kafka底层会定期的check日志文件,然后将过期的数据从log中移除,由于Kafka使用硬盘存储日志文件,因此使用Kafka长时间缓存一些日志文件是不存在问题的。

消费组

在消费者消费Topic中数据的时候,每个消费者会维护本次消费对应分区的偏移量,消费者会在消费完一个批次的数据之后,会将本次消费的偏移量提交给Kafka集群,因此对于每个消费者而言可以随意的控制改消费者的偏移量。因此在Kafka中,消费者可以从一个topic分区中的任意位置读取队列数据,由于每个消费者控制了自己的消费的偏移量,因此多个消费者之间彼此相互独立。消费者使用ConsumerGroup名称标记自己,并且发布到Topic的每条记录都会传递到每个订阅ConsumerGroup中的一个消费者实例。如果所有Consumer实例都具有相同的ConsumerGroup,那么Topic中的记录会在改ConsumerGroup中的Consumer实例进行均分消费;如果所有Consumer实例具有不同的ConsumerGroup,则每条记录将广播到所有ConsumerGroup进程。
在这里插入图片描述

同组均分,不同组广播(共享)

更常见的是,我们发现Topic具有少量的Consumer Group,每个ConsumerGroup可以理解为一个“逻辑的订阅者”。每个ConsumerGroup均由许多Consumer实例组成,以实现可伸缩性和容错能力。这无非就是发布-订阅模型,其中订阅者是消费者的集群而不是单个进程。这种消费方式Kafka会将Topic按照分区的方式均分给一个ConsumerGroup下的实例,如果ConsumerGroup下有新的成员介入,则新介入的Consumer实例会去接管ConsumerGroup内其他消费者负责的某些分区,同样如果一下ConsumerGroup下的有其他Consumer实例宕机,则由改ConsumerGroup其他实例接管。

由于Kafka的Topic的分区策略,因此Kafka仅提供分区中记录的有序性,也就意味着相同Topic的不同分区记录之间无顺序。因为针对于绝大多数的大数据应用和使用场景, 使用分区内部有序或者使用key进行分区策略已经足够满足绝大多数应用场景。但是,如果您需要记录全局有序,则可以通过只有一个分区Topic来实现,尽管这将意味着每个ConsumerGroup只有一个Consumer进程。

kafka相比其他系统的优势有哪些?
  • 写操作:顺序写入
    Kafka的特性之一就是高吞吐率,但是Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的。
    Kafka会把收到的消息都写入到硬盘中,防止丢失数据。为了优化写入速度Kafka采用了两个技术, 顺序写和MMFile

顺序写:因为硬盘是机械结构,每次读写都会寻址,然后写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最讨厌随机I/O,最喜欢顺序I/O。为了提高读写硬盘的速度,Kafka就是使用顺序I/O。这样省去了大量的内存开销以及节省了IO寻址的时间。但是单纯的使用顺序写入,Kafka的写入性能也不可能和内存进行对比,因此Kafka的数据并不是实时的写入硬盘中。

MMFile:Kafka充分利用了现代操作系统分页存储来利用内存提高I/O效率。Memory Mapped Files(后面简称mmap)也称为内存映射文件,在64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成MMP映射后,用户对内存的所有操作会被操作系统自动的刷新到磁盘上,极大地降低了IO使用率。

在写的时候,kafka只需要将数据写入到内核空间的缓存中即可,什么时候刷新由操作系统决定。
在这里插入图片描述

  • 读操作:ZeroCopy

Kafka服务器在响应客户端读取的时候,底层使用ZeroCopy技术,直接将磁盘无需拷贝到用户空间,而是直接将数据通过内核空间传递输出,数据并没有抵达用户空间。常规的IO操作流程如下:
在这里插入图片描述

1.用户进程调用read等系统调用向操作系统发出IO请求,请求读取数据到自己的内存缓冲区中。自己进入阻塞状态

2.操作系统收到请求后,进一步将IO请求发送磁盘

3.磁盘驱动器收到内核的IO请求,把数据从磁盘读取到驱动器的缓冲中。此时不占用CPU。当驱动器的缓冲区被读满后,向内核发起中断信号告知自己缓冲区已满

4.内核收到中断,使用CPU时间将磁盘驱动器的缓存中的数据拷贝到内核缓冲区中。

5.如果内核缓冲区的数据少于用户申请的读的数据,重复步骤3跟步骤4,直到内核缓冲区的数据足够多为止。

6.将数据从内核缓冲区拷贝到用户缓冲区,同时从系统调用中返回完成读取任务

缺点:用户的每次IO请求,都需要CPU多次参与。

现代操作系统大都引入了协处理器的概念,也就是说系统在读取的磁盘文件的时候,无需CPU直接参与。而是将数据读取的任务交给DMA控制器,负责辅助CPU完成数据的读取过程。
在这里插入图片描述
1.用户进程调用read等系统调用向操作系统发出IO请求,请求读取数据到自己的内存缓冲区中。自己进入阻塞状态。

2.操作系统收到请求后,进一步将IO请求发送DMA。然后让CPU干别的活去。

3.DMA进一步将IO请求发送给磁盘。

4.磁盘驱动器收到DMA的IO请求,把数据从磁盘读取到驱动器的缓冲中。当驱动器的缓冲区被读满后,向DMA发起中断信号告知自己缓冲区已满。

5.DMA收到磁盘驱动器的信号,将磁盘驱动器的缓存中的数据拷贝到内核缓冲区中。此时不占用CPU。这个时候只要内核缓冲区的数据少于用户申请的读的数据,内核就会一直重复步骤3跟步骤4,直到内核缓冲区的数据足够多为止。

6.当DMA读取了足够多的数据,就会发送中断信号给CPU。

7.CPU手动DMA的信号,知道数据已经准备好,于是将数据从内核拷贝到用户空间,系统调用返回。

跟IO中断模式相比,DMA模式下,DMA就是CPU的一个代理,它负责了一部分的拷贝工作,从而减轻了CPU的负担。DMA的优点就是:中断少,CPU负担低。

在了解底层操作系统的IO操作以后,我们来看一下网络场景。文件在磁盘中数据被copy到内核缓冲区 ->从内核缓冲区copy到用户缓冲区->用户缓冲区copy到内核与socket相关的缓冲区-> 数据从socket缓冲区copy到相关协议引擎发送出去。

在这里插入图片描述

从上图可以看出,默认数据需要从内核到用户在到内核空间的这么一个过程是多余的,所谓ZeroCopy的做法是直接在内核中将数据发送出去,因此节省了1次拷贝。文件在磁盘中数据被copy到内核缓冲区->从内核缓冲区copy到内核与socket相关的缓冲区->数据从socket缓冲区copy到相关协议引擎发送出去。

在这里插入图片描述

所谓零Copy指的是用户空间中的copy次数为0.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值