logstash實現mysql數據庫表實時同步

logstash可以將不同數據源,例如日誌、文件、或jdbc等,同步到ElasticSearch中,本文利用logstash實現mysql數據庫表之間的數據。(實例:數據庫DB1中的表A有添加或者修改,數據庫DB2中的表B也會自動同步)

一、準備:

數據源輸入使用logstash中自帶的logstash-input-jdbc,無需額外安裝,官網使用說明地址
數據源輸出需要使用logstash-output-jdbc,但是在loastash官網中output plugins列表中並沒有相關插件,需要額外安裝,使用說明在Github地址

安裝logstash

將logstash下載後,放到/opt/elastic/目錄下,並將logstash目錄重命名爲logstash-test

安裝logstash-output-jdbc,在/opt/elastic/logstash-test目錄下執行:

	bin/logstash-plugin install logstash-output-jdbc

安裝成功:在這裏插入圖片描述

二、數據庫表

在數據庫DB1中創建表A,並添加數據如下:
在這裏插入圖片描述
在數據庫DB2中創建表B,表結構與A一致,暫不添加數據:
在這裏插入圖片描述

三、logstash配置文件

logstash配置文件中必須包含兩個元素inputoutput,分別是數據來源的配置和數據輸出的配置。還有一個可選項filter,用來處理數據源和數據輸出的之間的適配,例如,需要將某個字段的值10以後再輸出,這個10的動作就應該寫在filter模塊;還有數據源和數據輸出字段的編碼不同,日期類型不同等情況的處理。(由於本文中A表和B表中數據結構都是一樣的,只是實現簡單的數據同步,暫時用不到filter

同步配置文件如下:後面對每個部分進行解釋。

input {
    jdbc {
        jdbc_connection_string => "jdbc:mysql://IP:3306/DB1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true"
        jdbc_user => "expert"
        jdbc_password => "123456"
        jdbc_driver_library => "/opt/elastic/logstash-test/mysql-connector-java-5.1.6.jar"
        jdbc_driver_class => "com.mysql.jdbc.Driver"
        statement => "SELECT title,description FROM A"
   }
}

filter {}

output {
    jdbc {
        connection_string => "jdbc:mysql://IP:3306/DB2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true"
        username => "root"
        password => "root123"
        driver_jar_path => "/opt/elastic/logstash-test/mysql-connector-java-5.1.6.jar"
        driver_class => "com.mysql.jdbc.Driver"
        statement => ["insert into B (title,description) values (?,?)","[title]","[description]"]
    }
    stdout {
        codec => json_lines
    }
}

input配置

input的配置中有很多強大的功能,詳細使用見官網地址,此處只介紹上面涉及到的參數:

  • jdbc_connection_string :數據庫連接配置
  • jdbc_user :用戶名(連接DB1的用戶名)
  • jdbc_password:密碼(連接DB1的密碼)
  • jdbc_driver_library:數據驅動的jar位置
  • jdbc_driver_class :數據庫驅動類名(類似jdbc中的Class.forName(“com.mysql.jdbc.Driver”))
  • statement :查詢數據源的sql語句(output中就是將此處的查詢結果insert到數據庫DB2中)

output配置

由於logstash-output-jdbc是額外擴展的output插件,在配置參數的寫法上也略有不同,比如:所有的參數前面都沒有jdbc_前綴

  • connection_string :數據庫連接配置
  • username :用戶名(連接DB2的用戶名
  • password :密碼(連接DB2的密碼)
  • driver_jar_path :與input參數中的jdbc_driver_library一致
  • driver_class :與input參數中的jdbc_driver_class一致
  • statement :向DB2中添加數據的insert語句。

四、執行啓動命令

將上述的配置文件命令爲logstash_default.conf,放在logstash-test/conf文件夾下,在logstash-test下執行:

logstash啓動命令

./bin/logstash -f /opt/elastic/logstash-test/config/logstash_default.conf --path.data=/opt/elastic/logstash-test/test

啓動後發現報如下異常:

java.lang.IllegalAccessError: tried to access class com.mysql.jdbc.EscapeProcessor from class com.mysql.jdbc.ConnectionImpl
在這裏插入圖片描述
java.lang.IllegalAccessError: com/mysql/jdbc/EscapeProcessor在這裏插入圖片描述

遺憾的是目前沒有找到爲什麼會報這個異常,不過換了一種驅動的配置方式,這個異常就消失了。另外一種指定驅動jar包的方式也是官網給出的方式如下:
在這裏插入圖片描述
下面結合本例中給出解決辦法。

啓動異常處理方式:

在logstash目錄下,創建目錄vendor/jar/jdbc(/opt/elastic/logstash-test/vendor/jar/jdbc),將驅動jar包放入該路徑下。
在這裏插入圖片描述
將配置文件中的driver_jar_path註釋掉,
在這裏插入圖片描述

重新執行logstash啓動命令

./bin/logstash -f /opt/elastic/logstash-test/config/logstash_default.conf --path.data=/opt/elastic/logstash-test/test

執行結果:
在這裏插入圖片描述
檢查DB2中的表B:數據已經全部同步過去了。
在這裏插入圖片描述

五、定時自動同步數據

按照上面的過程,能實現執行logstash命令以後,DB1中的表A和DB2中的表B數據同步,但是如果後續表A中的數據有新增或者修改,還需要再去啓動logstash。logstash提供了一種定時任務的方式,定期去檢查表A中的數據是否有變化,根據表A的最後修改時間(LastUpdateDate)將表A中新增和修改的數據修改新增到表B中。

將配置文件做如下修改:

input {
    jdbc {
        jdbc_connection_string => "jdbc:mysql://IP:3306/DB1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true"
        jdbc_user => "expert"
        jdbc_password => "123456"
        jdbc_driver_library => "/opt/elastic/logstash-test/mysql-connector-java-5.1.6.jar"
        jdbc_driver_class => "com.mysql.jdbc.Driver"
        statement => "SELECT title,description FROM A"
        schedule => "* * * * *"
        record_last_run => true
        use_column_value => true
        tracking_column => "LastUpdateDate"
        tracking_column_type => "timestamp"
        last_run_metadata_path => "/opt/elastic/logstash-test/last_record/logstash_default_last_time"
        clean_run => false
        lowercase_column_names => false
   }
}

filter {}

output {
    jdbc {
        connection_string => "jdbc:mysql://IP:3306/DB2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true"
        username => "root"
        password => "root123"
        driver_class => "com.mysql.jdbc.Driver"
        statement => ["insert into B (title,description) values(?,?) on duplicate key update title=values(title),description=values(description)","[title]","[description]"]
    }
    stdout {
        codec => json_lines
    }
}

input中新增的參數:

  • schedule => "* * * * *":每分鐘檢查一次
  • ` record_last_run => true``:是否記錄上一下執行的時間
  • ` use_column_value => true``:是否使用數據源的字段
  • `tracking_column => “LastUpdateDate”``:數據源的最後修改時間字段
  • `tracking_column_type => “timestamp”``:字段類型
  • ` last_run_metadata_path => “/opt/elastic/logstash-test/last_record/logstash_default_last_time”``:存放最後修改時間的文件位置
  • ` clean_run => false``:這個參數表示你在開啓Logstash同步數據時需不需要clean掉上次的記錄
  • lowercase_column_names => false讀取字段時是否區分大小寫

output新增的參數:

stdout {
    codec => json_lines
}

stdout爲可選字段,將輸出數據的方式加一種,stdout可以把input中statement 的select結果轉爲json字符串打印到logstash的log中,便於追蹤檢查哪些數據被更新了。

六、補充

output中的statement修改:

將表B中的title字段設置爲唯一約束,將statement改爲如下。即可實現如果title相同的時候,只修改記錄,而不是新增。唯一約束可以根據實際需求去設置。

["insert into B (title,description) values(?,?) on duplicate key update title=values(title),description=values(description)","[title]","[description]"]

表A修改完只有需要1分鐘以後才能在表B中看到同步效果,因爲定時任務設置的每分鐘執行一次。

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