1.消息队列(MQ)
- (1)什么是消息队列?
- 官方定义:消息队列是一种异步的服务间通信方式,是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。
- 简单点说:消息队列MQ用于实现两个系统之间或者两个模块之间传递消息数据时,实现数据缓存
- (2)功能:基于队列的方式,实现消息传递的数据缓存
- 队列的特点:顺序,先进先出
- (3)特点
- ①优点:解耦、实现最终一致性、提高高并发的性能
- ②缺点:运维更加麻烦,安全性保障更加繁琐,必须保证生产数据和消费数据不丢失和不重复
- (4)应用场景
- ①用于所有需要实现实时、高性能、高吞吐、高可靠的消息传递架构中
- ②大数据应用中:作为唯一的实时数据存储平台
- 1)实时数据采集:生产(Kafka写入)
- 2)实时数据处理:消费(Kafka读取)
2.同步与异步
- (1)同步:
- 提交和处理是同步操作,立即就能看到结果,立即一致性
- ①流程
- step1:用户提交请求
- step2:后台处理请求
- step3:将处理的结果返回给用户,用户继续下一步操作
- ②特点
- 用户看到的结果就是我处理好的结果,等待看到结果后,进行下一步
- ③场景
- 去银行存钱、转账等,必须看到真正处理的结果才能表示成功,实现立即一致性
- ④优点:结果肯定是准确的
- ⑤缺点:性能问题(较慢)
- (2)异步:
- 提交和处理是异步操作,最终得到一个处理的结果,最终一致性
- ①流程
- step1:用户提交请求
- step2:后台将请求放入消息队列,等待处理,返回给用户一个临时结果,用户不管这次的结果是什么,直接进行下一步
- step3:用户看到临时的结果,真正的请求在后台等待处理
- ②特点
- 用户看到的结果并不是我们已经处理的结果
- ③场景:
- 用户暂时不需要关心真正处理结果的场景下,只要保证这个最终结果是用户想要的结果即可,实现最终一致性
- ④缺点:可能结果误差
- ⑤优点:性能更高
- ①流程
3.消息队列的一次性语义
- (1)什么是一次性语义?
- 答:消息传递时,每次发送消息只会影响最终结果一次
- (2)消息队列的三种一次性语义
- ① at-most-once:至多一次
- 会出现数据丢失的问题
- ② at-least-once:至少一次
- 会出现数据重复的问题
- ③ exactly-once:有且仅有一次
- 1)只消费处理成功一次
- 2)所有消息队列想要实现的目标
- ① at-most-once:至多一次
- (3)大多数的消息队列一般不能满足Exactly Once就满足at-least-once,Kafka理论上实现了exactly-once
4.消息队列的模式
- (1)点对点模式
- ① 图示
- ② 角色
- 1)生产者:负责往消息队列中写数据的
- 2)消息队列:负责缓存传递的数据
- 3)消费者:负责从消息队列中读取数据的
- ③ 流程
- step1:生产者要往消息队列中写数据
- step2:消费者从消息队列中读数据
- step3:消费者消费成功以后,会返回一个确认ack给消息队列,消息队列会将消费成功的数据删除
- ④ 特点:数据只能被一个消费者使用,消费成功以后数据就会被删除,无法实现消费数据的共享
- ① 图示
- (2)订阅发布模式
- ①图示
- ②角色
- 1)生产者:同上
- 2)消息队列:同上
- 3)消费者:同上
- 4)Topic:主题,用于划分存储不同业务的数据
- ③流程
- 1)生产者往消息队列中生产数据,将数据写入对应的主题Topic中
- 2)消费者可以订阅主题,如果主题中出现新的数据,消费就可以立即消费
- ④特点:(类似微信公众号)
- 1)生产者不断生产数据写入Topic
- 2)消费者订阅了Topic,就可以读取Topic中最新的数据
- 3)允许一个消费者订阅多个Topic,一个Topic也可以被多个消费者订阅
- ①图示
5.Kafka简介
- (1) 定义:
- 分布式的基于订阅发布模式的高吞吐高性能的实时消息队列系统
- (2) 功能
- ①分布式流式数据实时存储:实时消息队列存储,工作中常用
- ②分布式流式计算:KafkaStream,这个功能一般不用
- (3) 应用场景
- 实时场景:只要做实时大数据,都必用Kafka,没有其他替代品
- 离线数仓:Hive
- 实时数仓:Kafka
Kafka生产者:(数据采集的工具)Flume、Logstash
Kafka消费者:(实时计算的程序)SparkStreaming、FLink
- 实时场景:只要做实时大数据,都必用Kafka,没有其他替代品
- (4) 特点:
- ①高性能:实时的对数据进行实时读写(顺序写磁盘,其性能高于内存)
- 1)基于分布式内存 + 分布式磁盘数据存储系统
- 2)数据写入:先写内存,后台自动同步到磁盘中【顺序写磁盘】
- 3)数据读取:先读内存,如果内存没有,再读磁盘【顺序读取机制,索引】
- 4)与Hbase区别:内存和磁盘的机制都不一样
- a. Hbase:内存【RS的JVM堆内存】,磁盘[HDFS]
- b.Kafka:内存【Page Cache:操作系统级别】,磁盘【自己管理:顺序写】
- ②高并发:分布式并行读写
- 分布式
- ③高吞吐:使用分布式磁盘存储,没有使用HDFS
- 自己实现分布式磁盘管理
- ④高可靠:分布式主从架构
- 节点备份机制
- ⑤高安全性:数据安全保障机制
- 1)内存:备份:内存的级别是操作系统级别【只有机器故障才会导致内存数据丢失】
- 2)磁盘:备份
- ⑥高灵活性
- 根据需求,随意添加生产者和消费者
- ①高性能:实时的对数据进行实时读写(顺序写磁盘,其性能高于内存)
6.Kafka相关概念
Producer------>kafka集群[多个broker]<------Consumer group
-
(1) Producer(生产者)
- 功能:负责将数据写入kafka中,工作中一般生成的都是数据采集工具
- 本质:kafka写入数据的客户端,格式一般为KV对
-
(2) Broker(kafka节点):物理存储节点,用于存储Kafka每个分区的数据
- 功能:kafka是一个分布式集群,多台机器构成,每台kafka的节点就是一个broker
- 注:kafka的进程就是kafka
- 功能:kafka是一个分布式集群,多台机器构成,每台kafka的节点就是一个broker
-
(3) Consumer(消费者)
- 功能:负责从kafka中消费数据
- 本质:kafka消费数据的客户端(主要消费的是数据的value值)
- ①消费者如何消费kafka中的Topic的数据?
- 1)、第一次消费:根据属性:
- auto.offset.reset= latest | earliest | none
- latest:从最新的位置消费
- earliest:从最早的位置消费
- none:如果是第一次消费,这个属性为none,Kafka会抛出异常;如果不是第一次消费,上面这个属性不起作用
- 2)、第二次消费:根据上一次消费的Offset位置+1继续进行消费
- ②如果消费者故障,重启,不知道上一次的位置怎么办?
- 1)、Kafka让每个消费者自动定期将自己消费的offset记录在一个Topic中,__consumer_offsets
- 2)、如果消费者没有给定请求位置,Kafka根据记录的offset来返回对应的数据请求
- ★ 自动提交offset存在的问题?
- 答:数据丢失或数据重复
- 自动提交周期为1S,消费是否成功,是根据处理的结果来决定的,自动提交offset是根据时间来决定的,
- 若消费了未处理,记录周期到了offset被记录,重启后会直接消费下一条,造成数据丢失;若消费并处理成功,但是没有提交offset,程序故障,重启再次消费上一条数据,数据会重复
- 解决方案:
- 如果消费并处理成功:手动提交offset
- 如果消费处理失败:不提交offset
- 答:数据丢失或数据重复
-
(4)Consumer group(消费者组)
- 功能:kafka中必须以消费组的形式从kafka中消费数据
- 1)、消费者组到kafka消费数据
- 2)、任何一个消费者必须属于某一个消费者组
- 3)、一个消费者组可以有多个消费者
- a.多个消费者并行消费数据
- b.消费者中多个消费者的数据是不一致的
- c.这个消费者中左右的数据加起来才是一份完整的数据
- 功能:kafka中必须以消费组的形式从kafka中消费数据
-
(5)Topic(数据主题):逻辑存储对象,用于区分不同数据的的存储
- ①定义:Kafka中的对象,类似于Hbase中表的概念,不同的数据写入不同Topic
- ②功能:用于区分不同的数据,对数据进行分类
- Topic就是分布式的概念,一个topic可以划分多个分区partition,每个不同分区存储在不同的kafka节点上
- 1)写入topic的数据实现分布式存储
- 2)问题:生产者写入一条KV结构数据,这条数据写入哪个topic分区由什么分区规则来决定?(Kafka中生产数据的分区规则是什么?)
- 答:有多重分区规则,不同场景对应的分区规则不一样
- 先判断是否指定了分区
- a.如果指定了分区,就写入指定的分区
- b.如果没有指定分区,再判断是否指定了key
- a)、如果指定了Key,根据Key的Hash取余分区个数
- b)、如果没有指定key,使用黏性分区
-
(6)Partition(数据分区):逻辑上分布式划分的概念、物理上存储数据的单元
- 功能:对Topic的数据构建多个分区,实现分布式存储
- ①一个topic可以划分多个分区,类似于HBASE表可以划分多个region
- ②每个分区储存在不同的kafka节点broker上
- ③写入topic,根据一定的规则决定写入哪个具体的分区(参见topic)
- 如何自定义分区器?
- a.自己开发分区器
- a)实现partitioner接口
- b)重写partition
- b.在配置中指定分区器
- a.自己开发分区器
- 功能:对Topic的数据构建多个分区,实现分布式存储
-
(7)Replicas(分区副本机制)
- ①Kafka怎么保证分区数据的安全(节点单点故障)?
- 1)构建副本机制:对每个分区构建多个副本
- 2)相同分区的副本不存在同一个节点上(一个分区的副本个数最多等于机器的个数)
- ②Kafka如何决定分区副本的读写?
- 答:Kafka对一个分区的多个副本划分了角色
- Leader:负责对外提供读写
- Follower:负责与leader同步数据,如果leader故障,参与选举成为新的leader
- 答:Kafka对一个分区的多个副本划分了角色
- ③Kafka分区副本概念:AR、ISR、OSR
- 1)、AR :All - Replicas
- 所有副本:指的是一个分区在所有节点上的副本
- 2)、ISR :In - Sync - Replicas
- a. 可用副本:所有正在与Leader同步的Follower副本
- b. 如果leader故障,是从ISR列表中选择新的leader
- 3)、OSR :Out - Sync - Replicas
- a. 不可用副本:与Leader副本的同步差距很大,成为一个OSR列表的不可用副本
- b. 原因:网路故障等外部环境因素,某个副本与Leader副本的数据差异性很大
- 4)、AR = ISR + OSR
- 1)、AR :All - Replicas
- ①Kafka怎么保证分区数据的安全(节点单点故障)?
-
(8)Offset
- ①定义:kafka中所有消费者数据的读取都是按照offset来读取数据的,offset是每条数据在自己分区中的偏移量
- 1)、写入分区的顺序就是offset偏移量,offset是分区级别的,每个分区的offset独立管理,都从0开始
- 2)、消息队列:先进先出
- ②功能:基于offset来制定数据的顺序,消费时按照offset进行读取
- 1)如果没有offset会怎么样?
- a.从头读一遍,会造成数据重复
- b.只读最新的数据,中间数据丢失
- 2)怎么保证消费数据不丢失也不重复?(靠自己写代码实现)
- 答:只要保证消费者每次都是按照offset的顺序消费即可,将处理成功的分区的Offset进行额外的存储,默认存储在kafka上的__consumer_offsets文件,外部可存在mysql,Redis,zookeeper上
- 1)如果没有offset会怎么样?
- ①定义:kafka中所有消费者数据的读取都是按照offset来读取数据的,offset是每条数据在自己分区中的偏移量
-
(9)Segment
- ①定义:对每个分区的数据进行了更细的划分,先写入的数据会先生成一对Segment文件,存储到一定条件以后,后面数据写入另外一对Segment文件,每个文件就叫Segment文件对
- ②内容:每个Segment对应一对【两个】文件
- 1)xxxxxxxxx.log:数据文件,存储数据
- 2)xxxxxxxxx.index:对应.log的文件的数据索引
- 3)0.11(0.10.0.1)版本后,新增时间戳记录文件xxxxx.timeindex
- ③设计思路:为了加快数据检索的效率,将数据按照规则写入不同的文件,以后可以根据规则快速定位到数据所在的文件,读取对应的segment文件,避免读取所有数据文件
- ④命名:数据在这个分区中的offset在文件中最小offset来命名的
- ⑤为什么要设计Segment?
- 1)提高查询效率:每个Segment以最小offset来命名文件
- 2)避免按条删除,影响性能,以Segment为单位进行数据过期删除
7.概念对比
- HDFS:分布式文件离线存储系统
- Hbase:分布式NOSQL实时列储存数据库
- Kafka:分布式实时消息队列
- Redis:基于内存的分布式的NoSQL数据库
8.Kafka集群架构和角色功能
- (1)架构组成
- ①Kafka
- 分布式主从架构,实现消息队列的构建
- ②Zookeeper
- 辅助选举controller(active的主节点),元数据存储
- ①Kafka
- (2)Kafka中的角色及其功能
- ①分布式主从架构
- ②主节点:Kafka Controller
- 1)是一种特殊的broker,从所有的broker中选举出来的,负责普通broker的工作
- 2)负责管理所有从节点:topic,分区和副本
- 3)每次启动集群,会从所有broker中选举一个controller,由ZK实现
- ③从节点:kafka Broker
- 1)对外提供读写请求
- 2)其他的broker监听controller,如果controller故障,会重新从broker中选出一个新的controller
9.简述kafka中topic管理的脚本和常用选项参数
- (1)脚本:kafka-topics.sh
- (2)参数
- ①–create/–delete/–list/–describe
- ②–partitions
- ③–replication-factor
- ④–topic
- ⑤–bootstrap-server
- ⑥–broker-list
10.简述如何使用kafka simple java API实现消费数据?描述具体的类和方法
- ①消费者:实时数据处理程序
- ②KafkaConsumer
- 1)、subscribe
- 2)、poll
- ③Properties
- ④ConsumerRecords
- ⑤ConsumerRecord
- Topic/Partition/Offset/K/V
11.简述kafka生产数据时如何保证数据不丢失
- 答:属性acks机制+重试机制
- (1) 属性acks机制
- ①0:生产者生产数据到Kafka的分区中,写入leader副本后,直接返回ack,生产者收到ack发送下一条
- ②1:生产者生产数据到Kafka的分区中,写入leader副本后,直接返回ack,生产者收到ack发送下一条
- ③All/-1:生产者生产数据到Kafka的分区中,等待leader和所有follower都写入成功,返回ack,生产者收到ack发送下一条
- (2) 重试机制:如果生产者没有收到ack,就认为数据丢失,重新发送这条数据
- (1) 属性acks机制
12.简述kafka生产数据时如何保证数据不重复
(为什么数据会重复?答:ack会丢失,生产者会再次发生数据造成重复)
- 答:幂等性机制
- ①Kafka通过幂等性机制在数据中增加数据id,每条数据的数据id都不一致
- ②Kafka会判断每次要写入的id是否比上一次的id多1,如果多1,就写入,不多1,就直接返回ack
13.Kafka消费分配基本规则和常用的分配策略
- (1)基本规则:
- ①一个分区的数据只能由一个消费者消费
- ②一个消费者可以消费多个分区的数据
- (2)分配策略:
-
①范围分配(RangeAssignor),kafka默认的分配策略
- 1)规则:每个消费者消费一定范围的分区,尽量做均分,如果不能均分,优先将分区分配给编号小的消费者
- 2)应用:适合于Topic个数少或者每个Topic都能均分场景
- 3)优点:如果topic个数少,分配相对比较均衡
- 4)缺点:如果topic个数比较多,而且不能均分,易导致负载不均衡
-
②轮询分配(RoundRobinAssignor),常见于Kafka2.0之前的版本
- 1)规则:根据订阅关系,将订阅的Topic的分区排序轮询分配给订阅的消费者
- 2)应用:所有消费者都订阅共同的Topic,能实现让所有Topic的分区轮询分配所有的消费者
- 3)优点:如果有多个消费者,消费的Topic都是一样的,实现将所有Topic的所有分区轮询分配给所有消费者,尽量的实现负载的均衡(大多数场景都是这样)
- 4)缺点:遇到消费者订阅的Topic是不一致的,不同的消费者订阅了不同Topic,只能基于订阅的消费者进行轮询分配,导致整体消费者负载不均衡的(如下图)
-
③黏性分配(StickyAssignor),Kafka2.0之后建议使用
- 1)规则:尽量保证所有分配均衡(类似轮询分配),尽量保证每个消费者如果出现故障,剩余消费者依旧保留自己原来消费的分区(相比轮询的优化),故障分区均分给其余消费者,相比于轮询的故障后重新分配所有分区,降低了网络IO消耗
- 2)特点:
- a.相对的保证的分配的均衡
- b.如果某个消费者故障,尽量的避免网络传输
- c.尽量保证原来的消费的分区不变,将多出来分区均衡给剩余的消费者
-
14.Kafka中是怎么体现消息顺序性的?
- kafka每个partition中的消息在写入时都是有序的,消费时每个partition只能被每一个consumer group中的一个消费者消费,保证了消费时也是有序的,但整个topic不保证有序。
- 如果为了保证topic整个有序,那么只能
- ①将partition调整为1
- ②写入指定的某一个分区
15.Kafka的数据是如何写入的?
- (1)先放入批次,当Batch满了或者达到一定时间,提交整个batch
- (2)根据分区规则计算数据的分区,获取元数据,得到这个分区所在的leader副本的broker的id
- (3)请求对应Broker,将数据写入PageCache中
- (4)将PageCache中的数据同步到磁盘文件中:最新的Segment的.log文件中
- (5)follower与leader同步数据
16.Kafka的数据是如何读取的?
- (1)提交Topic、Partition、Offset给Kafka
- (2)Kafka根据分区以及元数据,找到leader副本所在的节点
- (3)先读PageCache,如果数据在pageCache,通过Zero Copy(零拷贝)机制实现从内存读取
- (4)如果不在内存,根据offset来读取对应segment
- (5)先读取.index文件找到这个offset在.log文件中最近位置
- (6)再读取.log文件,从最近位置读取
17.Kafka为什么那么快?
- (1)Kafka为什么写入很快?
- ①先写入内存:PageCache
- ②写入磁盘:顺序写磁盘
- (2)Kafka为什么读取和快?
- ①先读PageCache + ZeroCopy
- ②Segment + index索引
- (3)总结:
此处参考自:https://zhuanlan.zhihu.com/p/183808742?utm_source=wechat_timeline- ①读写都是分布式分区并行处理
- ②顺序写磁盘,充分利用磁盘特性
- ③利用现代操作系统分页存储 Page Cache来利用内存提高 I/O 效率
- ④采用了零拷贝技术
- ⑤Producer 生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入
- ⑥Customer从broker读取数据,采用 sendfile,将磁盘文件读到 OS 内核缓冲区后,转到 NIO buffer进行网络发送,减少CPU消耗
18.Kafka存储机制:index索引设计
- (1).index文件中的索引的内容是什么?
- ①索引类型:稀疏索引
- ②两列
- 第一列:每个offset是这个文件的第几条
- 第二列:这个offset在.log文件中的物理字节偏移量
- (2)查询数据时如何根据索引找到对应offset的数据?
- ①先计算要找的offset是这个文件的第几条:要找的offset文件最小offset + 1
- ②读取.index文件获取离这个offset最近最小的位置
- ③根据最新位置的物理偏移量读取.log文件
- (3)问题:为什么不直接将offest作为索引的第一列?
- 答:因为offset会很长,索引时比较会比较耗时
19.Kafka数据清理
- (1)Kafka用于实现实时消息队列的数据缓存,不需要永久性的存储数据,如何将过期数据进行清理?
- 答:delete方案:根据时间定期的清理过期的Segment文件
- ①、基于时间清理:168H/7天清理一次(最常用)
- ②、基于文件大小清理:当文件大小达到某个阈值时清理最老版本Segment
- 答:delete方案:根据时间定期的清理过期的Segment文件
20.Kafka数据同步概念
-
(1)什么是HW、LEO?
- ①HW:高水位线,消费者能消费到的最大位置,当前这个分区所有副本都同步的位置+1
- ②LEO:当前即将写入的offset的位置,leader当前最新的位置offset+1
- ③副本最小的LEO = HW
-
(2)数据写入leader及同步过程
- Step1::数据写入分区的Leader副本
- Step2:Follower到Leader副本中同步数据