實時採集MySQL資料之輕量工具Maxwell實操

itxiaoshen發表於2022-12-19

@

概述

定義

Maxwell 官網地址 https://maxwells-daemon.io/

Maxwell GitHub原始碼地址 https://github.com/zendesk/maxwell

Maxwell 是由美國 Zendesk 開源,採用 Java 語言開發的 MySQL 實時抓取工具,透過實時讀取MySQL binlog二進位制日誌並作為生產者生產 JSON 格式訊息傳送給 Kafka、Kinesis、RabbitMQ、Redis或其他流媒體平臺的應用程式。最新版本為1.39.4

Maxwell的操作開銷很低,只需要mysql和資料同步目的地,常用場景包括ETL、快取構建/過期、指標收集、搜尋索引和服務間通訊。

原理

Maxwell 的工作原理很簡單,就是把自己偽裝成 MySQL 的一個 slave,然後以 slave的身份從 MySQL master伺服器複製資料,需要MySQL的binlog資料格式設定為row模式。

Binlog說明

MySQL開啟binlog大概會有 1%的效能損耗,主要用於主從複製和資料恢復。二進位制日誌包括兩類檔案

  • 二進位制日誌索引檔案(檔名字尾為.index):用於記錄所有 的二進位制檔案
  • 二進位制日誌檔案(檔名字尾為.00000*):記錄資料庫所有的 DDL 和 DML(除了資料查詢語句)語句事件。

MySQL 生成的 binlog 檔案初始大小一定是 154 位元組,然後字首是 log-bin 引數配置的,字尾是預設從.000001,然後依次遞增(包括每次重啟mysql也會遞增)。除了 binlog 檔案檔案以外,MySQL 還會額外生產一個.index 索引檔案用來記錄當前使用的 binlog 檔案。

Maxwell和Canal的區別

Maxwell最初的設計思想是MySQL+Kafka,用於對MySQL資料採集個人比較推薦Maxwell,當然還有我們前面學過的FlinkCDC。

  • 服務端+客戶端一體,輕量級
  • 支援斷點還原功能+bootstrap+json,全量同步
  • maxwell社群比canal社群活躍

image-20221219231229027

部署

安裝

# 下載最新版本1.39.4的maxwell,注意從github的release歷史中可知maxwell從v1.30.0開始就已經不再支援JDK8,支援JDK11
wget https://github.com/zendesk/maxwell/releases/download/v1.39.4/maxwell-1.39.4.tar.gz
# 解壓檔案
tar -xvf maxwell-1.39.4.tar.gz
# 進入主目錄
cd maxwell-1.39.4

MySQL準備

修改mysql的配置檔案,開啟mysql的binlog設定,vim /etc/my.cnf

# mysql server的id,如果有多臺id需要唯一
server_id=1
# 設定生成的二進位制檔案的字首
log-bin=mysql-bin
# 設定binlog的二進位制檔案的日誌級別 行級模式
binlog_format=row
# binlog的執行的庫 如果不加這個引數那麼mysql會對所有的庫都生成對應的binlog 即對所有的庫盡心binlog監控
# 設定只監控某個或某些資料庫
binlog-do-db=my_maxwell_01
binlog-do-db=my_maxwell_02
# 修改後重啟MySQL的服務
service mysqld restart

初始化Maxwell後設資料庫

在 MySQL 中建立一個 maxwell 庫用於儲存 Maxwell 的後設資料

# 建立資料庫,在我們使用的時候它會自己建立對應的表,這裡我們只需建庫不需要創表
CREATE DATABASE maxwell;
# 建立使用者任意遠端訪問
CREATE USER 'maxwell'@'%';
# 修改密碼
ALTER USER 'maxwell'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
#給使用者授權
GRANT SELECT ,REPLICATION SLAVE , REPLICATION CLIENT ON *.* TO maxwell@'%';
GRANT ALL PRIVILEGES ON maxwell.* TO "maxwell"@"%";
#重新整理許可權
FLUSH PRIVILEGES;

Maxwell程式啟動

命令列引數

# 啟動maxwell
bin/maxwell --user='maxwell' --password='123456' --host='hadoop3' --port=3308 --producer=stdout

詳細引數配置可以查閱官網

image-20221219145234235

# 在mysql中建立前面在MySQL的配置檔案中binlog資料庫
CREATE DATABASE my_maxwell_01;
# 資料表,賬號表
use my_maxwell_01;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(4) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 插入資料
INSERT INTO account(name,age) VALUES('張三三',20),('李思',23),('王樂',26);

從日誌可以看出建立資料庫、資料表和資料插入捕獲的binlog由maxwell轉換為json的日誌,向 mysql 的my_maxwell_01庫的account表同時插入 3 條資料,控制檯出現了 3 條 json日誌,說明 maxwell 是以資料行為單位進行日誌的採集的。

image-20221219150217790

透過啟動maxwell後我們也可以maxwell後設資料庫的內容,包含核心幾張表資料。

image-20221219163646478

配置檔案

# 複製maxwell根目錄下config.properties.example
cp config.properties.example config.properties
# 修改config.properties配置檔案

log_level=info
producer=stdout
# mysql login info
host=hadoop3
port=3308
user=maxwell
password=123456

image-20221219151059520

# 透過指定配置檔案啟動maxwell
bin/maxwell --config ./config.properties
# 再次插入資料測試
INSERT INTO account(name,age) VALUES('吳三',25);
# 也可以透過jps檢視maxwell程式com.zendesk.maxwell.Maxwell
jps -l

image-20221219151742515

接下里看下修改資料和刪除資料json資料內容,後續主要就是針對json內容做處理

UPDATE account SET age = 28 WHERE id =4;
UPDATE account SET age = 30 WHERE name ='吳三';
DELETE FROM account WHERE id =4;

image-20221219152520787

json內容分別如下,主要是type型別區分,更新包含old資料的值,ts為秒級時間戳。

# 新增
{
    "database": "my_maxwell_01", 
    "table": "account", 
    "type": "insert", 
    "ts": 1671434231, 
    "xid": 5097, 
    "commit": true, 
    "data": {
        "id": 4, 
        "name": "吳三", 
        "age": 25
    }
}
# 更新
{
    "database": "my_maxwell_01", 
    "table": "account", 
    "type": "update", 
    "ts": 1671434616, 
    "xid": 6302, 
    "commit": true, 
    "data": {
        "id": 4, 
        "name": "吳三", 
        "age": 28
    }, 
    "old": {
        "age": 25
    }
}
# 刪除
{
    "database": "my_maxwell_01", 
    "table": "account", 
    "type": "delete", 
    "ts": 1671434700, 
    "xid": 6584, 
    "commit": true, 
    "data": {
        "id": 4, 
        "name": "吳三", 
        "age": 30
    }
}

實時監控Mysql輸出Kafka

# 啟動 Maxwell 監控 binlog
bin/maxwell --user='maxwell' --password='123456' --host='hadoop3' --producer=kafka --kafka.bootstrap.servers=kafka1:9092 --kafka_topic=test_topic_1

一旦mysql表有了資料的更新麼mysql底層的binlog檔案肯定會有變化,binlog變化了則maxwell程式就能捕捉到這個變化,將之解析並轉換為json資料寫入到kafka裡面。使用kafka的圖形化工具kafka tool檢視資料,點選test_topic_1檢視,不更新資料這裡的topic是不會被建立的,插入資料後test_topic_1就有相關的訊息資料了

# 繼續插入資料
INSERT INTO account(name,age) VALUES('劉說',27);

image-20221219155314573

# 官方的命令列消費指令碼也可以消費到資料
kafka-console-consumer.sh --bootstrap-server kafka1:9092 --topic test_topic_1

透過 kafka 消費者來檢視到了資料,說明資料成功傳入 kafka

image-20221219155127513

Kafka Topic分割槽控制

上面的示例往kafka寫入的訊息都是是發往一個分割槽,在實際生產環境中一般都會用 maxwell 監控多個 mysql 庫的資料,然後將這些資料發往 kafka 的一個主題 Topic,提高併發度主題肯定是多分割槽的。先建立一個名稱test_topic_2,分割槽為3副本為2的topic。

image-20221219160131248

這次使用配置檔案方式,修改config.properties

# 配置生產者是kafka
producer=kafka
# kafka的server
kafka.bootstrap.servers=kafka1:9092
# 指定topoic
kafka_topic=test_topic_2
#按什麼分割槽 [database, table, primary_key, transaction_id, thread_id, column]
producer_partition_by=database

image-20221219161020889

使用配置檔案的方式啟動maxwell程式

bin/maxwell --config ./config.properties
# 在mysql中建立前面在MySQL的配置檔案中binlog資料庫
CREATE DATABASE my_maxwell_02;
# 資料表,賬號表
use my_maxwell_02;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(4) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 分別往兩個資料庫的account表插入一條資料
INSERT INTO my_maxwell_01.account(name,age) VALUE('李丹',30);
INSERT INTO my_maxwell_02.account(name,age) VALUE('李丹',30);

再來看看topic,在test_topic_2中兩條資料分割槽分別為0和1,驗證不同資料庫的資料會發往不同的分割槽。

image-20221219161527606

實時監控MySQL指定表

主要是透過--filter引數設定exclude排除,include是包含來實現

# 啟動maxwell
bin/maxwell --user='maxwell' --password='123456' --host='hadoop3' --filter 'exclude: *.*, include:my_maxwell_01.product' --port=3308 --producer=stdout

建立新的資料表,分別往兩張表插入資料

use my_maxwell_02;
CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `type` int(4) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO my_maxwell_01.account(NAME,age) VALUE('李丹',30);
INSERT INTO my_maxwell_01.product(NAME,TYPE) VALUE('iphone13',1);

image-20221219162849650

可以看到只有product表捕獲變更資料,此外還可以設定 include:my_maxwell_01.*,透過此種方式來監控 mysql 某個庫的所有表,也就是說過濾整個庫。

監控MySQL指定表同步全量資料

監控MySQL指定表同步全量資料常用於資料初始化操作,Maxwell 程式預設只能監控 mysql 的 binlog 日誌的新增及變化的資料,但是Maxwell 是支援資料初始化的,可以透過修改 Maxwell 的後設資料,來對 MySQL 的某張表進行資料初始化,也就是我們常說的全量同步。接下來演示將 my_maxwell_01庫下的 account表的5條資料全量匯入輸出到 maxwell 控制檯。

前面我們建立過maxwel的後設資料庫,這裡需求修改 Maxwell 的後設資料以觸發資料初始化機制,在 mysql 的 maxwell 庫中 bootstrap表中插入一條資料,寫明需要全量資料的庫名和表名

insert into maxwell.bootstrap(database_name,table_name) values('my_maxwell_01','account');

image-20221219164054827

# 啟動 maxwell 程式,此時初始化程式會直接列印account表的所有資料
bin/maxwell --user='maxwell' --password='123456' --host='hadoop3' --port=3308 --producer=stdout

image-20221219164159981

當資料全部初始化完成以後,Maxwell 的後設資料會變化,is_complete 欄位從 0 變為 1,start_at 欄位從 null 變為具體時間(資料同步開始時間),complete_at 欄位從 null 變為具體時間(資料同步結束時間),在Maxwell 執行過程中繼續往maxwell.bootstrap插入資料也會觸發處理。

image-20221219164244308

本人部落格網站IT小神 www.itxiaoshen.com

相關文章