mirror maker2背景
通常情況下,我們都是使用一套kafka叢集處理業務。但有些情況需要使用另一套kafka叢集來進行資料同步和備份。在kafka早先版本的時候,kafka針對這種場景就有推出一個叫mirror maker的工具(mirror maker1,以下mm1即代表mirror maker1),用來同步兩個kafka叢集的資料。
最開始版本的mirror maker本質上就是一個消費者 + 生產者的程式。但它有諸多諸多不足,包括
- 目標叢集的Topic使用預設配置建立,但通常需要手動repartition。
- acl和配置修改的時候不會自動同步,給多叢集管理帶來一些困難
- 訊息會被
DefaultPartitioner
打散到不同分割槽,即對一個topic ,目標叢集的partition與源叢集的partition不一致。 - 任何配置修改,都會使得叢集變得不穩定。比如比較常見的增加topic到whitelist。
- 無法讓源叢集的producer或consumer直接使用目標叢集的topic。
- 不保證exactly-once,可能出現重複資料到情況
- mm1支援的資料備份模式較簡單,比如無法支援active <-> active互備
- rebalance會導致延遲
因為存在這些問題,mirror maker難以在生產環境中使用。所以kafka2.4版本,推出一個新的mirror maker2(以下mm2即代表mirror maker2)。mirror maker2基於kafka connect工具,解決了上面說的大部分問題。
今天主要介紹mirror maker2的設計,主要功能和部署。
設計和功能
整體設計
mirror maker2是基於kafka connect框架進行開發的,可以簡單地將mirror maker2視作幾個source connector和sink connector的組合。包括:
- MirrorSourceConnector, MirrorSourceTask:用來進行同步資料的connector
- MirrorCheckpointConnector, MirrorCheckpointTask:用來同步輔助資訊的connector,這裡的輔助資訊主要是consumer的offset
- MirrorHeartbeatConnector, MirrorHeartbeatTask:維持心跳的connector
不過雖然mirror maker2歲基於kafka connect框架,但它卻做了一定的改造,可以單獨部署一個mirror maker2叢集,當然也可以部署在kafka connect單機或kafka connect叢集環境上。這部分後面介紹部署的時候再介紹。
和mm1一樣,在最簡單的主從備份場景中,mm2建議部署在目標(target)叢集,即從遠端消費然後本地寫入。如果部署在源叢集端,那麼出錯的時候可能會出現丟資料的情況。
其整體架構如圖:
內部topic設計
mm2會在kafka生成多個內部topic ,來儲存源叢集topic相關的狀態和配置資訊,以及維持心跳。主要有三個內部topic:
- hearbeat topic
- checkpoints topic
- offset sync topic
這幾個內部topic都比較好理解,一看名字基本就知道是幹嘛用的,值得一提的是這其中checkpoints和hearbeat功能都可以通過配置關閉。下面我們詳細介紹下這幾個topic的功能和資料格式。
heartbeat topic
在預設的配置中,源叢集和目標叢集都會有一個用於傳送心跳的topic,consumer 客戶端通過這個 topic,一方面可以確認當前的 connector 是否存活,另一方面確認源叢集是否處於可用狀態。
heartbeat topic的schema如下:
- target cluster:接收心跳叢集
- source cluster:傳送心跳的叢集
- timestamp:時間戳
checkpoints topic
對應的connector(即MirrorCheckpointConnector)會定期向目標叢集傳送checkpoint資訊,主要是consumer group提交的offset ,以及相關輔助資訊。
checkpoints topic 的schema如下:
- consumer group id (String)
- topic (String) :包含源叢集和目標叢集的 topic
- partition (int)
- upstream offset (int): 源叢集指定consumer group已提交的offset(latest committed offset in source cluster)
- downstream offset (int): 目標叢集已同步的offset(latest committed offset translated to target cluster)
- metadata (String):partition後設資料
- timestamp
mm2提供的另一個功能,consumer切換叢集消費就是通過這個topic實現的。因為這個topic中存放了源叢集consumer group的消費offset,在某些場景(比如源叢集故障)下要切換consumer到目標叢集,就可以通過這個topic獲取消費offset然後繼續消費。
offset sync
這個topic ,主要是在兩個叢集間同步topic partition的offset。這裡的offset並不是consumer的offset,而是日誌的offset。
它的 schema 如下:
- topic (String):topic 名
- partition (int)
- upstream offset (int):源叢集的 offset
- downstream offset (int):目標叢集的 offset,和源叢集的應該保持一致
config sync
mm2會將源叢集的資料同步到目標叢集,那麼目標叢集對應的topic的讀寫許可權上怎樣的呢?mm2約定了,目標叢集對應的topic(源叢集備份的那個)只有source和sink connector能夠寫入。為了實施此策略,MM2使用以下規則將 ACL 策略傳播到下游主題:
- 若使用者對源叢集的topic有read的許可權,那麼對目標叢集對應的topic也有read的許可權
- 除了mm2,別的使用者都不能寫入目標叢集對應的topic
同時會同步topic相關配置資訊
acl
consumer切換叢集
源叢集的consumer group offset ,是儲存在目標叢集的checkpoint topic中,這點我們上面已經有說到過。要獲取這些offset資訊,可以使用MirrorClient#remoteConsumerOffsets
這個 api,然後就能用 consumer#seek
api 根據給出的offset消費。
這裡順便提供下大致程式碼,首先maven新增依賴:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>connect-mirror</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>connect-mirror-client</artifactId>
<version>2.4.0</version>
</dependency>
然後獲取offset資訊:
MirrorMakerConfig mmConfig = new MirrorMakerConfig(mm2.getProp());
MirrorClientConfig mmClientConfig = mmConfig.clientConfig("target-cluster");
MirrorClient mmClient = new MirrorClient(mmClientConfig);
Map<TopicPartition, OffsetAndMetadata> offsetMap =
mmClient.remoteConsumerOffsets("my-consumer-group", "source-cluster", Duration.ofMinutes(1));
consumer#seek
的用法就不演示了。
其他功能
最後順便介紹下其他比較基礎的功能。
源叢集和目標叢集partition保持同步
- 訊息的分割槽和排序,源叢集和目標叢集都會保持一樣
- 目標叢集的分割槽數與源叢集分割槽保持一樣
- 目標叢集只會有一個topic與源叢集topic對應
- 目標叢集只會有一個分割槽與源叢集的分割槽對應
- 目標叢集的partition i對應源叢集partition i
說白了就是源叢集和目標叢集的partition和訊息會盡量保持一致,當然可能會有重複訊息的情況,因為目前還不指定exactly-once,據說後續版本會有(2.4版本以後)。
同步topic增加字首
mm1有一個缺陷,因為mm1備份資料的時候,源叢集和目標叢集的topic名稱都是一樣的,所以可能出現兩個叢集的訊息無限遞迴的情況(就是兩個名稱相同的topic,一條訊息a傳b,b再傳a,迴圈往復)。mm2解決這個缺陷,採用了給topic加一個字首的方式,如果是兩個叢集相互備份,那麼有字首的topic的訊息,是不會備份的。
同步配置和acl
mm1的時候,配置資訊和topic acl相關的資訊是不會同步的,這會給叢集管理帶來一定的困難,mm2解決了這個問題,即源叢集的配置和acl都會自動同步到目標叢集中。
說完功能,最後再介紹下部署方式。
部署方式
目前主要支援三種部署方式
- mm2專用叢集部署:無需依賴kafka connect,mm2已經提供了一個driver可以單獨部署mm2叢集,僅需一條命令就可以啟動:./bin/connect-mirror-maker.sh mm2.properties
- 依賴kafka connect叢集部署:需要先啟動kafka connect叢集模式,然後手動啟動每個mm2相關的connector,相對比較繁瑣。適合已經有kafka connect叢集的場景。
- 依賴kafka connect單機部署:需要在配置檔案中配置好各個connector,然後啟動Kafka connect單機服務。不過這種方式便捷性不如mm2專用叢集模式,穩定性不如kafka connect 叢集模式,適合測試環境下部署。
mm2 相關的配置參照KIP-382,主要配置包括 source 和 target 的 broker 配置,hearbeat ,checkpoint 功能是否啟用,同步時間間隔等。
mm2獨立叢集部署
要部署mm2叢集相對比較簡單,只需要先在config/mm2.properties寫個配置檔案:
# 指定兩個叢集,以及對應的host
clusters = us-west, us-east
us-west.bootstrap.servers = host1:9092
us-east.bootstrap.servers = host2:9092
# 指定同步備份的topic & consumer group,支援正則
topics = .*
groups = .*
emit.checkpoints.interval.seconds = 10
# 指定複製鏈條,可以是雙向的
us-west->us-east.enabled = true
# us-east->us-west.enabled = true # 雙向,符合條件的兩個叢集的topic會相互備份
# 可以自定義一些配置
us-west.offset.storage.topic = mm2-offsets
# 也可以指定是否啟用哪個鏈條的hearbeat,預設是雙向hearbeat的
us-west->us-east.emit.heartbeats.enabled = false
然後使用一條命令就可以啟動了,./bin/connect-mirror-maker.sh mm2.properties
。啟動後用jps觀察程式,再list下topic,可以發現多了許多個topic,這種時候應該就啟動成功了。
順便說下,如果是使用kafka connect叢集,那需要手動啟動每個connector,類似這樣:
PUT /connectors/us-west-source/config HTTP/1.1
{
"name": "us-west-source",
"connector.class": "org.apache.kafka.connect.mirror.MirrorSourceConnector",
"source.cluster.alias": "us-west",
"target.cluster.alias": "us-east",
"source.cluster.bootstrap.servers": "us-west-host1:9091",
"topics": ".*"
}
以上~