目录
一、消息可靠性传输,是非常重要,消息如果丢失,可能带来严重后果
二、Kafka数据存储流程和log日志
三、kafka的副本(replica)
四、生产者发送数据流程
五、副本数据同步机制和问题
六、Partition什么时间发送ack确认机制(要追求高吞吐量,那么就要放弃可靠性)
producer端:
不采用oneway发送,使用同步或者异步方式发送,做好重试,但是重试的Message key必须唯一
投递的日志需要保存,关键字段,投递时间、投递状态、重试次数、请求体、响应体
broker端:
多主多从架构,需要多机房
同步双写、异步刷盘 (同步刷盘则可靠性更高,但是性能差点,根据业务选择)
机器断电重启:异步刷盘,消息丢失;同步刷盘消息不丢失
硬件故障:可能存在丢失,看队列架构
consumer端
消息队列一般都提供的ack机制,发送者为了保证消息肯定消费成功,只有消费者明确表示消费成功,队列才会认为消息消费成功,中途断电、抛出异常等都不会认为成功——即都会重新投递,每次在确保处理完这个消息之后,在代码里调用ack,告诉消息队列消费成功
消费端务必做好幂等性处理
消息消费务必保留日志,即消息的元数据和消息体
Kafka 采取了分片和索引机制,将每个partition分为多个segment,每个segment对应2个文件 log 和 index
index文件中并没有为每一条message建立索引,采用了稀疏存储的方式
每隔一定字节的数据建立一条索引,避免了索引文件占用过多的空间和资源,从而可以将索引文件保留到内存中
缺点是没有建立索引的数据在查询的过程中需要小范围内的顺序扫描操作。
配置文件 server.properties
# The maximum size of a log segment file. When this size is reached a new log segment will be created. 默认是1G,当log数据文件大于1g后,会创建一个新的log文件(即segment,包括index和log)
log.segment.bytes=1073741824
举例:
#分段一
00000000000000000000.index 00000000000000000000.log
#分段二 数字 1234指的是当前文件的最小偏移量offset,即上个文件的最后一个消息的offset+1
00000000000000001234.index 00000000000000001234.log
#分段三
00000000000000088888.index 00000000000000088888.log
每个topic下都有多个partition,每个partition可以设置有N个副本, 副本数最好要小于broker的数量
每个分区有1个leader和0到多个follower,我们把多个副本分为Learder replica和follower replica
保证producer 发送到指定的 topic, topic 的每个 partition 收到producer 发送的数据后
需要向 producer 发送 ack 确认收到,如果producer 收到 ack, 就会进行下一轮的发送否则重新发送数据
当producer在向partition中写数据时,根据ack机制,默认ack=1,只会向leader中写入数据
然后leader中的数据会复制到其他的replica中,follower会周期性的从leader中pull数据,对于数据的读写操作都在leader replica中,follower副本只是当leader副本挂了后才重新选取leader,follower并不向外提供服务
假如还没同步完成,leader副本就宕机了,怎么办?
kafka中有几种关于follower从leader同步数据的方式。相当于把分布式CAP理论中的C和A做成配置项ack。可以根据业务做选择使用哪种。
当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别
副本数据同步策略 , ack有3个可选值,分别是0, 1,all。
ack=0
producer发送一次就不再发送了,不管是否发送成功
发送出去的消息还在半路,或者还没写入磁盘, Partition Leader所在Broker就直接挂了
存在的问题:客户端认为消息发送成功了,此时就会导致这条消息就丢失
ack=1(默认)
只要Partition Leader接收到消息而且写入【本地磁盘】,就认为成功了,不管他其他的Follower
有没有同步过去这条消息了
存在的问题:万一Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了
ack= all(即-1)
producer只有收到分区内所有副本的成功写入全部落盘的通知才认为推送消息成功
备注:leader会维持一个与其保持同步的replica集合,该集合就是ISR,leader副本也在ISR里面
当ack=all时,会有以下2个问题:
问题一:如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复
数据发送到leader后 ,部分ISR的副本同步,leader此时挂掉。比如follower1和follower2都有可能变成新的leader, producer端会得到返回异常,producer端会重新发送数据,数据可能会重复
重复消费问题,任何队列都无法避免,所以消费端应用程序应该做好幂等性处理。
问题二:acks=all 就可以代表数据一定不会丢失了吗
Partition只有一个副本,也就是一个Leader,任何Follower都没有.接收完消息后宕机,也会导致
数据丢失,acks=all,必须跟ISR列表里至少有2个以上的副本配合使用
在设置request.required.acks=-1的同时,也要min.insync.replicas这个参数设定 ISR中的最
小副本数是多少,默认值为1,改为 >=2,
如果ISR中的副本数少于min.insync.replicas配置的数量时,客户端会返回异常
分布式CAP理论中C和A的选择可以看看这个博文:
分布式应用核心CAP知识_wnn654321的专栏-CSDN博客