消息中间件KAFKA

1.使用场景

① 大数据领域
网站行为分析、日志聚合、应用监控、流式数据处理、在线和离线数据分析等领域。
② 数据集成
将消息导入MaxCompute、OSS、RDS 、Hadoop、 HBase等离线数据仓库。
③ 流计算集成
与StreamCompute、 E-MapReduce、 Spark、Storm等 流计算引擎集成。

在这里插入图片描述

2. 架构原理

在这里插入图片描述
① Broker
Kafka 的服务也叫做 Broker,默认是 9092 的端口。生产者和消费者都需要跟这个 Broker 建立一个连接,才可以实现消息的收发。

② 消息
客户端之间传输的数据叫做消息,或者叫做记录。消息在传输的过程中需要序列化

③ 生产者
为了提升消息发送速率,生产者不是逐条发送消息给 Broker,而是批量发送。多少条发送一次由一个参数决定。默认16K,默认发送等待时间5毫秒
pros.put(“batch.size”,16384);
pros.put(“linger.ms”, 5);

④ 消费者
消费者获取消息有两种模式,Pull 模式 和 Push 模式

Pull 模式就是消费放在 Broker,消费者自己决定什么时候去获取。Push 模式是消息放在 Consumer,只要有消息到达 Broker,都直接推给消费者。

KAFKA默认Pull 模式,max.poll.size=500 默认拉取500个消息

④ Topic
Topic,是一个逻辑概念,可以理解为一组消息的集合

生产者跟消费者通过TOPIC关联,生产者和 Topic 以及 Topic 和消费者的关系都是多对多。一个生产者可以发送消息到多个 Topic,一个消费者也可以从多个 Topic 获取消息(但是不建议这么做)。

生产者发送消息时,如果 Topic 不存在,会自动创建。由一个参数控制:auto.create.topics.enable,默认为 true。

⑤分区(Partition)
一个 Topic 中的消息太多,一是,不方便把数据分布在不同的机器上实现扩展,二是,所有的客户端操作的都是同一个 Topic,在高并发的场景下性能会大大下降

Kafka 引入了一个分区(Partition)的概念。一个 Topic 可以划分成多个分区。分区在创建 Topic 的时候指定,每个 Topic 至少有一个分区 。如果没有指定分区数,默认的分区数是一个:服务端由一个参数控制分区数:num.partitions=1

Partition 思想上有点类似于分库分表,实现的也是横向扩展负载 的目的。

⑥ Partition 副本 Replica 机制
如果 Partition 的数据只存储一份,在发生网络或者硬件故障的时候,该分区的数据就无法访问或者无法恢复了。

每个 Partition 可以有若干个副本(Replica),副本必须在不同的 Broker 上面,一般我们说的副本包括其中的主节点,服务端有一个参数控制默认的副本数:offsets.topic.replication.factor。副本的个数不大于节点数

Partition 副本有 Leader和 Follower 的概念,Leader通过zookeeper 选举产生。生产者发消息、消费者读消息都是针对Leader

⑦ Segment
如果一个 Partition 只有一个 log 文件,消息不断地追加,这个 log 文件也会变得越来越大,这个时候要检索数据效率就变低了

Partition 再进一步切分,切分出来的单位就叫做段(Segment)。实际上 Kafka 的存储文件是划分成段来存储

每个 Segment 都有至少有 1 个数据文件和 2 个索引文件,这 3 个文件成套出现

一个Segment默认1073741824 bytes(1G),由参数控制:log.segment.bytes

⑧ Consumer Group消费者组
生产者生产消息的速率过快,会造成消息在 Broker堆积,通过增加消费者的数量,可以提升消费者的消费速度

消费同一个TOPIC的消费者划分到同一个消费者组,每一个消费者组通过groupid来标识。
消费同一个 Topic 的消费者不一定是同一个组,只有 group id 相同的消费者才是同一个消费者组。

同一个 Group 中的消费者,不能消费相同的 Partition,Partition 要在消费者之间分配。
在这里插入图片描述
⑨ Consumer Offset
Partition 里面的消息顺序写入,被读取之后不会被删除。

通过对消息进行编号,用来标识一条唯一的消息,可以保证消费者接着上次的位置读取消息,或者从某个特定的位置读取消息,进而不会出现重复消费的情况

offset之前保存在zookeeper,现在在KAFKA内部保存
在这里插入图片描述

2. 生产者原理

2.1 消息幂等性

消息幂等性用于KAFKA消费端,解决消息重复消费的情况。

Kafka 在 Broker 实现了消息的重复性判断,首先依赖于 “生产者的消息的唯一的标识”, 由参数控制:
props.put(“enable.idempotence”, true);
设置成 true 后,Producer 自动升级成幂等性 Producer。

幂等性的生产者每个客户端都有一个唯一的编号 PID(Producer ID,且发送的每条消息都会带相应的 sequence number,
KAFKA Server 端就是根据这个值来判断数据是否重复。如果说发现 sequence number 比服务端已经记录的值要小,就是出现消息重复了

sequence number 并不全局有序,不能保证所有时间上的幂等。只能保证某个主题的一个分区上不出现重复消息;
Producer 进程一次运行,当重启了之后,幂等性不保证。

如果要实现多个分区的消息原子性,需要用到 Kafka 的事务机制

2.2 生产者事务

两阶段提交(2PC)
在这里插入图片描述
有一个协调者的角色,叫做 Transaction Coordinator。

事务管理必须要有事务日志,来记录事务的状态,以便 Coordinator 在意外挂掉之后继续处理原来的事务。跟消费者 Offset 的存储一样,Kafka 使用 topic_transaction_state 来记录事务状态。

要有事务Id,transaction.id,配置了 transaction.id,则此时 enable.idempotence 会被设置为 true(事务实现的前提是幂等性)。事务 ID 相同的生产者,可以接着处理原来的事务。

2.3 生产者消费发送流程

在这里插入图片描述
① main线程启动,初始化KafkaProducer的时候,创建Sender线程,Sender线程负责与Broker通信

② 拦截器的作用是实现消息的定制化

③ 利用指定的工具对 key 和 value 进行序列化,除了自带的序列化工具之外,可以使用如 Avro、JSON、Thrift、Protobuf 等,
或者使用自定义类型的序列化器来实现,实现 Serializer 接口即可

④ 分区器为一条消息指定路由到的分区

⑤ 选择分区以后并没有直接发送消息,而是把消息放入了消息累加器

2.4. 数据可靠性保证

2.4.1 服务端响应策略

在KAFKA中,单个 Partition(Leader)写入成功,如果有多个副本,所有的 Follower 全部完成同步之后,服务端再发送 ACK 给客户端

服务端确认以后,生产者才发送下一轮的消息,否则重新发送数据。

这种响应策略延迟相对来说高一些,但是节点挂掉的影响相对来说小一些,因为所有的节点数据都是完整的。
在这里插入图片描述
假设有一个 Follower出了问题,没有办法从 Leader 同步数据。按照这个规则,Leader 就要一致等待,无法发送 ACK

2.4.2 ISR

我们可以把那些 正常和 leader 保持同步的 replica 维护起来,放到一个动态 set 里面,这个就叫做 in-sync replica set(ISR),只要 ISR 里面的 follower 同步完数据之后,KAFKA服务端就给客户端发送 ACK。

多久没有向 Leader 同步数据,被踢出 ISR,由参数:replica.lag.time.max.ms 决定(默认值 30 秒)

如果 leader 挂了,就会从 ISR 重新选举 leader。

2.4.3 ACK应答机制

适合不是同步全部数据,允许有些数据丢失,不管数据落盘没落盘的情况

三种可靠性级别:
① pros.put(“acks”,“0”);
producer 不等待 broker 的 ack,这一操作提供了一个最低的延迟,broker 一接收到还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据;

② pros.put(“acks”,“1”);
producer 等待 broker 的 ack,partition 的 leader 落盘成功,后返回 ack,如果在 follower 同步成功之前 leader 故障,那么将会丢失数据;

③ pros.put(“acks”," -1");
producer 等待 broker 的 ack,partition 的 leader 和 follower
全部落盘成功后才返回 ack

如果在 follower 同步完成后,broker 发送 ack 之前,leader 发生故障,没有给生产者发送 ACK,那么会造成数据重复。在这种情况下, 把 reties 设置成 0(不重发),才不会重复。
由服务端参数控制: 异常日动重试次数:pros. put(“retries”,0);

三种机制,性能依次递减 (producer 吞吐量降低),数据健壮性则依次递增

3. 消息保留机制

Kafka 的日志(数据)在消费以后不删除,所以可以顺序追
加写入,但总会有磁盘撑爆的情况,所以对于比较老旧的日志,需要有一定清理策略。

日志的清理开关默认是开启的:
log.cleaner.enable=true
但有两种清理方式:log.cleanup.policy=delete | Compact

3.1 直接删除(delete)

直接删除delete 方式:
log.retention.check.interval.ms=300000默认每5分钟,由定时任务清理一次

3.1.1 时间粒度删除

默认删除超过168个小时的数据,也即一周的数据
log.retention.hours

也有更细粒度的配置:分钟和毫秒,默认值为空
log.retention.minutes
log.retention.ms
选用的时间单位越小,优先级越高

3.1.2 日志大小粒度删除

假设 Kafka 产生消息的速度是不均匀的,有的时候一周几百万条,有的时候一周几千条,那这个时候按照时间删除就不合理,所以KAFKA提供了第二种删除策略就是根据日志文件总大小删除,先删旧的消息,删到不超过这个大小为止
log.retention.bytes
默认值是-1,代表不限制大小,想写多少就写多少。

也可以对单个 Segment 文件大小进行限制
log.segment.bytes
默认值 1073741824 字节(1G)

3.2 日志压缩(Compact)

压缩就是把相同的 Key 合并为最后一个 Value。

topic:_consumer_offsets,存储的是消费者id 和 Partition 的 Offset 关系,消费者不断地消费消息 commit 的时候,不断顺序写入新的 Offset
在这里插入图片描述

4.高可用架构

4.1 Controller控制器

Kafka 先从所有 Broker 中选出唯一的一个Broker,用于控制Leader选举,这个Broker叫做控制器

其选举办法是,Broker在 ZK 里,竞争写入一个/controller 临时节点,哪个写入成功,哪个成为Controller

Controller的职责:
① 监听 Broker 变化。
② 监听 Topic 变化。
③ 监听 Partition 变化。
④ 获取和管理 Broker、Topic、Partition 的信息。
⑤ 管理 Partiontion 的主从信息

4.2 分区副本 Leader 选举

① AR
Assigned-Replicas
一个分区所有的副本

② In-Sync Replicas(ISR)
AR 中 跟 Leader 数据保持一定程度同步的副本

③ OSR
Out-Sync-Replicas
AR中跟 Leader 同步滞后过多的副本

AR=ISR+OSR。正常情况下 OSR 是空的,副本都正常同步,AR=ISR。

ISR是一个动态列表,副本同步延迟超过 30 秒,就踢出 ISR,进入 OSR,如果赶上来了,就加入 ISR

默认情况下,当 Leader 副本发生故障时,只有在 ISR 集合中的副本才有资格被选举为新的 Leader。

ISR 为空的情况下,也可以允许ISR之外的副本参与选举,由参数:unclean.leader.election.enable=false 控制,但不建议开启

Kafka 的选举实现,采用的类似于微软的 PacificA 算法。在这种算法中,默认是让 ISR 中第一个 Replica 变成 Leader。比如 ISR 是 1、5、9,优先让 1 成为 Leader。

4.3 主从副本同步

Leader 确定之后,客户端的读写只能操作 Leader 节点。Follower 需要向 Leader同步数据。

4.3.1 LEO & HW

不同副本同步时的OFFSET不一样,为此提出了两个概念:
① LEO
Log End Offset
下一条等待写入的消息的 Offset(最新的 Offset + 1),

② HW
Hign Watermark,ISR 中最小的 LEO。Leader 会管理所有 ISR 中最小的 LEO 作为 HW
在这里插入图片描述

Consumer 最多只能消费到 HW 之前的位置,也就是说:其他的副本没有同步过去的消息,是不能被消费的。这是因为如果在同步成功之前就被消费了,Consumer Group 的Offset 会偏大。如果 Leader 崩溃,中间会缺失消息。

4.3.2 同步过程

① Follower 节点向 Leader 发送一个 fetch 请求,Leader 向 Follower 发送数据后,也需要更新 Follower 的 LEO

② Follower 接收到数据响应后,依次写入消息并且更新 LEO

③ Leader 更新 HW(ISR 最小的 LEO)

4.3.3 Replica 故障处理

① Follower 故障
首先会被踢出 ISR,故障排除副本恢复以后,把高于 HW 的消息截掉。然后向 Leader 同步消息。追上 leader 之后(30 秒),重新加入ISR。

② Leader 故障
首先从ISR中选举出Leader,然后其它Leader把高于 HW 的消息截取掉,然后从Leader同步数据。这种机制只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复(即不能保证可靠性)。

5. 消费者原理

5.1 消费者组和OFFSET关系

ex:消费者组gp-assign-group-1
一个TOPIC (assign) 的
五个PARTITION的偏移量关系,查看命令:

./kafka-consumer-groups.sh --bootstrap-server IP1:9092,IP2:9092,IP3:9092
–describe --group gp-assign-group-1
在这里插入图片描述
主要描述了消费者组中的一个consumer 和 Topic中的一个 Partition 的消费位置,即OFFSET(Offset 在 Partition 中连续编号而不是全局连续编号)。

5.2 OFFSET存储位置

消费者组和OFFSET对应关系,保存在一个特殊的TOPIC中:__consumer_offsets,默认有 50 个分区(offsets.topic.num.partitions 默认是 50)

① 查看主题__consumer_offsets的数据分布情况
./kafka-topics.sh
–topic __consumer_offsets
–describe
–bootstrap-server IP1:9092
在这里插入图片描述
② 一个 consumer group 的 Offset 放在Topic 的哪个分区
Math.abs(“消费者组名”.hashCode()) % 50)

③ 查看 __consumer_offsets的内部结构
./kafka-console-consumer.sh
–topic __consumer_offsets
–bootstrap-server IP1:9092,IP2:9092,IP3:9092
–formatter
“kafka.coordinator.group.GroupMetadataManager$OffsetsMessageFormatter”
–from-beginning
在这里插入图片描述

这个 Topic里面主要存储两种对象:
GroupMetadata:保存了消费者组中各个消费者的信息(每个消费者有编号。[消费者组,主题,分区]

OffsetAndMetadata:保存了消费者组和各个 partition 的 offset 位移信息元数据

④ 消费者找不到OFFSET
增加了一个新的消费者组去消费一个 Topic 的某个 Partion,这种情况会出现消费者找不到OFFSET

可以控制消费者的消费位置,由参数控制:auto.offset.reset
默认值是 latest,也就是从最新的消息(最后发送的)开始消费的。历史消费是不能消费的。
earliest 代表从最早的(最先发送的)消息开始消费。可以消费到历史消息。

5.3 OFFSET的更新

消费者组的 Offset 保存在 Broker,但是由消费者上报给Broker。消费者消费了消息要有一个COMMIT的操作,便于Broker更新OFFSET

消费者可以自动提交,或手工提交,
由参数:enable.auto.commit 控制
默认是 true。代表消费者消费消息以后自动提交此时 Broker 会更新消费者组的 Offset。auto.commit.interval.ms 可以控制提交频率,默认是5秒钟

enable.auto.commit=false,代表手工提交,也分两种方式:
consumer.commitSync() 手动同步提交
consumer.commitAsync() 手动异步提交

如果不提交或者提交失败,Broker 的 Offset 不会更新,消费者组下次消费的时候会消费到重复的消息。

5.4 消费者消费策略

① RangeAssignor
根据分区编号,按照范围将分区中的日志分配给消费者,这也是默认消费策略
在这里插入图片描述
② RoundRobinAssignor(轮询)
在这里插入图片描述

③ StickyAssignor(粘滞)
这种策略复杂一点,但是相对来说均匀一点(每次的结果都可能不一样)。原则:
1)分区的分配尽可能的均匀
2)分区的分配尽可能和上次分配保持相同

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值