kafka是基于发布、订阅模式的消息队列,由scala写成,吞吐强悍,适用于大数据实时处理。

优点

  • 多个生产者消费者
  • broker横向扩展
  • 数据冗余
  • 通过topic将数据分类
  • 分批发送压缩数据,减少传输开销提高吞吐
  • 支持多种模式消息,基于磁盘持久化
  • 高性能,亚秒级延迟
  • 消费者可以消费多个topic
  • 对cpu 网络 内存的消耗小
  • 支持跨数据中心的数据复制和镜像集群

缺点

  • 批量发送不是真的实时
  • 只能实现分区内有序,不能实现全局有序
  • 监控不完善
  • 会丢失数据,不支持事务
  • 会重复消费

架构

image.png
topic:
producer:生产者
consumer group:消费组,内含多个消费者。
consumer:消费者从broker拉取消息,以适当速度消费消息。
offset:偏移量,相当于消息在队列里的位置。

broker:kafka集群由多个实例组成,每个实例称为broker。一个broker可以被多个topic共用。
partition:一个topic分成多个partition,每个partition处理一部分消息,每个partition内有序,每个partition只能由一个consumer消费,一个consumer可以消费多个partition,partition数<=consumer数。通过分区可以方便扩展,提高并发。
Replication:一个partition分成leader和多个follower,他们都成为replication,分布在多个broker上,replication数不能超过broker数。

原理

写入方式

producer采用 push 模式将消息发布到 broker,每条消息都被 append 到 patition 中,被赋予了一个唯一的 offset 值。属于 顺序写磁盘 ,顺序写比随机写要起码提速3个数量级!

分区方式

1.指明partition
2.没指明,但又key,将key的hash值对分区数取余
3.没有key,第一次调用时随机生成一个整数,此后每次自增,用这个数对分区数取余(round-robin算法)

存储结构

image.png
每个partition分为多个segment,每个segment有一个.INDEX存放索引(log文件中消息的偏移地址)和一个.LOG存放数据。index和log文件以自己第一条消息的偏移量命名。

数据可靠性

at least once
at most once
exactly once

生产者信息发送至Broker
  1. producer 从 ZK 找到目标 Partition 的 Leader 元数据。
  2. producer 发送消息给 Leader。
  3. Leader 接受消息持久化,然后根据acks配置选择如何同步Follower。
  4. Follower 按照前面说的同步数据后给Leader回复ack。
  5. Leader 跟 Follower 同步完毕后 Leader 给 producer 回复 ack。

acks配置

request.required.acks = 0

producer不等待 broker 的ack,提供了一个最低的延迟,broker接收到还没有写入磁盘就已经返回,当broker故障时有可能丢失数据,对应 At Most Once 模式。

request.required.acks = 1

默认值,producer 等待 broker 的 ack,partition 的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将会丢失数据;认为leader返回 信息就成功了。

request.required.acks = -1 / all

producer 等待 broker 的 ack,partition 的 leader 和 follower (ISR中的)全部落盘成功后才返回 ack。
但如果在 leader 收到信息返回ok,follower 收到信息但是发送 ack 时 leader 故障,此时生产者会重新给follower 发送个信息。
对应 At Least Once 模式。

幂等性

无论生产者发送多少个重复消息,Server端只会持久化一条数据,在生产者参数中 enable.idompotence= true。运用的是broker对requestno做缓存的原理。

数据落磁盘

producer.type = sync,默认模式,数据落盘才ok
producer.type = async,异步模式,数据刷新到os的page cache就返回,如果宕机数据就丢失了。

拉取数据

消费者从broker拉取消息分成两个阶段
1.获得数据,提交offset
2.处理数据
如果先提交offset再处理数据会可能会处理失败。如果先处理数据再提交offset可能会重复消费。

  • 如果broker里没有数据,消费者可能陷入拉取循环。消费者在消费时会传入一个时长参数,如果当前没数据可供消费,消费者会等待一段时间之后再返回。

分区策略

通过paritition.assignment.strategy来设置

  1. rangeAssignor 范围分区,默认模式
    分区对消费者做hash,如果除不尽,前面的会多消费一个分区

    • 缺点:对于每个除不尽的topic前面的消费者都多消费一个分区,极少成多,就不平衡了
  2. roundRobinAssignor 分配策略,轮询分区
    把所有partition和所有consumer拿出来,hash分区。
    当所有consumer订阅的topic一样时,是平衡的。
    当所有consumer订阅的topic不一样事,就不平衡了。

高效读写

tps:事务数/秒 qps:查询数/秒 kafka可以百万tps

顺序读写数据
内存映射文件
  1. 虚拟内存把内存切分为和物理内存一样的虚拟页
  2. 用os的page实现物理内存到文件的映射,操作读写数据到page中,os根据映射对应到物理硬盘上,实现类似顺序读写的功能
  3. 缺点是不落真正的磁盘可能导致数据丢失

    直接读取内存DMA(direct memory access)

    外部设备不经过cpu而直接和系统内存交换数据的技术叫做DMA。
    数据传输只用到了DMA没经过cpu,称作zero copy,零拷贝。
    kafka读写时数据,磁盘读取数据到操作系统内存page cache;再传输到nic网卡缓存区。
    image.png

    batch deal

    消费者拉取数据时,kafka不是一个一个送数据的,是批量处理的,这样可以节省网络传输,增大tps,缺点是降低实时性。

zookeeper作用

1 broker注册
管理分布式部署并相互独立的broker
2 topic注册
topic的partition信息和其分布的broker信息是zookeeper来维护
3 消费者注册
消费者启动会在zookeeper下创建节点,消费者会互相监听变化,方便负载均衡,消费者也会监听broker,方便负载均衡。
4 生产者负载均衡
生产者合理的把消息分给各分区
5 消费者负载均衡
消费者去哪个broker拉取信息
一个消费者可以听多个分区
6 分区与消费者的关系
消费者id要写到分区节点上
7 消费进度(customer offset)
用于失败重试、消费者重启或其他消费者接管后继续进度

多个消费者问题

rocket mq:复制消息
kafka:zookeeper记录消费者的offset(张三消费到这了,李四消费到这了)

为什么不搞读写分离?

kafka只能读写master,slave完全是备份。

主从的好处和缺点

好处:从节点分担主节点的读压力。
缺点:1.主从数据不一致。2.延时。redis主从需要经历网络→主节点内存→网络→从节点内存。kafka要经历网络→主节点内存→主节点磁盘→网络→从节 点内存→从节点磁盘,更加耗时。

  • 读写分离是为了负载均衡,但是kafka已经很均衡了。主副本可以平均分在各个broker上。
  • 分配不均的可能和破解办法

    • 某些broker分到的分区数比别的broker多
    • 生产者只向部分分区写入
    • 消费者只消费部分分区
    • 副本切换不均,某些broker中leader特别多

?zooker是怎么决定哪个broker放主副本哪个broker放从副本的?
?kafka的分配算法
?kafka的优先副本选举


cathy_mu
15 声望1 粉丝