分片与副本机制
- 分片
分片是一种逻辑概念,将topic比作一个大容器,一个topic可以拆分为多个小容器,多个小容器可以构建为一个topic - 分片的目的
- 提高读写效率:分片可以分布在不同节点上,在进行读写的时候,可以让多个节点一起负责
- 分布式存储:解决单节点存储容量优先的问题
- 副本
副本是一种物理的概念,针对每个分片的数据,可以将其进行备份- 副本的目的:提高数据可靠性,防止数据丢失
- 副本的数量:最多与节点数保持一致
kafka保证数据不丢失
1、生产者端保证数据不丢失
在生产者端,数据生产发送到Broker后,Broker提供一个确认响应ack,ack返回的值有0
、1
、-1|ALL
,分别代表的含义是
- ack=0: 生产者只发送数据,不关心Broker的响应
- ack=1:生产者发送数据到Broker端,等待Broker端中topic对应分片上的主副本接收到消息后,才认定为发送成功
- ack=-1|ALL:生产者发送数据到Broker端,等待Broker端中topic对应分片上所有副本都接收到消息后,才认定为发送成功
从效率来说:0 > 1> -1
从安全角度来说:-1 > 1 > 0
在实际使用中,三种方案都有可能,在数据非常重要的情况下,选择-1,如果关心效率问题,不在意丢失的情况,选择0,如果允许数据有一定丢失的情况,可以选择1。
思考点:
- 如果Broker迟迟未给ACK响应该如何解决?
可以设置超时时间,如果超时进行重试,多次重试无法解决,程序会出现报错的情况
- 每次发送数据,Broker就要给予一次ACK响应,对网络带宽会造成影响,如何处理?
对于经常使用的数据,引入缓存池,池中的数据到一定条件后,通过异步的方式发送到Broker端,Broker则需要针对这批数据给予一次响应
- 通过按批次异步发送数据,如果Broker端对这批数据没有给予响应,此时缓存池中数据已经满了,如何解决?
如果数据是可重复读的情况下,可以选择清空缓存池,让程序报错,通知处理,处理后,重新读取发送;如果数据是不可重复读的,此时需要对数据进行一个备份,当数据生产成功时,删除其备份,如果生产失败,可以在对应的位置上重新拉取处理(补推)。不清空缓存池的情况下,可以让程序阻塞写入,一直等待。
相关配置:
# 缓存池的大小 默认值32M
buffer.memory :33554432
# 重试次数, 最终重试不完全取决于此参数
retries :2147483647
# 一次发送数据总的超时时间 默认值为 120000(120s)
delivery.timeout.ms :120000
# 一次请求的超时时间 默认值为30000(30s)
request.timeout.ms :30000
# 最终重试次数: (delivery.timeout.ms / request.timeout.ms) -1
# 一批数据的大小 默认值 16384(16kb)
batch.size: 16384
# 每一批次的间隔时间 默认值 0
linger.ms :0
2、broker端保证数据不丢失
broker端保证数据不丢失的方案:磁盘存储 + 多副本 + ack为-1
3、消费端保证数据不丢失
- consumer启动后,连接到kafka,根据group.id搜索kakfa上次消费的位置
- 如果找到上次消费的位置,就接着从这个位置开始消费数据,如果没找到,则是第一次到来,消费的位置从当前消息的偏移量位置开始
- 消费者每次消费完数据,都要向kafka进行汇报,汇报当前消费到哪个偏移量信息
通过这种方式,可以保证消费端数据不丢失,但是会存在数据重复消费的问题。
在0.8.x版本之前,消息的偏移量记录在zookeeper上
在0.8.x版本后,消息的偏移量记录在kafka集群上,通过一个topic进行记录:__consumer_offsets,该topic共有50个分片,每个分片下有一个副本
kafka消息存储和查询机制
- segment
- 由两个文件组成:index文件和log文件,log文件存储消息数据,index文件存储log文件位置(索引)
- 默认情况下,log文件最大为1GB,当到达1GB后,会滚动形成新的log文件,同时index文件也会滚动形成新的文件
- 文件名表示当前消息的起始偏移量
- 在默认情况下,kafka会自动删除超过7天的数据
相关配置:
# server.properties
log.retention.hours=168
log.segment.bytes=1073741824
- 数据查询机制
查询数据的步骤分为3步:
- 确定数据存储在哪个segment
- 找到对应segment的index文件,根据index找到log位置
- 返回log文件的位置信息,基于磁盘顺序查询找到log文件,读取log文件中的数据。
kafka消费者负载均衡机制
对于kafka消费者负载均衡:
- 在同个消费者组内,消费者数量最多和所监听的topic分片数量是相等的,如果有大于分片数量的消费者,则会存在消费者处于闲置的状态
- 在同个消费者组内,topic的一个分片数据只能被一个消费者接收,不允许出现一个分片被多个消费者接收,而一个消费者可以接收多个分片数据
模拟场景:
现在有一个topic(3个分片),1个副本,有一个consumer,每分钟可以消费40条消息
1、生产者每分钟生产40条消息到topic,此时消费者每分钟可以消费40条数据,两者到达均衡,此时是一个理想化的状态。
2、生产者生产的数据量变为120条,消费者消费能力不变,此时会发生数据积压,此时我们可以通过增加消费者来解决这个问题,前提是新增的消费者在同一个消费者组内;也可以通过提高消费者消费速度来解决。
3、解决以上问题后,生产者消费者的能力持平,又达到理想化状态,随着时间推移,生产者生产速度又快了,到达160,此时假设我们再增加消费者,还是会出现数据积压问题,此时我们可以尝试增加topic的分片数量,同时提升消费者的消费速度。
- 对于点对点消费模式:所有监听这个topic的消费者都在同一个消费者组内
- 对于发布订阅模式:所有监听这个topic的消费者在不同消费者组内
查看数据积压命令:
kafka-consumer-groups.sh --bootstrap-server zk1:9092,zk2:9092,zk3:9092 --group yourgroupname --describe