kafka是基于发布、订阅模式的消息队列,由scala写成,吞吐强悍,适用于大数据实时处理。
优点
- 多个生产者消费者
- broker横向扩展
- 数据冗余
- 通过topic将数据分类
- 分批发送压缩数据,减少传输开销提高吞吐
- 支持多种模式消息,基于磁盘持久化
- 高性能,亚秒级延迟
- 消费者可以消费多个topic
- 对cpu 网络 内存的消耗小
- 支持跨数据中心的数据复制和镜像集群
缺点
- 批量发送不是真的实时
- 只能实现分区内有序,不能实现全局有序
- 监控不完善
- 会丢失数据,不支持事务
- 会重复消费
架构
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算法)
存储结构
每个partition分为多个segment,每个segment有一个.INDEX存放索引(log文件中消息的偏移地址)和一个.LOG存放数据。index和log文件以自己第一条消息的偏移量命名。
数据可靠性
at least once
at most once
exactly once
生产者信息发送至Broker
- producer 从 ZK 找到目标 Partition 的 Leader 元数据。
- producer 发送消息给 Leader。
- Leader 接受消息持久化,然后根据acks配置选择如何同步Follower。
- Follower 按照前面说的同步数据后给Leader回复ack。
- 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来设置
rangeAssignor 范围分区,默认模式
分区对消费者做hash,如果除不尽,前面的会多消费一个分区- 缺点:对于每个除不尽的topic前面的消费者都多消费一个分区,极少成多,就不平衡了
- roundRobinAssignor 分配策略,轮询分区
把所有partition和所有consumer拿出来,hash分区。
当所有consumer订阅的topic一样时,是平衡的。
当所有consumer订阅的topic不一样事,就不平衡了。
高效读写
tps:事务数/秒 qps:查询数/秒 kafka可以百万tps
顺序读写数据
内存映射文件
- 虚拟内存把内存切分为和物理内存一样的虚拟页
- 用os的page实现物理内存到文件的映射,操作读写数据到page中,os根据映射对应到物理硬盘上,实现类似顺序读写的功能
缺点是不落真正的磁盘可能导致数据丢失
直接读取内存DMA(direct memory access)
外部设备不经过cpu而直接和系统内存交换数据的技术叫做DMA。
数据传输只用到了DMA没经过cpu,称作zero copy,零拷贝。
kafka读写时数据,磁盘读取数据到操作系统内存page cache;再传输到nic网卡缓存区。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的优先副本选举
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。