之前我分享了一个视频,《分布式系统中的强一致性和弱一致性》,我们来看看Kafka是怎么保证一致性的。

权衡 trade-offs

鱼和熊掌不可兼得。系统设计需要根据具体的应用场景做出权衡。

  • 吞吐量 - 每分钟可以写入多少消息,可以消费多少消息?
  • 可用性 - 可以同24x7的不间断服务吗?
  • 可靠性 - 写入的消息,可以保证顺序不变吗?保证不丢吗?
  • 一致性 - 确保所有的消费者都能读到一样的消息吗?
  • 低延迟 - 写入和读出消息的响应时间是几毫秒?
  • 磁盘空间 - 需要多大的磁盘空间来存储这些消息?

系统设计者可以通过配置Kafka,来得到不同程度的需求满足。

主从副本 Replication

每个Kafka主题(topic)都分为多个分区(partitions)。每个分区可以具有多个副本(replica),其中一个副本是主分区(leader)。所有读写请求都由主分区提供。其他副本只需要与主分区(leader)保持同步(in-sync),并实时复制所有最近的消息。如果主分区挂了,则一个同步副本(in-sync)将成为新的主分区(leader)。从而是整个集群继续可用。

Kafka的主从副本(每个分区具有多个副本)是Kafka所有可靠性保证的核心。在多个副本中写入消息是,Kafka可以在某个节点发生崩溃时也能保证消息不丢。

什么是同步副本(in-sync)?

除了主分区(leader),满足以下条件的分区副本也是同步副本(in-sync):

  • 与Zookeeper保持会话(session) - 最近6秒钟(可配置)内向Zookeeper发送了心跳
  • 最近10秒钟内(可配置)从主分区获取过所有的最新消息 - 最多比lead少10s的消息

不满足以上条件的分区副本就是不同步的(out-of-sync)。有可能是节点挂掉从启动了,也有可能是网络断了一段时间。当不同步的副本赶上之后,满足了上面的两个条件,就也会成为同步分区(in-sync)。 这是一个动态变化的过程。




kafka 一致性 kafka如何保证一致性_kafka 一致性


如果某个in-sync的分区比较慢,会影响整个集群的相应速度,因为producer需要等所有的in-sync的副本确认提交(commit)消息,才认为成功发送;consumer也只能读到提交(commit)的消息。反而out-of-sync的分区不会影响性能,因为它不参与决策。

服务器端的配置

服务器broker中的三个配置参数可影响Kafka关于可靠消息存储的行为。

  • replication.factor,副本个数,默认是3个;每个topic可以有不同的配置,也可以运行时修改。
  • min.insync.replicas,最少的in-sync的节点数,默认是2。可以在broker和topic级别上配置。
  • unclean.leader.election.enable, 允许out-of-sync的分区成为lead吗?默认是true(不安全)

副本个数 replication.factor的权衡

副本个数越多,自然是越安全,但是也会越慢。因为需要同步的节点多。同时需要的磁盘空间也大。broker的数量要大于副本个数,在一个broker上有多于1个的副本没有意义。

如果对一致性要求很高,比如金融系统,可以设置为5。如果是日志收集或者性能监控消息收集,可以允许丢消息,消息量很大,那么1或者2都可以。

min.insync.replicas 最少的in-sync的节点数

只有所有in-sync的节点都commit了,消息才算提交了(commit)。如果总的replica是3个,min.insync.replicas 是2,那么是允许1个replica挂掉的。这样只要lead还有一个备份。当然你也可以选择全部必须都是in-sync的,那样不允许一个replica挂掉。

unclean.leader.election.enable, 允许out-of-sync的分区成为lead吗?默认是true

如果 min.insync.replicas 小于 replication.factor,就意味着允许有out-of-sync的副本存在。比如默认是3个备份,最小in-sync的节点数是2的情况下,就可能有一个replica是out-of-sync的。这个时候如果lead挂了,那么还有一个in-sync的replica可以当lead,还是安全的。但是如果lead和in-sync的节点都挂了,只剩下一个out-of-sync的节点了,怎么办?

允许这个节点成为主lead节点吗?这个决定很重要,关系到可用性和可靠性还有一致性的选择:

如果允许,那么就有可能丢消息,因为这个节点不包含很多已经提交的(commit)的消息,而哪些已经提交的消息很可能已经被消费过了。比如图中,消费者已经消费到offset 900了,那个out-of-sync的节点才到350。这就是说这个新lead会产生新的从351以后的消息。如果别的消费者去消费,就会消费到和之前的消费者不一样的消息。这样就不一致了。

如果不允许,那就必须停止对外服务。这个cluster挂掉了。得等那两个in-sync的节点恢复好,这可能需要比较长的时间。会影响系统的可用性。

总结

整个系统的一致性和可靠性也不完全是服务器broker端可以决定的。客户端在生产消息和消费消息的时候也可以做出选择,也需要做出一个配合。我们下次继续分享。