前不久在工作过程中用到了kafka中间件,简单来说是个消息队列,除了支持高吞吐量、发布订阅等功能外,它还支持回放,我可以通过修改偏移量重新获取数据,这个功能是一个非常常见的使用场景,也是我选择kafka的一个重要原因。但kafka追随者副本不对外提供服务,乍看起来,令人百思不得其解,MySQL、redis都可以使用通过读从节点从而分摊主节点的压力。为什么kafka不这样设计呢?究其原因它的设计思路是读自己的写以及单调读,这种做法就不会因为读取follower的数据而导致的数据不一致。相信我们在使用MySQL或者redis的时候就经常碰到一个问题就是在从多个从节点查询数据时,某条数据一会存在一会不存在的问题,当然MySQL和redis也是有对应的解决方案,这个我们后面在说。kafka的从节点的存在有什么意义?毫无疑问提供数据冗余、主从切换。kafka的follower自动从leader拉取消息,kafka会把符合时间间隔标准的follower添加到ISR同步集合中。当leader宕机后,就会从ISR集合中选举一个follower升级为leader。那么到底以什么标准进行选举呢?这个标准就是Broker端参数replica.lag.time.max.ms参数值。这个参数的含义是Follower副本能够落后Leader副本的最长时间间隔,当前默认值是10秒。这就是说,只要一个Follower副本落后Leader副本的时间不连续超过10秒,那么Kafka就认为该Follower副本与Leader同步的,即使此时Follower副本中保存的消息明显少于Leader副本中的消息。我们在前面说过,Follower副本唯一的工作就是不断地从Leader副本拉取消息,然后写入到自己的提交日志中。如果这个同步过程的速度持续慢于Leader副本的消息写入速度,那么在replica.lag.time.max.ms时间后,此Follower副本就会被认为是与Leader副本不同步的,因此不能再放入ISR中。此时,Kafka会自动收缩ISR集合,将该副本踢出ISR。值得注意的是,倘若该副本后面慢慢地追上了Leader的进度,那么它是能够重新被加回ISR的。这也表明,ISR是一个动态调整的集合,而非静态不变的。可能我们第一感觉总是当然是根据消息的落后数量了,但是其实不是的,其主要原因是时间这个参数很难给出一个合适的值,比如以默认值4000为例,如果我的tps是10,那么这个值就没有任何参考意义,因为太大了;如果tps是2000,那么一定会引起ISR集合的频繁变动,所以kafka从0.9x废弃了该参数。如果所有的副本延时都比较大,ISR集合中没有一个副本,该怎么办?其实我们可以通过配置至少存在一个副本或者开启Unclean选举。Kafka如何保证leader和Follower之间的数据一致性呢?