MysqlsMom: 同步mysql數據到elasticsearch的利器

原文鏈接

https://www.jianshu.com/p/fb96ab7fbde9

把Mysql的數據同步到Elasticsearch是個很常見的需求,但在Github裏找到的同步工具用起來或多或少都有些彆扭。
例如:某記錄內容爲"aaa|bbb|ccc",將其按|分割成數組同步到es,這樣的簡單任務都難以實現,再加上配置繁瑣,文檔語焉不詳...
所以我寫了個同步工具MysqlsMom:力求用最簡單的配置完成複雜的同步任務。目前除了我所在的部門,也有越來越多的互聯網公司在生產環境中使用該工具了。
歡迎各位大佬進行試用並提出意見,任何建議、鼓勵、批評都受到歡迎。
github: https://github.com/m358807551/mysqlsmom

MysqlsMom.jpeg

簡介:同步mysql數據到elasticsearch的工具;
QQ、微信:358807551

特點

  1. 純Python編寫;
  2. 有全量、增量更新兩種模式;
  3. 全量更新只佔用少量內存;支持通過sql語句同步數據;
  4. 增量更新自動斷點續傳;
  5. 取自mysql的數據可經過一系列自定義函數的處理後再同步至elasticsearch;
  6. 能用非常簡單的配置完成複雜的同步任務;

環境

  • python2.7;
  • 如需增量同步,需要mysql開啓binlog(binlog-format=row)且本地開啓redis;

快速開始

全量同步MySql數據到es

  1. clone 項目到本地;

  2. 安裝依賴;

    cd mysqlsmom
    pip install -r requirements.txt
    

    默認支持 elasticsearch-2.4版本,支持其它版本請運行(將5.4換成需要的elasticsearch版本)

    pip install --upgrade elasticsearch==5.4
    
  3. 編輯 ./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
                        }
                    }
                }
            ]
        }
    ]
    
  4. 運行

cd mysqlsmom
python mysqlsmom.py ./config/example_init.py

等待同步完成即可;

增量同步MySql數據到es

  1. 確保要增量同步的MySql數據庫開啓binlog,且本地開啓redis(爲了存儲最後一次讀到的binlog文件名及讀到的位置。未來可能支持本地文件存儲該信息。)

  2. 下載項目到本地,且安裝好依賴後,編輯 ./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
                        }
                    }
                }
            ]
        }
    ]
    
  3. 運行

    cd mysqlsmom
    python mysqlsmom.py ./config/example_binlog.py
    

    該進程會一直運行,實時同步新增和更改後的數據到elasticsearch;

    注意:第一次運行該進程時不會同步MySql中已存在的數據,從第二次運行開始,將接着上次同步停止時的位置繼續同步;

    同步舊數據請看全量同步MySql數據到es

組織架構

all.png

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
            }
        }
 ]

全量同步很快會支持該功能;

爲什麼我的增量同步不及時?

  1. 連接本地數據庫增量同步不及時

    該情況暫未收到過反饋,如能復現請聯繫作者。

  2. 連接線上數據庫發現增量同步不及時

    2.1 推薦使用內網IP連接數據庫。連接線上數據庫(如開啓在阿里、騰訊服務器上的Mysql)時,推薦使用內網IP地址,因爲外網IP會受到帶寬等限制導致獲取binlog數據速度受限,最終可能造成同步延時。

待改進

  1. 據部分用戶反饋,全量同步百萬級以上的數據性能不佳。

未完待續

文檔近期會大幅度更新完善,任何問題、建議都收到歡迎,請在issues留言,會在24小時內回覆;或聯繫QQ、微信: 358807551;

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