Apache kafka原理

1.分区副本机制

分区机制:主要解决了单台服务器存储容量有限和单台服务器并发数限制的问题 ,一个分片的不同副本不能放到同一个broker上。

副本机制:副本备份机制解决了数据存储的高可用问题

kafka中,副本的作用仅仅是冗余备份,所有的读写请求都是由leader副本处理。follower副本仅有一个作用那就是从leader副本中拉取消息保持一致。多个follower副本通常存放在和leader副本不同的broker中,leader上副本down掉时,follower副本会转正,成为leader。


follower副本不对外提供服务的原因:

这个问题本质上是对性能和一致性的取舍。试想一下,如果follower副本也对外提供服务那会怎么样呢?首先,性能是肯定会有所提升的。但同时,会出现一系列问题。类似数据库事务中的幻读,脏读。

比如你现在写入一条数据到kafka主题a,消费者b从主题a消费数据,却发现消费不到,因为消费者b去读取的那个分区副本中,最新消息还没写入。而这个时候,另一个消费者c却可以消费到最新那条数据,因为它消费了leader副本。为了提高那么些性能而导致出现数据不一致问题,那显然是不值得的。

2.数据不丢失机制

分为消息生产者和消费者两方

消息生产者保证数据不丢失:消息确认机制(ACK机制),参考值有三个:0,1,-1

//producer无需等待来自broker的确认而继续发送下一批消息。
properties.put(ProducerConfig.ACKS_CONFIG,"0");

//producer只要收到一个分区副本成功写入的通知就认为推送消息成功了。
//这里有一个地方需要注意,这个副本必须是leader副本。
//原因在上述副本分区机制中涉及
properties.put(ProducerConfig.ACKS_CONFIG,"1");

//ack=-1,简单来说,producer只有收到分区内所有副本的成功写入的通知才认为推送消息成功了。
properties.put(ProducerConfig.ACKS_CONFIG,"-1");

消息消费者保证数据不丢失:需要关闭自动提交位移

原因:由于Kafka consumer默认是自动提交位移的(先更新位移,再消费消息),如果消费程序出现故障,没消费完毕,则丢失了消息,此时,broker并不知道。

properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"false");

3.消息存储及查询机制

存储机制:

kafka 使用日志文件的方式来保存生产者消息,每条消息都有一个 offset 值来表示它在分区中的偏移量。

为避免日志文件过大,一个分片并不是直接对应在一个磁盘上的日志文件,而是对应磁盘上的一个目录,这个目录的命名规则是<topic_name>_<partition_id>

该分区目录中采用多文件存储方式,每个文件称之为LogSegment,一个 LogSegment 对应磁盘上的一个日志文件(00000000000000000000.log)和一个索引文件(00000000000000000000.index)。日志文件是用来记录消息的,索引文件是用来保存消息的索引。LogSegment 的大小可以在server.properties 中log.segment.bytes设置。

查询机制:

第一步查询LogSegment:

segment file命名规则跟offset有关,根据segment file可以知道它的起始偏移量,因为Segment file的命名规则是上一个segment文件最后一条消息的offset值。所以只要根据offset 二分查找文件列表,就可以快速定位到具体文件。

第二步通过segment file查找message:

通过第一步定位到segment file,当offset=5000时,依次定位到00000000000000000000.index的元数据物理位置和00000000000000000000.log的物理偏移地址,然后再通过00000000000000000000.log顺序查找直到offset=5000为止。

4.消费者负载均衡机制

同一个分区中的数据,只能被一个消费者组中的一个消费者所消费,多个消费组可以重复消费消息。

kafka 副本同步 优化 kafka副本同步机制_kafka

  • 如果有3个Partition, p0/p1/p2,同一个消费组有3个消费者,c0/c1/c2,则为一一对应关系;
  • 如果有3个Partition, p0/p1/p2,同一个消费组有2个消费者,c0/c1,则其中一个消费者消费2个分区的数据,另一个消费者消费一个分区的数据;
  • 如果有2个Partition, p0/p1,同一个消费组有3个消费者,c0/c1/c3,则其中有一个消费者空闲,另外2个消费者消费分别各自消费一个分区的数据;