原文鏈接
https://www.jianshu.com/p/fb96ab7fbde9
把Mysql的數據同步到Elasticsearch是個很常見的需求,但在Github裏找到的同步工具用起來或多或少都有些彆扭。
例如:某記錄內容爲"aaa|bbb|ccc",將其按|分割成數組同步到es,這樣的簡單任務都難以實現,再加上配置繁瑣,文檔語焉不詳...
所以我寫了個同步工具MysqlsMom:力求用最簡單的配置完成複雜的同步任務。目前除了我所在的部門,也有越來越多的互聯網公司在生產環境中使用該工具了。
歡迎各位大佬進行試用並提出意見,任何建議、鼓勵、批評都受到歡迎。
github: https://github.com/m358807551/mysqlsmom
簡介:同步mysql數據到elasticsearch的工具;
QQ、微信:358807551
特點
- 純Python編寫;
- 有全量、增量更新兩種模式;
- 全量更新只佔用少量內存;支持通過sql語句同步數據;
- 增量更新自動斷點續傳;
- 取自mysql的數據可經過一系列自定義函數的處理後再同步至elasticsearch;
- 能用非常簡單的配置完成複雜的同步任務;
環境
- python2.7;
- 如需增量同步,需要mysql開啓binlog(binlog-format=row)且本地開啓redis;
快速開始
全量同步MySql數據到es
clone 項目到本地;
-
安裝依賴;
cd mysqlsmom pip install -r requirements.txt
默認支持 elasticsearch-2.4版本,支持其它版本請運行(將5.4換成需要的elasticsearch版本)
pip install --upgrade elasticsearch==5.4
-
編輯 ./config/example_init.py,按註釋提示修改配置;
# coding=utf-8 STREAM = "INIT" # 修改數據庫連接 CONNECTION = { 'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'passwd': '' } # 修改elasticsearch節點 NODES = [{"host": "127.0.0.1", "port": 9200}] TASKS = [ { "stream": { "database": "test_db", # 在此數據庫執行sql語句 "sql": "select * from person" # 將該sql語句選中的數據同步到 elasticsearch }, "jobs": [ { "actions": ["insert", "update"], "pipeline": [ {"set_id": {"field": "id"}} # 默認設置 id字段的值 爲elasticsearch中的文檔id ], "dest": { "es": { "action": "upsert", "index": "test_index", # 設置 index "type": "test", # 設置 type "nodes": NODES } } } ] } ]
-
運行
cd mysqlsmom
python mysqlsmom.py ./config/example_init.py
等待同步完成即可;
增量同步MySql數據到es
確保要增量同步的MySql數據庫開啓binlog,且本地開啓redis(爲了存儲最後一次讀到的binlog文件名及讀到的位置。未來可能支持本地文件存儲該信息。)
-
下載項目到本地,且安裝好依賴後,編輯 ./config/example_init.py,按註釋提示修改配置;
# coding=utf-8 STREAM = "BINLOG" SERVER_ID = 99 # 確保每個用於binlog同步的配置文件的SERVER_ID不同; SLAVE_UUID = __name__ # 配置開啓binlog權限的MySql連接 BINLOG_CONNECTION = { 'host': '127.0.0.1', 'port': 3306, 'user': 'root', 'passwd': '' } # 配置es節點 NODES = [{"host": "127.0.0.1", "port": 9200}] TASKS = [ { "stream": { "database": "test_db", # [table]所在的數據庫 "table": "person" # 監控該表的binlog }, "jobs": [ { "actions": ["insert", "update"], "pipeline": [ {"only_fields": {"fields": ["id", "name", "age"]}}, # 只同步這些字段到es,註釋掉該行則同步全部字段的值到es {"set_id": {"field": "id"}} # 設置es中文檔_id的值取自 id(或根據需要更改)字段 ], "dest": { "es": { "action": "upsert", "index": "test_index", # 設置 index "type": "test", # 設置 type "nodes": NODES } } } ] } ]
-
運行
cd mysqlsmom python mysqlsmom.py ./config/example_binlog.py
該進程會一直運行,實時同步新增和更改後的數據到elasticsearch;
注意:第一次運行該進程時不會同步MySql中已存在的數據,從第二次運行開始,將接着上次同步停止時的位置繼續同步;
同步舊數據請看全量同步MySql數據到es;
組織架構
Pipeline
如果需要從Mysql獲取數據再進行特殊處理再同步到elasticsearch,pipeline組件會派上用場。
無論數據來自於全量同步的Sql語句或是通過實時分析binlog。
例如:
-
只同步某些字段到es
"pipeline": [ {"only_fields": {"fields": ["id", "name"]}}, # 只同步 id 和 name字段 ... ]
-
重命名字段
"pipeline": [ {"replace_fields": {"name": ["name1", "name2"]}}, # 將name重命名爲name1和name2 ... ]
-
甚至可以執行跨庫數據庫查詢
"pipeline": [ { "do_sql": { "database": "db2", "connection": CONNECTION2, "sql": "select company, personid from company_manager where personid = {id}" # id 的值會自動替換 } } ... ]
支持編寫自定義函數,只需在 row_handlers.py 中加入,之後可在pipeline中配置調用。
row_handlers.py中預定義了一些數據處理函數,但可能需要自定義的情況更多。
常見問題
能否把數據同步到多個es索引?
目前增量同步支持,只需修改配置文件中的[dest]
"dest": [
{
"es": {
"action": "upsert",
"index": "index1", # 同步到 es index1.type1
"type": "type1",
"nodes": NODES
}
},
{
"es": {
"action": "upsert",
"index": "index2", # 同時同步到 es index1.type1
"type": "type2",
"nodes": NODES
}
}
]
全量同步很快會支持該功能;
爲什麼我的增量同步不及時?
-
連接本地數據庫增量同步不及時
該情況暫未收到過反饋,如能復現請聯繫作者。
-
連接線上數據庫發現增量同步不及時
2.1 推薦使用內網IP連接數據庫。連接線上數據庫(如開啓在阿里、騰訊服務器上的Mysql)時,推薦使用內網IP地址,因爲外網IP會受到帶寬等限制導致獲取binlog數據速度受限,最終可能造成同步延時。
待改進
- 據部分用戶反饋,全量同步百萬級以上的數據性能不佳。
未完待續
文檔近期會大幅度更新完善,任何問題、建議都收到歡迎,請在issues留言,會在24小時內回覆;或聯繫QQ、微信: 358807551;