简介:
Kafka是一个分布式系统:它以集群的方式运行,可以灵活伸缩(分区),在内部通过 复制数据提升容错能力和高可用性 , 高可用(主从集群),高吞吐(分区分段+索引,顺序读写,0拷贝,批量写),分布式消息持久化(文件系统),集群部署的消息中间件。
0.9版本之前offset 存储在zk,0.9版本之后offset存储在本地
注册中心 zookeeper集群
1.注册中心,producer,broker,consumer 注册 和 心跳 ,
2.topic 和 partition 等 meta 数据;
3.还负责 broker 故障发现,partition leader 选举,负载均衡等功能
leader容灾
leader的节点监听:controller会在Zookeeper的/brokers/ids节点上注册Watch,一旦有broker宕机,它就能知道。
读取对应partition的ISR(in-sync replica已同步的副本)列表,选一个出来做leader。
Kafka的Leader选举是通过在ZooKeeper上创建/controller临时节点来实现leader选举,并在该节点中写入当前broker的信息 {“version”:1,”brokerid”:1,”timestamp”:”1512018424988”}
利用ZooKeeper的强一致性特性,一个节点只能被一个客户端创建成功,创建成功的broker即为leader,即先到先得原则,leader也就是集群中的controller,负责集群中所有大小事务。当leader和ZooKeeper失去连接时,临时节点会删除,而其他broker会监听该节点的变化,当节点删除时,其他broker会收到事件通知,重新发起leader选举。
producer 集群
发送消息方式:
1.直接发送消息 acks = 0
2.异步发送消息 acks = 1 这意味着producer在ISR中的leader已成功收到数据并得到确认。如果leader宕机了,则会丢失数据。
3.同步发送消息 acks = all (-1)
配合min.insync.replicas使用,控制写入isr中的多少副本才算成功,producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。但是这样也不能保证数据不丢失,比如当ISR中只有leader时
发送机制
0.有key hash(key)% partitionSize, 没有就轮询
1.batch.size默认值是16KB,凑够16KB的数据才会发送
2.linger.ms batch最大的空闲时间
但是消息并不是必须要达到一个batch尺寸才会批量发送到服务端呢,Producer端提供了另一个重要参数linger.ms,用来控制batch最大的空闲时间,超过该时间的batch也会被发送到broker端。
3.max.in.flight.requests.per.connection"这个参数设置的值(默认是5) 消息顺序性
就是这5条消息其中的一条发送失败了,如果进行重试,那么重发的消息其实是在下个批次的,这就会造成消息顺序的错乱
发送多少条消息后,接收服务端确认,比如设置为1,就是每发一条就要确认一条,设置为5就是,发送5条消息等待一次确认
4.buffer.memory 消息缓冲池默认值32MB
sender 来不及发送,并发太快,线程阻塞 max.block.ms默认值30000ms(30秒),生产者会抛出超时异常。线程无法释放,很快tomcat就会没有线程可用
Sender线程来不及把消息发送到Kafka,当生产者的发送缓冲区已满(producer 发送消息太快),这时候就会线程阻塞。阻塞时间达到 max.block.ms默认值30000ms(30秒) 时,生产者会抛出超时异常。线程分分钟就会全部被阻塞,web容器在没有可用线程时收到的请求一般还会存放在队列中等待响应,线程得不到释放意味着内存同样无法被释放,所以很快内存就溢出了。
5.批量发送机制
Accumulator 负责 消息按照每个分区进行分批, sender线程会去遍历 分区的每个批次的消息 去发送
Kafka中producer的幂等是怎么实现的
kafka 会维护一个 producer 的pid 对应 partition的分区 的一个序列号,这个序列号自增
小于 就丢弃,大于直接报错(说明消息丢失)
为了实现生产者的幂等性,broker 端会在内存中为每一对 <PID,分区> 维护一个序列号,对于收到的每一条消息,只有当它的序列号的值(SN_new)比 broker 端中维护的对应的序列号的值(SN_old)大1(即 SN_new = SN_old + 1)时,broker 才会接收它。如果 SN_new< SN_old + 1,那么说明消息被重复写入,broker 可以直接将其丢弃。如果 SN_new> SN_old + 1,那么说明中间有数据尚未写入,出现了乱序,暗示可能有消息丢失,对应的生产者会抛出 OutOfOrderSequenceException,这个异常是一个严重的异常,后续的诸如 send()、beginTransaction()、commitTransaction() 等方法的调用都会抛出 IllegalStateException 的异常。
producer 性能优化的设计
1.增加batch.size
2.linger.ms(消息滞留时间),启用压缩 LZ4,关闭重试
3.buffer.memory 缓存池 避免内存溢出 发送消息线程阻塞