Kafka Connect 實時讀取MSSQL數據到Kafka

在處理實時數據時,需要即時地獲得數據庫表中數據的變化,然後將數據變化發送到Kafka中。這篇文章將介紹如何使用Kafka Connector完成這一工作。當獲取實時數據時,數據源需要支持對數據變化進行反饋。不同的數據源採用了不同的技術和方法實現該功能,因爲我們的業務數據庫是MS SQL Server,因此這篇文章採用MSQL作爲數據源。

1. 選擇Connector

首先需要選擇Connector,不同的數據源有不同的Connector,例如ActiveMQ Connector、MySql Connector、MSSQL Connector等。即便是同一數據源,也可能有不同的第三方提供。我一共嘗試了下面兩個MSSQL Connector:

比較遺憾的是:這兩個Connector,debezium的是Alpha版本,confluent的是Preview版本,反正都不是正式版,而MySql都已經有正式版本了,可見開源社區對MS真的不友好呀 >_<、 它們兩個一個是使用MSSQL Server的 Change Data Capture 獲取數據變更,一個是使用 Change Tracking

因爲Change Tracking相比Change Data Capture來說,更輕量一些,因此我選用了confluent的Connector。其下載地址是:<https://www.confluent.io/hub/&gt;

2. 安裝Connector

下載後,將其解壓縮至 $KAFKA_HOME/connectors 文件夾下,如下圖所示:

說明:$KAFKA_HOME是你的kafka安裝目錄,如果是集羣,要安裝在集羣下每臺機器的connectors目錄下。

Kafka Connect 實時讀取MSSQL數據到Kafka

在上面的截圖中,可以看到我還安裝了confluentinc-kafka-connect-hdfs-5.0.0和debezium-connector-sqlserver兩個connector。

3. 配置Connector

接下來要對Connector進行配置,此時可以回顧一下 Kafka Connect 基本概念。Connector是一組獨立的集羣,並且是作爲Kafka集羣的客戶端,我們首先需要對Connector進行配置,配置文件位於 $KAFKA_HOME/config/connect-distributed.properties:

# kafka集羣地址
bootstrap.servers=kafka1:9092,kafka2:9092,kafka3:9092

# Connector集羣的名稱,同一集羣內的Connector需要保持此group.id一致
group.id=connect-cluster

# 存儲到kafka的數據格式
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter
key.converter.schemas.enable=false
value.converter.schemas.enable=false

# 內部轉換器的格式,針對offsets、config和status,一般不需要修改
internal.key.converter=org.apache.kafka.connect.json.JsonConverter
internal.value.converter=org.apache.kafka.connect.json.JsonConverter
internal.key.converter.schemas.enable=false
internal.value.converter.schemas.enable=false

# 用於保存offsets的topic,應該有多個partitions,並且擁有副本(replication)
# Kafka Connect會自動創建這個topic,但是你可以根據需要自行創建
# 如果kafka單機運行,replication.factor設置爲1;當kafka爲集羣時,可以設置不大於集羣中主機數
# 因爲我這裏的環境是3主機的集羣,因此設爲2
offset.storage.topic=connect-offsets
offset.storage.replication.factor=2
offset.storage.partitions=12

# 保存connector和task的配置,應該只有1個partition,並且有多個副本
config.storage.topic=connect-configs
config.storage.replication.factor=2

# 用於保存狀態,可以擁有多個partition和replication
status.storage.topic=connect-status
status.storage.replication.factor=2
status.storage.partitions=6

# Flush much faster than normal, which is useful for testing/debugging
offset.flush.interval.ms=10000

# RESET主機名,默認爲本機
#rest.host.name=
# REST端口號
rest.port=18083

# The Hostname & Port that will be given out to other workers to connect to i.e. URLs that are routable from other servers.
#rest.advertised.host.name=
#rest.advertised.port=

# 保存connectors的路徑
# plugin.path=/usr/local/share/java,/usr/local/share/kafka/plugins,/opt/connectors,
plugin.path=/opt/kafka/kafka_2.11-1.1.0/connectors注意到connect-distributed.properties中的distributed。Kafka Connector有兩種運行模式,單機(Standalone)和分佈式(Distrubited)。因爲單機通常作爲測試運行,因此這篇文章只演示分佈式運行模式。在config文件夾下,還有一個單機運行的配置文件,叫做connect-standalone.properties,內容大同小異。

4. 創建Topic

儘管首次運行Kafka connector時,會自動創建上面的topic,但是如果創建出錯,那麼Connector就會啓動失敗。保險起見,可以在運行Connector之前,手動創建好上面的三個特殊topic。

# bin/kafka-topics.sh --zookeeper zookeeper1:2181/kafka --create --topic connect-offsets --replication-factor 2 --partitions 12

# bin/kafka-topics.sh --zookeeper zookeeper1:2181/kafka --create --topic connect-configs --replication-factor 2 --partitions 1

# bin/kafka-topics.sh --zookeeper zookeeper1:2181/kafka --create --topic connect-status --replication-factor 2 --partitions 6

5. 運行Connector

接下來就可以運行Connctor了,此時還沒有涉及到任何業務或者數據庫相關的配置和操作(即 Kafka Connect 基本概念 中提到的用戶配置)。

執行下面的代碼以運行Connector:

# bin/connect-distributed.sh config/connect-distributed.properties

上面這樣是前臺運行,當退出shell後進程也就結束了,前臺運行的好處就是在開始運行時便於調試。如果想要後臺運行,則需加上-daemon選項:

# bin/connect-distributed.sh -daemon config/connect-distributed.properties

運行connect時,會看到不停地涌現大量INFO信息,此時可以修改一下connect-log4j.properties,只顯示WARN信息。

# vim config/connect-log4j.properties
log4j.rootLogger=WARN, stdout

6. 開啓MSSQL數據庫的Change Tracking

在繼續進行之前,我們在數據庫中創建表test_online,並且開啓Change Tracking功能:

Go
CREATE TABLE [dbo].[test_online](
  [Id] [int] IDENTITY(1,1) NOT NULL,
  [UserName] [varchar](50) NOT NULL,
  [IsOnline] [bit] NOT NULL,
  [LastLogin] [int] NOT NULL,
 CONSTRAINT [PK_test_online] PRIMARY KEY CLUSTERED 
(
  [Id] ASC
)

Go
ALTER DATABASE db_name  
SET CHANGE_TRACKING = ON  
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)  

Go
ALTER TABLE [db_name].dbo.[test_online]  
ENABLE CHANGE_TRACKING  
WITH (TRACK_COLUMNS_UPDATED = ON)  

7. Kafka Connector REST API

當Kafka Connector運行起來以後,它就開啓了REST API端口,像我們上面配置的是:18083。如果我們需要運行Task,比如實時捕捉數據庫數據變化並寫入Kafka,那麼就需要像這個REST API提交用戶配置(User Config)。在提交用戶配置之前,我們先看看Kafka Connector REST API都包含哪些常見功能:

7.1 獲取Worker的信息

因爲我的kafka(主機名分別爲kafka1、kafka2、kafka3)和kafka connector集羣是共用主機的,因此可以使用下面的命令獲取(你需要將下面的kafka1改成ip或者相應的主機名):

# curl -s kafka1:18083/ | jq
{
  "version": "1.1.0",
  "commit": "fdcf75ea326b8e07",
  "kafka_cluster_id": "N93UISCxTS-SYZPfM8p1sQ"
}

7.2 獲取Worker上已經安裝的Connector

此時的Connector是靜態概念,即上面第一節安裝的Confluent MSSQL Connector,從下面的顯示可以看到,我安裝了好幾個Connector:

# curl -s kafka1:18083/connector-plugins | jq
[
  {
    "class": "io.confluent.connect.cdc.mssql.MsSqlSourceConnector",
    "type": "source",
    "version": "0.0.1.9"
  },
  {
    "class": "io.confluent.connect.hdfs.HdfsSinkConnector",
    "type": "sink",
    "version": "5.0.0"
  },
  {
    "class": "io.confluent.connect.hdfs.tools.SchemaSourceConnector",
    "type": "source",
    "version": "1.1.0"
  },
  {
    "class": "io.confluent.connect.storage.tools.SchemaSourceConnector",
    "type": "source",
    "version": "1.1.0"
  },
  {
    "class": "io.debezium.connector.sqlserver.SqlServerConnector",
    "type": "source",
    "version": "0.9.0.Alpha1"
  },
  {
    "class": "org.apache.kafka.connect.file.FileStreamSinkConnector",
    "type": "sink",
    "version": "1.1.0"
  },
  {
    "class": "org.apache.kafka.connect.file.FileStreamSourceConnector",
    "type": "source",
    "version": "1.1.0"
  }
]

對於你來說,可能就只有io.confluent.connect.cdc.mssql.MsSqlSourceConnector這一個connector。

7.3 列出當前運行的connector(task)

# curl -s kafka1:18083/connectors | jq
[]

因爲我們當前Connector中沒有提交過任何的用戶配置(即沒有啓動Task),因此上面返回空數組。

7.4 提交Connector用戶配置

當提交用戶配置時,就會啓動一個Connector Task,Connector Task執行實際的作業。用戶配置是一個Json文件,同樣通過REST API提交:

# curl -s -X POST -H "Content-Type: application/json" --data '{
    "name": "connector-mssql-online",
    "config": {
        "connector.class": "io.confluent.connect.cdc.mssql.MsSqlSourceConnector",
        "tasks.max": 1,
        "server.name": "192.168.0.21",
        "server.port" : "1433",
        "username": "user_id",
        "password": "your_password",
        "initial.database": "db_name",
        "change.tracking.tables": "dbo.test_online"
    }
}' http://kafka1:18083/connectors | jq

注意上面的配置要修改成你的本地配置。提交完成後,再次執行上一小節的命令,會看到已經有一個connector在運行了,其名稱爲connector-mssql-online:

curl -s kafka1:18083/connectors | jq
[
  "connector-mssql-online"
]

7.5 查看connector的信息

# curl -s kafka1:18083/connectors/connector-mssql-online | jq
{
  "name": "connector-mssql-online",
  "config": {
    "connector.class": "io.confluent.connect.cdc.mssql.MsSqlSourceConnector",
    "password": "your_password",
    "initial.database": "db_name",
    "server.name": "192.168.0.21",
    "tasks.max": "1",
    "server.port": "1433",
    "name": "connector-mssql-online",
    "change.tracking.tables": "dbo.test_online",
    "username": "user_id"
  },
  "tasks": [
    {
      "connector": "connector-mssql-online",
      "task": 0
    }
  ],
  "type": "source"
}

注意:上面task:0,不是說有0個task,是task的id是0。

7.6 查看connector下運行的task信息

使用下面的命令,可以查看connector下運行的task的信息:

# curl -s kafka1:18083/connectors/connector-mssql-online/tasks | jq
[
  {
    "id": {
      "connector": "connector-mssql-online",
      "task": 0
    },
    "config": {
      "connector.class": "io.confluent.connect.cdc.mssql.MsSqlSourceConnector",
      "password": "your_password",
      "initial.database": "db_name",
      "task.class": "io.confluent.connect.cdc.mssql.MsSqlSourceTask",
      "server.name": "192.168.0.21",
      "tasks.max": "1",
      "server.port": "1433",
      "name": "connector-mssql-online",
      "change.tracking.tables": "dbo.test_online",
      "username": "user_id"
    }
  }
]

這裏task的配置信息繼承自connector的配置。

7.7 查看connector當前狀態

# curl -s kafka1:18083/connectors/connector-mssql-online/status | jq
{
  "name": "connector-mssql-online",
  "connector": {
    "state": "RUNNING",
    "worker_id": "192.168.0.31:18083"
  },
  "tasks": [
    {
      "state": "RUNNING",
      "id": 0,
      "worker_id": "192.168.0.31:18083"
    }
  ],
  "type": "source"
}

7.8 暫停/重啓 Connector

# curl -s -X PUT kafka1:18083/connectors/connector-mssql-online/pause
# curl -s -X PUT kafka1:18083/connectors/connector-mssql-online/resume

7.9 刪除 Connector

# curl -s -X DELETE kafka1:18083/connectors/connector-mssql-online

8. 從Kafka中讀取變動數據

默認情況下,MSSQL Connector會將表的變動寫入到:${databaseName}.${tableName} 這個topic中,這個topic的名稱可以通過 topic.format 這個用戶配置參數中進行設置,因爲我們並沒有配置,因此,topic的名稱爲db_name.test_online。

運行下面的控制檯腳本,從Kafka中實時讀取topic的內容:

# bin/kafka-console-consumer.sh --bootstrap-server kafka1:9092 --topic db_name.test_online --from-beginning

此時因爲沒有任何數據,因此控制檯會阻塞。

9. 對test_online表進行修改

依次執行下面的增刪改語句,對test_online表進行修改:

insert into [test_online](UserName,IsOnline,LastLogin)
values('子陽', 1, DATEDIFF(s, '19700101',GETDATE()))

update test_online Set UserName='吉米' where UserName='子陽'
Delete test_online Where UserName='吉米'

現在查看Kafka讀取端控制檯,可以看到以Json格式實時收到了數據庫變動的消息:

# bin/kafka-console-consumer.sh --bootstrap-server kafka1:9092 --topic tgstat_ddztest.test_online
{"Id":5,"UserName":"子陽","IsOnline":true,"LastLogin":1540635666,"_cdc_metadata":{"sys_change_operation":"I","sys_change_creation_version":"13","sys_change_version":"13","databaseName":"tgstat_ddztest","schemaName":"dbo","tableName":"test_online"}}
{"Id":5,"UserName":"吉米","IsOnline":true,"LastLogin":1540635666,"_cdc_metadata":{"sys_change_operation":"U","sys_change_creation_version":"0","sys_change_version":"14","databaseName":"tgstat_ddztest","schemaName":"dbo","tableName":"test_online"}}
null

從上面的消息可以看到,對於delete操作,收到了null。對於insert和update操作,收到了詳細的變動信息。

至此,我們就配置完了Kafka Connector,並且實時獲取到了數據庫變更的消息。後續可以使用Spark Stream連接至此Topic,進行實時的數據運算和分析。以後有機會再進行掩飾。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章