apache Kafka Replication设计分析

1.设计目标

提供可配置,需要保障强可用性可以enable这个功能,如果想要更高的效率而不太在乎数据丢失的话,可以disable这个功能
自动replica管理,当cluster发生变化时,即broker server增加或减少时,可以自动的管理和调整replicas

2.问题

  1. 如何将partition的replicas均匀的分配到各个broker servers上面?
  2. 如何进行replicas同步?

2.1 如何均匀的分配partition的replicas呢

例子如下:有15个partitions,5个brokers,做3 replicas
第一个replica怎么放,很简单,15/5,每个broker上依次放3个,如下图,012,345
然后再放其他replica的时候,思路如下:

  • a. 当一个broker down的时候,尽量可以把它的load分散到其他所有的broker上,从而避免造成单个broker的负担过重,所以要考虑k,broker-0上的3个partition,0、1、2的第二个replica没有都放到broker-1,而是分别放到broker-1、2、3上
  • b. 当然一个partition的多个replica也不能放到同一个broker,那样就没有意义了 ,
     

考虑p0的3个replica分别放在broker-0、1、2上,注意这个分配的过程只会在初始化的时候做一次,并且一旦分配好后,会把结果存在zookeeper上,当cluster发生变化时不会重新分配,这样避免当增减broker时做大规模的数据迁移 当增减broker时,只会以最小的数据迁移来部分的replicas(随机选择m/n partitions迁移到Broker上)

这个方法的问题是, 没有考虑到partition和broker server的差异性,简单可用

2.2 replica同步问题

支持同步和异步的方式
异步比较简单,leader存成功,就告诉client存成功,优势是低延迟,缺点是容易丢数据
同步即需要多个replica都存成功才告诉client存成功,缺点就是延迟比较长

在同步中,又需要考虑是否采用quorum-based的设计,或是采用all的设计
quorum-based的设计,活性比较强,延迟小些,问题是,至少要3-replics,并且要保证半数以上的replics是存活的
primary-backup的设计需要写所有的replicas,当然问题就是延迟比较长,而且一个慢节点会拖慢整个操作,好处就是比较简单,2-replicas也可以,只需要有一个replica是存活就ok

Kafka最终选择的是primary-backup方案,比较务实,作为balance
通过各种timeout来部分解决慢节点的问题
并且follower中message写到内存后就向leader发commit,而不等真正写到disk,来优化latency的问题
 

2.3 同步replication

同步方案可以容忍n-1 replica的失败,一个replica被选为leader,而其余的replicas作为followers
leader会维护in-sync replicas (ISR),follower replicas的列表,并且对于每个partition,leader和ISR信息都会存在zookeeper中

有些重要的offset需要解释一下,
log end offset (LEO),表示log中最后的message
high watermark (HW),表示已经被commited的message,HW以下的数据都是各个replicas间同步的,一致的。而以上的数据可能是脏数据,部分replica写成功,但最终失败了
flushed offset,前面说了为了效率message不是立刻被flush到disk的,而是periodically的flush到disk,所以这个offset表示哪些message是在disk上persisted的
这里需要注意的是,flushed offset有可能在HW的前面或后面,这个不一定
 

3. 写请求

client找到leader,写请求
leader写入本地log,然后每个followers通过socket channel获取更新,写入本地log,然后发送ack到leader ,leader发现已经收到所有follower发送的ack,表示message已经被committed,通知client,写成功
leader递增HW,并且定期广播HW到所有的followers,follower会定期去checkpoint HW数据,因为这个很重要,follower必须通过HW来判断那些数据是有效的(committed)
 

4.读请求

从leader读,注意只有HW下的数据会被读到,即只有committed过的数据会被读到

Broker失效场景

毫无疑问,这里需要考虑容错的问题
follower失败,很简单,leader可以直接把这个follower drop掉
当follower comeback的时候,需要truncate掉HW以上的数据,然后和leader同步,完成后,leader会把这个follower加会ISR

leader失败比较复杂一些,在写请求不同的阶段分为3种cases,
真正写数据前,简单,client重发
数据写完后,简单,直接选个新leader,继续
数据写入一半,这个有点麻烦,client会超时重发,如果保证在某些replica上,相同message不被写两次

当leader失败的时候,需要重新选一个leader,ISR里面所有followers都可以申请成为leader
依赖zookeeper的分布式锁,谁先register上,谁就是leader
新的leader会将它的LEO作为新的HW,其他的follower自然需要truncate,追赶leader
 

猜你喜欢

转载自blog.csdn.net/wr_java/article/details/107617135