kafka-可靠性和一致性

数据可靠性

Producer往Broker发送消息

为了让用户设置数据可靠性,kafka在Producer里面体用了消息确认机制。也就是说我们可以通过配置来决定有几个副本收到这条消息才算Producer发送成功。可以在定义Producer时通过acks参数来指定。这个参数支持以下三种值:

  • acks=0:生产者不会等待任何来自服务器的响应。如果当中出现问题,导致服务器没有收到消息,那么生产者无从得知,会造成消息丢失。由于生产者不需要等待服务器的响应所以可以以网络能够支持的最大速度发生消息,从而达到很高的吞吐量。

  • acks=1(默认值):只要集群的Leader节点收到消息,生产者就会收到一个来自服务器的成功响应。如果消息无法到达Leader节点(例如Leader节点崩溃,新的Leader节点还没有被选举出来)生产者就会收到一个错误的响应,为了避免数据丢失,生产者会重发消息。如果一个没有收到消息的节点成为新Leader,消息还是会丢失。此时的吞吐量主要取决于使用的是同步发送还是异步发送,吞吐量还收到发送消息数量的限制,例如生产者在收到服务器响应之前可以发送多少个消息。

  • acks=-1:只有当所有参与复制的节点全部都收到消息时,生产者才会收到一个来自服务器的响应。这种模式是最安全的,可以保证不止一个服务器收到消息,就算有服务器发生崩溃,整个集群依然可以运行。延时比acks=1更高,因为要等待不止一个服务器节点收到消息。

另外,Producer发送消息还可以选择同步(默认,通过producer.type=sync配置)或者异步(producer.type=async)模式。如果设置成异步,虽然会极大的提高消息发送的性能,但是这样会增加丢失数据的风险。如果要确保消息的可靠性,必须将producer.type设置为sync。

Topic分区副本

可以通过default.replication.factor进行配置默认副本格式,默认为3.

Kafka可以保证单个分区里的事件时有序的,分区可以在线(可用),也可以离线(不可用)。在众多的分区副本里有一个副本是Leader,其余的副本是Follower,所有的读写操作都是经过Leader进行的,同时Follower会定期地去leader上复制数据。当Leader挂掉之后,其中一个Follower会重新成为新的Leader。通过分区副本,引入了数据冗余,同时也提供了Kafka的数据可靠性。

Kafka的分区多副本架构是Kafka可靠性保证的核心,把消息写入多个副本可以使Kafka在发生崩溃时扔能保证消息的持久性。

leader选举

在介绍Leader选举之前,让我们先来了解一下ISR(in-sync replicas)列表。每个分区的leader会维护一个ISR列表,ISR列表里面就是follower副本的Broker编号,只有“跟得上"leader的follower副本才能加如到ISR里面,这个是通过replica.lag.time.max.ms参数配置的。只有ISR里的成员才有被选为leader的可能。

所以当Leader挂掉了,而且unclean.leader.election.enable=false的情况下,Kafka会从ISR列表中选择第一个follower作为新的leader,因为这个分区拥有最新的已经committed的消息,通过这个可以保证已经committed的消息的数据可靠性。

综上所述:为了保证数据的可靠性,我们最少需要配置一下几个参数:

  • producer级别:acks=all(或者request.required.acks=-1),同时发送模式为同步producer.type=sync

  • topic级别:设置replication.factor>=3,并且min.insync.replicas>=2

  • broker级别:关闭不完全的leader选举,即unclean.leader.election.enable=false;

数据一致性

这里介绍的数据一致性主要是说无论是老的Leader还是新选举的Leader,Consumer都能读到一样的户数。那么Kafka是如何实现的呢?

假设有三个分区

副本0(Leader) : Message0,Message1 | Message 2 , Message 3

副本1(Follower) :Message0,Message1 | Message 2

副本2 (Follower):Message0,Message1 |

上面的"|" 表示的是High Water Mark

虽然副本0已经写入了Message3,但是Consumer只能读取到Message1.因为所有的ISR都同步了Mesage1,只有High Water Mark以上是消息才支持Consumer读取,而High Water Mark取决于ISR列表里面偏移量最小的分区,对应于副本2,这个很类似于木桶原理。

这样做的原因是还没有被足够多副本复制的消息被认为是“不安全“的,如果Leader发生崩溃,另一个副本称为新Leader,俺么这小消息很可能丢失了。如果我们允许消费者读取这些消息,可能就会破坏一致性。是想,如果一个消费者从当前Leader(副本0)读取并处理了Message3,这个时候Leader挂掉了,选举了副本1位新的Leader,这时候另一个消费者再去从新的Leader读取消息,发现这个消息其实并不存在,这就导致了数据不一致问题。

当然,引入了HighWaterMark机制,会导致Broker间的消息复制因为某些原因变慢,那么消息到达消费者的时间也会随之变长(因为我们会先等待消息复制完毕)。延迟时间可以通过参数replica.lag.time.max.ms参数配置,它指定了副本在复制消息时可被允许的最大延迟时间。

参考: https://www.cnblogs.com/yoke/p/11477167.html

你可能感兴趣的:(kafka-可靠性和一致性)