目录
ISR机制
数据丢失
重复消费
高吞吐的本质
kafka数据一致性简介:
kafka中的每个patition中可以有一个leader多个follower,而消息写入kafka时只是会发送到leader中,然后数据会被其他的replication拉取复制,其他的replication也就是follwer只是作为副本存在,在leader出现问题的时候才会选举成为leader,平时不会对外提供服务。
消息同步:
同步复制:消息发送到leader后,所有的follwer都同步完成之后才会commit提交
异步复制:消息发送到leader后,直接commit,follwer才会去拉取复制
ISR:
kafka中存在isr机制,leader会维护出一个与其基本保持一致的列表,该列表就是ISR,它有每个patition的leader动态维护。假如一个副本原本不再ISR列表中,但是慢慢的它的数据与leader基本同步的一致了,达到进入ISR列表的条件了,这时候leader就会把它加入到ISR中。同样的,原本在ISR列表中的副本,如果它的数据跟leader中相差太多,也会被移除ISR列表。
ISR列表有两个相关参数可以配置,达到这个标准才能在列表中:
replica.lag.time.max.ms=10000
# 如果 leader 发现 follower 超过 10 秒没有向它发起 fech 请求,那么 leader 就把它从 ISR 中移除。
rerplica.lag.max.messages=4000
# follower 与 leader 相差 4000 条数据,就将副本从 ISR 中 移除
ISR列表还有一个作用就是,当leader宕机的时候,会先从ISR列表中的副本中选出一个follwer作为leader,也会把原先的leader从ISR列表中移除。
生产者端导致数据丢失:
①producer在将数据发送到kafka的时候,kafka一开始的数据是存储到page cache中的,这个时候如果服务器忽然宕机,还没有将数据flush到磁盘上,就会造成数据丢失。
解决方案:
针对这个问题可以将flush的频率提高,但是官方不建议这种方式,建议提高副本数量来避免这一问题
log.flush.interval.messages
当缓存中有多少条数据时,触发溢写
log.flush.interval.ms
每隔多久时间,触发溢写
②当kafka使用备份机制的时候,也可能会发生数据丢失的问题。因为当producer的ack设置为0或者1的时候,只能保证leader中有数据,若这时候leader宕机,剩下的follwer还没来的及复制,就会导致数据丢失。
解决方案:
可以将ack设置为all,这时候就是上面说的同步复制了,即再发送数据的时候,会等到所有的follower都复制完成才会commit,但是这样也会影响性能,所以在实际的生产应用中也要合理的结合业务来平衡数据的一致性和性能。
消费者端导致数据丢失:
在使用kafka高级api的时候,消费者consumer每隔一段时间会自动提交offset保存到zookeeper上,这个提交偏移量默认是自动提交的,这时候如果自动提交偏移量过快,提交之后还没消费的时候机器忽然宕机,就会导致数据丢失
解决方案:
将自动提交偏移量关闭,改为手动提交,在数据全部消费完在提交。
在使用kafka高级api的时候,消费者consumer每隔一段时间会自动提交offset保存到zookeeper上,这个提交偏移量默认是自动提交的,这时候如果自动提交偏移量过慢,消费了几条消息但是这几条消息的偏移量还没来得及提交到zookeeper,机器忽然宕机,下次消费的时候就会从zookeeper上记录的偏移量开始读消息,这就造成了重复消费
解决方案:
关闭自动提交,改为手动提交
吞吐即读写
写操作:
kafka用了页缓存技术和磁盘顺序写
页缓存技术:
kafka在进行写数据的时候,是基于操作系统的页缓存来实现的。操作系统本身有一层缓存,叫做page cache,因为它是在内存中的缓存,也可以叫它os cache。
写入的数据会直接写到os cache中,接下来由操作系统决定什么时候把内存中的数据落地到磁盘中。这样就可以看作数据传输是发生在内存之间的,传输速度与直接落地到磁盘来比快很多倍。
磁盘顺序写
kafka在写数据的时候会按照磁盘顺序写,也就是说会仅仅将数据追加到文件的末尾,而不是随机的找位置来插入,这样性能就会比随机写高几百倍。
读操作
零拷贝技术
kafka的读操作如果不应用零拷贝技术会发生下面几步完成:
从上图里很明显可以看到第5和第6步骤的两次拷贝是没必要的!一次是从操作系统的cache里拷贝到应用进程的缓存里,接着又从应用程序缓存里拷贝回操作系统的Socket缓存里。
而且为了进行这两次拷贝,中间还发生了好几次上下文切换,一会儿是应用程序在执行,一会儿上下文切换到操作系统来执行。所以这种方式来读取数据是比较消耗性能的。
Kafka为了解决这个问题,在读数据的时候引入零拷贝技术。直接让操作系统的cache中的数据发送到网卡后传输给下游的消费者,中间跳过了两次拷贝数据的步骤,Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存。