阅读kafka文档
This commit is contained in:
58
mq/kafka/kafka-尚硅谷.md
Normal file
58
mq/kafka/kafka-尚硅谷.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Kafka
|
||||||
|
## 简介
|
||||||
|
### 消息队列应用场景
|
||||||
|
缓存/削峰、解耦、异步通信
|
||||||
|
### 缓存/削峰
|
||||||
|
当生产端生产数据的速率大于消费端消费数据的速率时,消息队列可用于对消费不完的数据进行缓存
|
||||||
|
### 解耦
|
||||||
|
当数据生产方来源存在多个(例如数据库、网络接口等),且消费方也存在多种(Hadoop大数据平台、spring boot服务实例等)时,可以将消息队列中存储的消息作为数据从生产端到消费端的中间格式。
|
||||||
|
|
||||||
|
生产端负责将产生的数据转化成特定格式的消息发送到消息队列,而消费端负责消费消息队列中的消息。不同种类的生产端和消费端只用针对消息的队列中的消息各自进行适配即可。
|
||||||
|
|
||||||
|
### 异步通信
|
||||||
|
通过消息队列,可以实现多个服务实例之间的异步调用,服务调用方在将调用信息封装到消息并发送消息到mq后,即可返回,并不需要同步等待。被调用方可以异步的从mq中获取消息并进行消费。
|
||||||
|
|
||||||
|
### 消息队列模式
|
||||||
|
#### 点对点
|
||||||
|
一个消息队列可以对应多个生产者和多个消费者,**但消息只能被一个消费者进行消费**,消费者将数据拉取并消费后,向mq发送确认,mq中将被消费的消息删除
|
||||||
|
#### 发布订阅模式
|
||||||
|
**生产者产生的数据可以被多个消费者消费**,生产者将消息发送到topic,订阅该topic的消费者会拉取消息进行消费,消费完成后并不会删除该消息,该消息仍可被其他订阅该topic的消费者进行消费。(消息并不会永久保存在消息队列中,通常会设置超期时间,消息保存超过该时间后自动删除)
|
||||||
|
|
||||||
|
### kafka架构
|
||||||
|
#### 分区存储
|
||||||
|
kafka将一个topic分为了多个分区,用于分布式存储数据。而每个分区都跨多台服务器实例进行存储,从而增加容错性。对特定分区来说,其存在于多台服务器实例,其中一台为主机,其他服务器为从机,**主机会处理对该分区数据所有的读写请求**(由于读写操作全都在主机上发生,而每台服务器都担当了某些分区的主机和其他分区的从机,故而读写请求在不同的服务器之间进行了负载均衡),而从机只会被动的复制主机修改。
|
||||||
|
#### group消费
|
||||||
|
每个消费者实例都属于一个consume group,一个consume group则是可以保存多个消费者实例。对于发送到kafka mq topic的每一条消息,都会被广播给订阅了该topic的每个consume group。而consume group接收到消息后,只会将消息发送给group中的一个消费者实例来进行处理,故而在consume group中,实现了消息在不同消费实例之间的负载均衡。
|
||||||
|
> 在kafka mq中,topic的实际订阅者是consume group,kafka mq会将topic中的消息广播给所有订阅了该topic的consume group,而每条消息都只会被consume group中的一个消费者实例进行消费
|
||||||
|
>
|
||||||
|
> 在一个consume group中,每个消费者实例都负责某一topic中相应的分区,每个特定分区只有一个消费者实例负责。
|
||||||
|
|
||||||
|
#### zookeeper
|
||||||
|
zookeeper作为注册中心,用于记录存在多个kafka实例时,当前已上线且状态正常的kafka实例,以及各个分区leader实例的信息
|
||||||
|
|
||||||
|
#### 生产者
|
||||||
|
##### 分区
|
||||||
|
生产者客户端将会决定将消息发送到某个分区,可以通过负载均衡随机决定将消息发送到哪个分区,也可以提供一个key并通过算法决定将消息发送到哪个分区。
|
||||||
|
|
||||||
|
决定将消息发送到哪个分区后,生产者会直接将消息发送到该分区对应的leader broker中。
|
||||||
|
|
||||||
|
##### 批量发送
|
||||||
|
生产者并不会每次产生消息后都立即将消息发送到broker,而是会累积消息,**直到消息数据积累到特定大小(默认为16K)后**,才会将消息发送给broker。
|
||||||
|
> **消息发送条件**
|
||||||
|
>
|
||||||
|
> - batch.size: 当消息累计到特定大小(默认为16K)后,发送给broker。如果消息的大小大于`batch.size`,那么并不会对消息做累积操作。**发送到broker的请求将会包含多个batch,每个batch对应一个分区,不同分区的消息通过不同的batch进行发送**
|
||||||
|
> - linger.ms: 生产者将会把发送给broker的两个请求之间的消息都累积到一个batch里,该batch将会在下次发送请求给broker时发送。但是,对特定分区累积大小如果没有达到`batch.size`的限制,哪个通过linger.ms来控制该消息延迟发送的最长时间。`linger.ms`单位为ms,**其默认值为0,代表即使消息累积没有达到`batch.size`,也会立马发送给broker**。若`linger.ms`设置为1000,则代表没有累积到`batch.size`大小的消息也会在延迟1s后发送给broker
|
||||||
|
|
||||||
|
##### ack级别
|
||||||
|
生产者将消息发送到broker后,broker对生产者有三种应答级别:
|
||||||
|
- 0:生产者发送数据后无需等待broker返回ack应答
|
||||||
|
- 1:生产者发送消息到broker后,leader broker将消息持久化后向生产者返回ack
|
||||||
|
- -1:生产者发送过来的数据,leader broker和isr队列中所有的broker都持久化完数据后,返回ack
|
||||||
|
|
||||||
|
##### 异步发送
|
||||||
|
kafka生产者异步发送是指生产者调用kafka客户端接口将发送的消息传递给kafka的客户端,此时消息并未发送到broker,而异步调用接口即返回。调用异步接口可以通过指定回调来获取消息传递到的topic、分区等信息。
|
||||||
|
|
||||||
|
##### 同步发送
|
||||||
|
除了异步调用接口外,还可以调用同步调用的接口来发送消息。在调用异步接口发送消息时,仅仅将消息放到缓冲区后调用就返回,可能放到缓冲区的消息并没有发送到broker。可以通过调用同步发送消息的接口来发送消息,其会阻塞并等待broker将消息持久化后返回的异常或者ack应答。
|
||||||
|
|
||||||
|
想要同步发送消息,只需要对异步接口返回的future对象调用`.get`即可,其会等待future对象完成。
|
||||||
@@ -323,3 +323,36 @@ Kafka的语义是直截了当的,当消息被发布时,有一个消息被提
|
|||||||
- `exactly-once`:当写入到外部系统时,限制是需要协调消费者位置和实际存储内容。通常情况下,实现该功能需要在消费者position的存储系统和消费者输出的存储系统之间引入两阶段提交。但是,可以通过将position和consumer output存储在一个位置来简化该过程。因为任何想要写入的系统可能并不支持两阶段提交。
|
- `exactly-once`:当写入到外部系统时,限制是需要协调消费者位置和实际存储内容。通常情况下,实现该功能需要在消费者position的存储系统和消费者输出的存储系统之间引入两阶段提交。但是,可以通过将position和consumer output存储在一个位置来简化该过程。因为任何想要写入的系统可能并不支持两阶段提交。
|
||||||
> Kafka在Kafka Streams中支持`exactly-once`传输,并且在处理topics之间数据时通过使用transactional producer/consumer来提供`exactly-once`功能。
|
> Kafka在Kafka Streams中支持`exactly-once`传输,并且在处理topics之间数据时通过使用transactional producer/consumer来提供`exactly-once`功能。
|
||||||
> 其他情况下,kafka默认保证at-least-once传输,但是也允许用户实现at-most-once传输,通过关闭生产者的重试功能并且在处理数据之前提交position变动。
|
> 其他情况下,kafka默认保证at-least-once传输,但是也允许用户实现at-most-once传输,通过关闭生产者的重试功能并且在处理数据之前提交position变动。
|
||||||
|
|
||||||
|
### 复制
|
||||||
|
#### 分区备份
|
||||||
|
kafka会将topic分区复制到多台mq server上,mq server的数量可配置。(可以针对单个topic来设置replication factor的数量)。在其他server上保存副本允许当某台server发生故障宕机后,仍然可以从其他server上存储的副本中获取信息。
|
||||||
|
|
||||||
|
复制针对的是topic分区。在kafka中,每个分区都有一个leader和零或多个follower。leader加上follower的数量构成了replication factor。所有的写操作都会针对leader分区,而读操作则是可以针对leader或follower分区。通常情况下,分区比broker要多,leader分区分布在broker中。follower分区上的日志和leader分区上的日志都相同,offset和日志内容都相同(在特定时间点,leader尾部可能有一些尚未被复制到follower的消息)。
|
||||||
|
|
||||||
|
follower从leader分区消息消息,就像一个普通的消费者一样,并且将从leader处消费的消息追加到自己分区的尾部。
|
||||||
|
|
||||||
|
#### broker节点的活跃状态定义
|
||||||
|
就像大多数的分布式系统一样,自动的故障容灾需要精确定义一个节点的“活跃”状态。在kafka中,存在一个节点单独来负责管理集群中broker的注册,该节点被称之为controller。broker的活跃状态需要满足如下要求:
|
||||||
|
- broker需要和controller维持一个active session来接收常规的元数据更新
|
||||||
|
- 作为follower的broker需要从leader处同步leader的写操作变动,从而保持分区数据和leader处相同
|
||||||
|
|
||||||
|
对于使用zookeeper的集群,在broker节点初始化与zookeeper的连接会话时,会在zookeeper中创建一个节点,如果broker没能在`zookeeper.session.timeout.ms`时间内向zookeeper发送心跳包,那么broker就会丢失和zookeeper的会话,zookeeper中对应的节点也会被删除。controller会根据zookeeper watch注意到节点的删除,并且将该节点对应的broker标记为离线。
|
||||||
|
|
||||||
|
#### ISR
|
||||||
|
满足上述“活跃”要求的节点会被成为"in sync"状态。而leader会跟踪那些处于“in sync”状态的副本,处于“in sync”状态的副本集合被称之为ISR(in sync replias,ISR中包含leader和follower).
|
||||||
|
|
||||||
|
如果ISR中的节点不再满足”活跃“对应的两条要求,那么该节点将会从ISR中被移除。例如,如果一个follower宕机,那么controller将会注意到zookeeper中节点的删除,并且将该broker中ISR中移除。
|
||||||
|
|
||||||
|
另外,**如果一个节点仍然处于活跃状态,但是离同步leader的数据有很长的延迟,那么leader将会将该节点从ISR中移除**。延迟的最长时间通过`replica.lag.time.max.ms`来配置。如果在`replica.lag.time.max.ms`时间内副本没能通过leader到日志结尾的数据,那么副本节点将会从ISR中被移除。
|
||||||
|
|
||||||
|
#### 消息提交的定义
|
||||||
|
在某分区对应ISR中所有的副本都将消息追加到它们的log后,则可以认为该消息被提交。故而,消费者并无需担心分区的leader宕机后消息会丢失的问题,因为消息在提交前已经持久化到其分区副本中。
|
||||||
|
|
||||||
|
作为生产者,可以在发送消息时决定是否等待消息被提交,这需要在等待提交所带来的延迟和不等待提交所带来的消息丢失风险中进行权衡。是否等待提交取决于生产者的ack设置。
|
||||||
|
#### 最小写入副本数
|
||||||
|
topic可以设置一个最小写入的副本数,通过配置`min.insync.replicas`,可以对最小写入副本数进行配置。即使消息已经同步到所有ISR副本后,如果同步数目小于该值(同步数目包含leader),消息也无法被视为提交
|
||||||
|
|
||||||
|
> kafka保证一条消息只要被提交,只要有一个in-sync-replica处于活跃状态,那么消息就不会被丢失
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user