kafka-整理-01-基础-架构-工作流-文件存储

整理了对kafka消息队列的一些理解,和一些实际应用,可能也有一些面试常问的一些点;

 


前言:

一:消息队列的两种模式

  • 点对点模式(一对一)
    • 消费者主动拉取数据,收到消息后清除;
    • 一个queue支持多个消费者,但是对一个消息来说,只能被一个消费者消费;​​​​​​
  • 发布订阅模式(一对多)
    • 消费者消费到数据后,不会删除消息
    • 发布给topic中的消息,会被所有的订阅者消费到;

其中kafka是基于发布订阅模式的,主动拉取数据,并消费后不会删除消息;

二:发布订阅模式中又分两种?

1:队列主动推数据(推模式-push):消息中间件主动将消息推送给消费者

2:消费者主动拉数据(拉模式-pull):消费者主动从消息中间件拉去消息

特点:

  • 拉取模式特点(pull):
    • 拉取模式是消费者主动获取数据的,采用长轮询机制,不间断的过两秒钟去询问,有没有新的消息过来,
    • 若是消费者消费不过来,可以根据一定的策略停止拉取,或者间隔拉取;
    • 优点:
      • 适合批量发送
        • 推模式是来一个消息就推,也可以缓存一批消息后推送,但是推模式的缺点也很明显,不清楚消费者的能力和状态,
        • 而拉模式可以参考消费者的状态,来决定一次缓存多少消息后批量发送;
    • 缺点:
      • 消息延迟
        • 拉模式是消费者主动拉取数据的,是不清楚什么时候有消息的,所以只能不断地去轮询,但又要控制好轮询的频率,不然生产者压力就很大;
      • 耗费性能
        • 若是生产者没有消息,消费者还是要不停的去轮询,比较浪费资源
  • 推送模式特点(push):
    • 生产者强制推消息给消费者;
    • 消息实时性高,生产者接收到消息后,会立马推送给消费者;
    • 对于消费者来说比较简单,只需要等消息推送过来就行了;
    • 缺点:
      • 推送速率难以适应消费速率
        • 推模式的目标就是为了以最快的速度推送消息,当生产者发送消息的速率大于消费者消费消息的速率时,随着时间的增长,消费者可能会挤压很多的消息,导致消费者消费不过来;
    • 场景:适用于消息量不大,要求实时性高的场景,根据消费者的状态控制推送速率;

总结:

rabbitmq默认是推模式,但是它也支持拉模式;

rocketMq和kafka都选择了拉模式;而且都是利用“长轮询”来实现的拉模式;

activityMq就是标准的基于推模式的消息队列;

扫描二维码关注公众号,回复: 13515192 查看本文章

1:kafka简单了解

  • kafka依赖的环境:java,zookeeper(用于保存broker的元数据信息)
  • consumergroup:各个consumer可以组成一个组,每个消息只能被组中的一个consumer消费,如果一个消息可以被多个consumer消费的话,那么这些consumer必须在不同的组。
    • kafka 允许多个消费组同时订阅一个topic,不同的消费组可以对同一条消息进行重复消费,并不进行互斥。比如有消费组A和消费组B,都订阅了topic xxx,当生产者C发布一个topic为xxx的消息,消费组A和消费组B都会收到消息。
  • 消息状态: 在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向 partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。
  • 消息持久化:Kafka中会把消息持久化到本地文件系统中,并且保持极高的效率。
  • 消息有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。
    • kafak不会删除已经消费的消息,而是不管消息是否消费都一并按照broker的配置保留一段时间,如broker配置保留2天,那就统一保留2天
  • Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。
  • 负载均衡方面: Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)。
  • 分区机制partition:Kafka的broker端支持消息分区,Producer可以决定把消息发到哪个分区,在一个分区中消息的顺序就是Producer发送消息的顺序,一个主题中可以有多个分区,具体分区的数量是可配置的。
    • 一个 topic 可以分布到多个 broker(即服务器)上
    • 一个 topic 可以分为多个 partition
    • 每个 partition 是一个有序的队列

2:kafka架构

1:kafka集群:broker(一台启动了kafka进程的服务器)

这里是kafka存储数据的地方;存储在topic;

2:Topic:(主题):作为消息的分类,根据业务区分的;

3:一个主题里面有分区和副本;

分区(partition):用来做某一个主题topic的负载均衡;还可以提高读写的效率(从leader中读写数据)

副本(follower):做数据备份冗余;

4:消费者中有一个消费者组(consumer-group):

   这里面需要考虑消费者组中的消费者消息的分配策略:

   原则一:若:消费者组中有两个消费者,同时订阅了某个topic,那么该topic的消息只能被一个消费者消费;

   原则二:若:一个topic被多个消费者组中的某个消费者订阅了,那么这个topic下发的消息是可以被多个消费者消费的(但是在同一个组内的多个消费者遵循第一个原则);

5:生产者消息分配:

   当一个topic有多个partition分区的时候,生产者有了一个消息,分配给哪个分区呢,生产者也有所谓的分配策略的;

   方式一:直接指定分配给哪一个partition;

   方式二:没有指定partition,但是指定key,根据对key的value进行hash,选出一个partition;

   方式三:partition和key都没有指定,则轮询选出一个partition;

3:kafka工作流程

首选我们要创建一个topic,用于存储消息的;

这个是官方的一个图,这个图表示有一个topic主题,

这个topic里面有三个分区,

生产者往topic写数据,

从这个图可以看出,每一个分区都维护了自己的偏移量offset;

所以这里有一个面试点:

    kafka并不能保证消息的全局有序性,只能在某一个分区里面,是有序的;

3.1:producer发布消息:

  • 写入方式
    • producer 采用 push 模式将消息发布到 broker,每条消息都被 append 到 patition 中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障 kafka 吞吐率)。
  • 消息路由
    • producer 发送消息到 broker 时,会根据分区算法选择将其存储到哪一个 partition。其路由机制为:

      1. 指定了 patition,则直接使用;
      2. 未指定 patition 但指定 key,通过对 key 的 value 进行hash 选出一个 patition
      3. patition 和 key 都未指定,使用轮询选出一个 patition。
  • 写入流程
    • producer 写入消息序列如下所示:
      1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader
      2. producer 将消息发送给该 leader
      3. leader 将消息写入本地 log
      4. followers 从 leader pull 消息,写入本地 log 后 leader 发送 ACK
      5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset) 并向 producer 发送 ACK

3.2:broker保存消息

  • 存储方式
    • 物理上把 topic 分成一个或多个 patition(对应 server.properties 中的 num.partitions=3 配置),每个 patition 物理上对应一个文件夹(该文件夹存储该 patition 的所有消息和索引文件)
  • 存储策略
    • 无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据:

      1. 基于时间:log.retention.hours=168
      2. 基于大小:log.retention.bytes=1073741824

      需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关

4:文件存储

当然这个图有个少的:

其实这里是有三个文件的:

  • .log存储消息文件
  • .index存储消息的索引
  • .timeIndex,时间索引文件,通过时间戳做索引

在kafka中每个topic可以指定多个分区(partition),

而每个partition又可以分为多个segment file:

当生产者往partition中存储数据时,内存中存不下了,就会往segment file里面存储。

为防止log文件过大导致数据定位效率低,kafka采取了分片索引机制,将每个partition分为多个segment(逻辑上的概念,index+log文件)

每个segment file对应两个文件,分别是以【.log】结尾的数据文件和以【.index】结尾的索引文件。在服务器上,每个partition是一个文件夹,每个segment是一个文件。

每个segment file也有自己的命名规则,每个名字有20个字符,不够用0填充。每个名字从0开始命名,下一个segment file文件的名字就是,上一个segment file中最后一条消息的索引值。在.index文件中,存储的是key-value格式的,key代表在.log中按顺序开始第条消息,value代表该消息的位置偏移。但是在.index中不是对每条消息都做记录,它是每隔一些消息记录一次,避免占用太多内存。即使消息不在index记录中,在已有的记录中查找,范围也大大缩小了。

kafka的配置文件:service.properties 配置了一些常见的配置

log.rerention.hours = 168   (这个就是配置了日志文件存在的时间:168小时,也就是7天)

log.segment.bytes = 1072741824 (日志文件最大值:1个G,表示每个segment file文件最大为一个G,超过一个G,再创建一个新的)

message.maxbytes = 6525000 (消息体的最大大小(6M左右),单位是字节)

在segment中查找数据的过程。。。。。。。。。。。。。。

二分查找?索引?偏移量?

百家争鸣,取长补短之道:

kafka工作流:

http://cache.baiducontent.com/c?m=eNjRNCQ3c3CgBMBzbMxoPL0tx0QnEA7cNCotk3abEZjk8Cd2DvhuDCfKiL2cLfXWXk3FR0_IGEiEz75fse1OrNd6ezJC6Zs4rS426KI33dweEZJAGS01vCbkTM1kyHeOKSIui2zEDcb6YzZN1AwwF4O1R2Ts1A38FtFFh93YxHu&p=8b2a970d86cc46af01aec8381b0d&newp=8b2a971f8f8311a05fedc53f555792695d0fc20e3bdcd201298ffe0cc4241a1a1a3aecbf2c251301d1c7776702ae485ce8f232783d0034f1f689df08d2ecce7e75d167&s=cfcd208495d565ef&user=baidu&fm=sc&query=kafak+%D1%A7%CF%B0%B1%CA%BC%C7&qid=ba91919e0019cf20&p1=1

kafka文件存储机制:

https://blog.csdn.net/Poppy_Evan/article/details/79221221?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161884317716780366561103%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161884317716780366561103&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-79221221.pc_search_result_no_baidu_js&utm_term=kafka%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E6%9C%BA%E5%88%B6

-

https://blog.csdn.net/hyunbar/article/details/107588593?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161884317716780366561103%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161884317716780366561103&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-107588593.pc_search_result_no_baidu_js&utm_term=kafka%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E6%9C%BA%E5%88%B6

-

https://blog.csdn.net/wangshuminjava/article/details/84026415?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161884317716780366561103%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161884317716780366561103&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-3-84026415.pc_search_result_no_baidu_js&utm_term=kafka%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E6%9C%BA%E5%88%B6

kafka配置参数解释:

https://www.cnblogs.com/alan319/p/8651434.html

kafka常见生产问题:

https://www.toutiao.com/i6948433866302587406/

https://www.codetd.com/article/12076626

猜你喜欢

转载自blog.csdn.net/u010953880/article/details/115821305