什么是kafka
如上图,我们常用的通信方式有点对点通信、代理通信;点对点通信适合用户量小的场景;代理通信适合用户量大的场景。
kafka就是一个代理通信的组件。
kafka的特性、使用场景
kafka的特性
- 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒。
- 可扩展性:kafka集群支持热扩展
- 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
- 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
- 高并发:支持数千个客户端同时读写
kafka的使用场景
- 日志收集:收集各个系统的日志,以统一接口服务的方式开放给各种系统消费。
- 消息系统:解耦和生产者和消费者、缓存消息等。
- 用户活动跟踪:记录web用户或者app用户的各种活动信息到主题,如浏览网页、搜索、点击等活动信息,然后订阅者通过订阅这些主题来做实时的监控分析,或做离线分析和挖掘。
- 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
- 流式处理:比如spark streaming和storm。
kafka的架构
- Producer: 消息生产者,将消息发送到kafka服务器
- Broker:Kafka服务器节点,管理消息
- Consumer: 获取消息并处理
- Zookeeper 存储节点元数据
思考1:为什么 0.8 版本之后,生产者不在依赖于zookeeper?
答:为了防止zookeeper被过多的客户端连接。
思考2:为什么消费端要依赖于zookeeper?
答:因为消费端是主动拉取,而不是被动推送,所以需要实时监控节点的变化信息。所以不能省略。
zookeeper的作用
zookeeper的作用主要是存储kafka集群的元数据信息。
如上图:我们可以看到在zookeeper中存储了kafka集群的broker、topic和消费者等信息。
消息存储
主题、分区、副本
1)、在kafka中数据被存储在主题中;
2)、每个主题被划分为若干个分区,这样做的目的,主要是为了提高kafka的吞吐量;
3)、每个分区被分为若干个副本,副本被分为leader副本、Follower副本;leader副本负责数据的读、写;follower副本负责容错。
4)、副本的数量应该小于broker的数量;
kafka的存储方式
Kafka中每个partition被划分成多个segment来组织数据。
在磁盘上,一个partition就是一个目录,然后每个segment由一个index文件和一个log文件组成。如下:
- log文件:log文件就是存储消息的地方,每个消息都会包含消息体、offset、timestamp、key、size、压缩编码器、校验和、消息版本号等;
- 索引(Index):Segment的index负责映射消息offset到某个消息在log文件中的位置;
- log文件的文件名就是这个log中第一条消息的offset;
log和index
- index中采用的是稀疏索引的方式;
- kafka采用的是二分查找的方式来定位offset,假如我们需要查找第5条消息,kafka会首先找到第3条消息的offset,然后顺序找到第5条消息;
容错机制
如下面zookeeper集群
1.如果Leader宕机
其它的Follower会通过选举产生新的Leader。
2.如果Follower宕机
Leader会动态感知,然后将原来的partition副本进行下线;在其恢复之后,才将已经下线的副本上线。
副本复制模式
同步复制
1、生产者联系zookeeper,找到leader;
2、生产者向leader发送消息;
3、leadr收到消息写入到本地log;
4、follower从leader pull(拉取)消息;
5、follower向本地写入log;
6、follower向leader发送ack(确认)消息;
7、leader收到所有follower的ack(确认)消息;
8、leader向生产者回传ack(确认)消息;
异步复制
和同步复制的区别在与leader写入本地log之后,直接向生产者回传ack(确认)消息,不需要等待所有follower复制完成,这样做的缺点是,副本复制过程可能会出现异常。
集群分片分配算法、分区平衡
1、集群分片分配算法
建设有n个broker, i个Partition;
- 第一个Partition0,是随机的散落到某一个节点上;
- 将所有n个broker, i个Partition排序(随机散落的节点排在第一位);
- 将第i个Partition分配到第 (i % n)个broker上;
- 将第i个Partition的第j个副本分配到第 ((i+j)%n)个broker上;
原理:负载均衡,将Leader分区散落到不同的broker上(Leader负责读写,Follower只是负责同步数据);
2、分区平衡
- 1、1个partition的默认leader是replicas中的第一个replica;
- 2、kafka controller会启动一个定时的check线程,kafka默认是5min周期,去check当前的leader信息;
- 3、该线程的工作原理: check每台alive的broker当前的元数据信息中的partition的leader信息,然后和默认的leader(1)的值进行比较,求出imbalanceRatio(比例);
- 4、比较发现这个比例超过10%(kafka默认),则进行rebalance;
言下之意就是当一个broker中leader分区过多的时候,就会进行重分区;
日志清除
1、按时间周期进行清除
按照我们数据的最后的offset的数据写入时间作为该offset的最后修改时间;如果当前时间 - 最后offset的时间 > 配置时间周期 就会对segment进行清除。
2、压缩清除法
本质是只保留所有key的最后一个版本的数据。
压缩清除法的使用场景:保存用户等数据的时候,可以使用压缩清除法(只保存最后一次修改的数据)。
消息发送
1、kafka生产者在本地会存在一个缓存队列,当满足发送条件的时候,会将一整批数据发送到相应的分区中;
2、当满足一定的时长或者队列存满的情况都会触发发送条件;
分区器
1、消息发送前,先通过分区器Partitioner进行数据路由,选择某一个Topic分区。如果没有指定key,消息会被均匀的分配到所有分区。
2、可通过实现 Partitioner 接口扩展分区策略。
同步或异步发送方式
1、同步:生产者发一条消息时,立马发送到某个分区。每个follower同步leader消息,确认成功后,leader再向客户端发送确认。特点:低延迟、低吞吐率、无数据丢失。
2、异步:生产者发一条消息时,先写到缓冲区,缓冲区里的数据还没写到broker集群的某个分区时,就返回发送成功。特点:高延迟、高吞吐率、可能会有数据丢失。
消息传播
ISR
AR: assinged replica 某一个分区已经分配的副本列表;
ISR: in-sync replica 跟主副本保持同步的副本列表;
Leader副本: AR的第一个副本;
1、如果一个Follower比Leader落后太多,或者超过一定时间未发起数据复制请求,则Leader将其从ISR中移除。
2、Leader写入数据后并不会告诉Producer消息发送成功(Commit),只有ISR列表中的所有 Folower 同步之后才会 Commit。
3、设置ISR主要是为了broker宕掉之后,将从ISR列表中重新选举partition的leader。
ack
- ack=1,只要leader分区成功写入,就认为消息发送成功。
- ack=0,producer发送一次就不再发送了,不管是否发送成功。
- ack=-1,只有收到分区内所有副本的成功写入的通知才认为推送消息成功了。
消息消费
消费组
1、一个Consumer只能属于一个Consumer Group(消费组),Consumer Group是整个Kafka集群唯一的。
2、对于每一条消息,在同一个Consumer Group里只会被一个Consumer消费。
3、消息被消费后,并不会删除,只是相应的offset加一,消费者从某个Partition读取的最后一条消息的offset(偏置量)存于Zookeeper中(0.10.1.1版本后默认存于 Kafka 服务器 Topic:__consumer_offsets 中)。
4、一个partition只能对应一个消费组中的消费者,内置的Partition分配策略:Range与RoundRoboin。
偏移量
- 偏移量用来记录消费组的消费情况;
- 偏移量设置不当会带来数据丢失和重复消费问题;
偏移量提交策略
- 自动提交(默认;
- 提交当前偏移量;
- 异步提交;
- 同步和异步组合提交;
- 提交特定的偏移量;
- 再均衡监听器;