前言
本文將使用Kafka Connect 實現MySQL增量同步,設計三種模式,分別為incrementing
timestamp
timestamp+incrementing
理論續自上文
當然你也可以使用除了MySQL其他DB,參考官網放置對應的驅動文件即可。
以下實驗請在能正常Kafka生產消費的基礎之上進行。
1、incrementing 自增模式
準備工作
創建 A數據庫源表person
CREATE TABLE `person` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
創建 B數據庫目標表kafkaperson
CREATE TABLE `kafkaperson` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
切換目錄 D:\com\kafka_2.11-2.0.1\config
quickstart-mysql.properties(source)
name=mysql-a-source-person
connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
tasks.max=1
connection.url=jdbc:mysql://localhost:3306/A?user=***&password=***
# incrementing 自增
mode=incrementing
# 自增字段 pid
incrementing.column.name=pid
# 白名單表 person
table.whitelist=person
# topic前綴 mysql-kafka-
topic.prefix=mysql-kafka-
quickstart-mysql-sink.properties(sink)
name=mysql-a-sink-person
connector.class=io.confluent.connect.jdbc.JdbcSinkConnector
tasks.max=1
#kafka的topic名稱
topics=mysql-kafka-person
# 配置JDBC鏈接
connection.url=jdbc:mysql://localhost:3306/B?user=***&password=***
# 不自動創建表,如果為true,會自動創建表,表名為topic名稱
auto.create=false
# upsert model更新和插入
insert.mode=upsert
# 下面兩個參數配置了以pid為主鍵更新
pk.mode = record_value
pk.fields = pid
#表名為kafkatable
table.name.format=kafkaperson
實驗一
創建 Kafka Topic: mysql-kafka-person
D:\com\kafka_2.11-2.0.1\bin\windows>kafka-run-class.bat kafka.admin.TopicCommand --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic mysql-kafka-person
啟動 Kafka Connect
D:\com\kafka_2.11-2.0.1\bin\windows>connect-standalone.bat D:/com/kafka_2.11-2.0.1/config/connect-standalone.properties D:/com/kafka_2.11-2.0.1/config/quickstart-mysql.properties D:/com/kafka_2.11-2.0.1/config/quickstart-mysql-sink.properties
A庫person表插入三條數據
稍后發現B庫kafkaperson表中進入了這三條數據
consumer控制臺 觀察到三條數據
此時插入1條新數據
INSERT INTO person(pid, firstname, age) VALUES(4, 'zl', 20);
發現B庫表中也多了一條pid為4的數據
實驗一結論
在 JDBC Sink Connector 官網中指出insert.mode
有且僅有兩個值
insert.mode=insert
只接收標準的INSERT SQL新增語句
insert.mode=upsert
接收新增和更新,當對主鍵修改時也可以洞察并且輸出。而insert
是無法滿足此要求的,因此根據實際業務使用的場景選擇insert.mode
。
INSERT INTO person (pid, firstname, age) VALUES (2, 'ls', 15) ON DUPLICATE KEY UPDATE firstname="world";
然而我在實驗過程中并沒有成功,因此沒看出來insert和upsert的區別,希望成功的人可以在留言中指正下!
2、timestamp 時間戳模式
準備工作
創建 A數據庫源表comments
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT NULL,
`commenttime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
注意timestamp必須指定not null,否則會報錯!(無法使用時間戳列進行增量查詢因為時間戳字段是可為空的...)
創建 B數據庫源表kafkacomments
CREATE TABLE `kafkacomments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT NULL,
`commenttime` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
切換目錄 D:\com\kafka_2.11-2.0.1\config
timestamp-mysql-source.properties(source)
name=mysql-b-source-comments
connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
tasks.max=1
connection.url=jdbc:mysql://localhost:3306/A?user=***&password=***
table.whitelist=comments
mode=timestamp
timestamp.column.name=commenttime
topic.prefix=mysql-kafka-
timestamp-mysql-sink.properties(sink)
name=mysql-b-sink-comments
connector.class=io.confluent.connect.jdbc.JdbcSinkConnector
tasks.max=1
#kafka的topic名稱
topics=mysql-kafka-comments
# 配置JDBC鏈接
connection.url=jdbc:mysql://localhost:3306/B?user=***&password=***
# 不自動創建表,如果為true,會自動創建表,表名為topic名稱
auto.create=false
# upsert model更新和插入
insert.mode=upsert
# 下面兩個參數配置了以id為主鍵更新
pk.mode = record_value
pk.fields = id
#表名為kafkatable
table.name.format=kafkacomments
實驗二
創建 Kafka Topic: mysql-kafka-comments
D:\com\kafka_2.11-2.0.1\bin\windows>kafka-run-class.bat kafka.admin.TopicCommand --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic mysql-kafka-comments
啟動 Kafka Connect
D:\com\kafka_2.11-2.0.1\bin\windows>connect-standalone.bat D:/com/kafka_2.11-2.0.1/config/connect-standalone.properties D:/com/kafka_2.11-2.0.1/config/timestamp-mysql-source.properties D:/com/kafka_2.11-2.0.1/config/timestamp-mysql-sink.properties
A庫comments表插入四條數據
此時發現控制臺和目標表中有了四條數據
此時修改id為2和4的內容content
,并修改評論時間commenttime
update comments set content = "show test data" ,commenttime="2018-12-20 15:55:10" where id in(2,4)
發現源表和目標表中的內容都發生了變化!
注意:
1、如果修改的時間戳早于latest time
,則不會洞察到更新。例如MySQL中的now()
獲取當前時間就是很好的能被獲取到的例子。
2、源表向目標表傳輸數據,假設有兩條(或以上)的數據行擁有同樣的時間戳,如果在傳輸第二條的過程中崩潰,恢復過后第二條將會被丟失,因為latest time
已經被記錄過了,他只會去找更新的下一次時間。這種方式雖然能獲取到update
更新,但是不夠穩健。而如果使用自增字段加時間戳字段混合的方式,即使崩潰也能記錄到更新的最大ID
,恢復之后可以被找到不會丟失。因此我們更推薦第三種方式!timestamp+incrementing
3、timestamp+incrementing 時間戳自增混合模式
實驗過程同方法2不做贅述,唯一變動的是source的config文件
name=mysql-b-source-comments
connector.class=io.confluent.connect.jdbc.JdbcSourceConnector
tasks.max=1
connection.url=jdbc:mysql://localhost:3306/A?user=***&password=***
table.whitelist=comments
mode=timestamp+incrementing
timestamp.column.name=commenttime
incrementing.column.name=id
topic.prefix=mysql-kafka-