kafka会把每个topic下的partitions复制到多个server(server数可以设置,通过设置每个分区的复制因子)。当集群中的一台server故障的时候,可以自动地实现故障转移,消息仍然可用。
其他的消息系统也提供了一些复制的功能,但是在我们看来,这体现为一种附加功能,不是经常使用,并且带有大的缺点:slaves是不活动的,吞吐量受到严重影响,需要精确的人工设置等等。而kafka默认使用复制-事实上,我们是通过把带复制的topics的复制因子设置为1来实现不带复制的topics的
复制的基本单元是topic partition。在不失败的情况下,kafka的每一个partition有一个leader和0或多个followers。1leader+nfollowers(n>=0)组成复制因子。所有的读和写都去到leader partition。通常,分区数比brokers多很多,leaders会均衡地分不到brokers上。followers上的logs和leader上的logs是一致的(当然,在任意时间the leader的logs的尾部会有还没有复制的message)
Followers和kafka普通消费者一样从leader消费并应用到自己的log。followers批量地拉取leader的message会有好的性能。
正如大多数的分布式系统一样,自动处理故障需要节点是否活着的精确定义。在kafka里,节点活跃有两个条件
1.一个节点必须能维护它和Zookeeper的session(通过Zookeeper的心跳机制)
2.如果它是一个slave,必须复制leader发生的写,并且不落后太多
我们把满足这两个条件的节点说成是“in sync”状态,避免“活着”和“失败”的含糊。leader将保持追踪“in sync”状态的节点集。如果一个follower挂了,或者停止复制了,或者落后了,leader会把它从“in sync”节点集中删除。通过参数replica.lag.max.messages设置落后多少可以删除,通过参数replica.lag.time.max.ms设置停止复制多少时间可以删除
在分布式系统术语中,我们只尝试解决“fail/recover”失败模型,即节点突然停止工作,但过一会儿又重新恢复(可能都不知道它们挂过)。kafka不去处理“Byzantine”失败,即节点产生任意的或者恶意的回应(可能由于bug或误操作)
当一个消息被它所在分区的所有的in sync的复制者应用到它们的日志后才被认为是“commited”状态。消费者只能消费“committed”状态的消息。所以消费者不用担心正在看到的message当leader失败的时候会丢失。另一方面,生产者可以选择可以等待状态到“committed”,也可以不等,取决于延迟和持久化的权衡。生产者可以使用request.required.acks参数设置
kafka可以保证只要有一个in sync状态的复制者存活,消息就不会丢失
kafka当出现短时间的节点失败时仍然可用,但是出现网络分区问题时可能会不可用