Sync Data From MySQL To ElasticSearch

https://giaphiep.com/blog/sync-data-from-mysql-to-elasticsearch-6964

Sync Data From MySQL To ElasticSearch

ElasticsearchMigrateLogstashSync

Giới thiệu:

MySQL là gì ?

MySQL là hệ quản trị cơ sở dữ liệu tự do nguồn mở ... Đọc tiếp

Elasticsearch là gì ?

Elasticsearch là một công cụ tìm kiếm dựa trên nền tảng Apache Lucene... Đọc tiếp

Logstash là gì ?

Logstash is an open source, server-side data processing pipeline that ingests data from a multitude of sources simultaneously, transforms it, and then sends it to your favorite “stash.” (Ours is Elasticsearch, naturally.)

Vấn đề:

Nếu bạn đọc đến đây thì chắc hẳn bạn đã lướt qua các khái niệm rồi. Nếu bạn gặp 1 dự án sử dụng MySQL hoặc SQL Server hoặc ... để lưu data nhưng việc truy vấn vào các hệ thống database như vậy sẽ tốn time rất lâu.

Vậy để cải thiện vấn đề này, nhiều người đã chọn giải pháp sử dụng song song database (ở đây mình dùng MySQL) và 1 công cụ search đang là hot trend hiện nay là ElasticSearch. Dùng MySQL để lưu data, và dùng ElasticSearch để truy vấn.

Điều này dẫn đến 1 vấn đề : khi insert bạn phải insert vào cả MySQL và ElasticSearch, việc làm này dẫn đến 1 risk là mất đồng bộ data khi trường hợp insert vào MySQL thành công, nhưng insert vào ElasticSearch thất bại.

Để giải quết vấn đề này, có 1 cách là chỉ insert vào MySQL, sau đó thực hiện đồng bộ từ MySQL lên ElasticSearch.

Ở đây mình sẽ hướng dẫn việc đồng bộ từ MySQL lên ElasticSearch, nếu có thời gian mình sẽ up thêm 1 bài tạo shell để settup việc thực hiện đồng bộ data theo thời gian đặt trước.

Mình sử dụng Logstash của Elastic, vì Logstash là 1 cơ chế của Elastic tạo ra để mình có thể sync data từ bất cứ DB nào vào ElasticSearch.

Mình dùng Ubuntu 16 nhé, Nếu bạn dùng Ubuntu 18 thì nên cẩn thận có 1 số feature Elastic không support

Implement:

Install logstash

Làm theo hướng dẫn ở link này thôi (easy mà) : https://www.elastic.co/guide/en/logstash/current/installing-logstash.html Check lại xem đã install được chưa nhé

    sudo service logstash start
    sudo service logstash status

Set environment :

Set biến môi trường trong Ubuntu thôi:

  • Mở file bashrc lên vi ~/.bashrc

  • Input path của logstash đã install vào export LS_HOME=/usr/share/logstash

  • Apply biến môi trường : source ~/.bashrc

Create file config to migrate data

Để logstash connect được vào MySQL và Sync data lên ElasticSearch thì phải define file config để logstash hiểu được nhá :

  • cd đến thư mục logstash : cd /usr/share/logstash

  • Tạo file config với tên logstash_mysql.conf với nội dung bên dưới (có thể phải dùng đến lệnh sudo đấy: sudo gedit logstash_mysql.conf )

input {
 jdbc {

       # Thông tin connect vào database MySQL

       jdbc_connection_string => "jdbc:mysql://localhost:3306/vietnam"
       jdbc_user => "root"
       jdbc_password => "12345"

       # Chúng ta sẽ sử dụng jdbc để connect đến MySQL (trỏ đường dẫn đến file mysql-connector-java-8.0.11.jar của bạn)
       jdbc_driver_library => "/home/xxx/Sync_Mysql_ES/lib/mysql-connector-java-8.0.11.jar"
       jdbc_driver_class => "com.mysql.jdbc.Driver"

       # our query
       # ở đây bạn select gì thì edit nhá (câu lệnh SQL như trong MySQL thôi)
       statement => "select id, name, age, heigh, weight from vietnam.girl where age >= 18"
   }

   output {
       stdout { codec => json_lines }
       elasticsearch {
           "hosts" => "localhost:9200"
           "index" => "vietnam_elasticsearch_index"
           "document_type" => "girl"

       }

   }

Bạn có thể thêm hoặc bớt các options config cho phần output tùy thích nhá. Here

Create index:

Tạo 1 index để test thử


PUT "localhost:9200/vietnam_elasticsearch_index"

{
  "mappings": {
      "girl": {
          "properties": {
              "id": {
                  "type": "text",
                      "fields": {
                          "keyword": {
                              "type": "keyword",
                              "ignore_above": 256
                            }
                         }
                    },
                    "name": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                     },
                     "age": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    },
                    "heigh": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    },
                    "weight": {
                        "type": "text",
                        "fields": {
                            "keyword": {
                                "type": "keyword",
                                "ignore_above": 256
                            }
                        }
                    }
                }
            }
    },
    "settings": {
        "index": {
            "number_of_shards": "5",
            "number_of_replicas": "1" 
        }
    }
}

Excute command migrate:

Migrate thôi nào, phần mình thích nhất: - cd vào thư mục logstash nhé (nơi bạn tạo file config ở trên) cd /usr/share/logstash - Run command và đợi thôi, run xong nếu ko có lỗi gì nó sẽ báo success :v: sudo bin/logstash --path.settings /etc/logstash/ -f logstash_mysql.conf

Result:

Mở postman lên và check thôi nào: GET : localhost:9200/vietnam_elasticsearch_index/girl/_search Kết quả sẽ tương tự thế này:

{
   "_index": "vietnam_elasticsearch_index",
   "_type": "girl",
   "_id": "AXXX",
   "_score": 0.2876821,
   "_source": {
                       "@version": "1",
                       "@timestamp": "2019-01-21T02:30:25.905Z",
                       "id": "PG1",
                       "name": "Quỳnh Búp Bê",
                       "age": "20",
                       "heigh": "1.65",
                       "weight": "45"
                       }
   }
  • Kết quả sẽ thấy id, name, age, heigh, weight ở table vietnam.girl sẽ được migrate lên index vietnam_elasticsearch_index

  • @version và @timestamp: 2 trường này mặc định logstash sẽ tự động insert vào elasticsearch của bạn, nó sẽ chứa thông tin thời gian thực hiện migrate bằng logstash, không cần quan tâm 2 trường này.

Migrate nhiều lần thì thế nào?

  • Sau khi thực hiện migrate ở bước trên, run tiếp lệnh sudo bin/logstash --path.settings /etc/logstash/ -f logstash_mysql.conf sẽ thế nào (trường hợp run thành công nhé):

    • Kết quả sẽ ra như sau:

{
    "_index": "vietnam_elasticsearch_index",
    "_type": "girl",
    "_id": "AXXX",
    "_score": 0.2876821,
    "_source": {
                "@version": "1",
                "@timestamp": "2019-01-21T02:30:25.905Z",
                "id": "PG1",
                "name": "Quỳnh Búp Bê",
                "age": "20",
                "heigh": "1.65",
                "weight": "45"
    }
},
{
    "_index": "vietnam_elasticsearch_index",
    "_type": "girl",
    "_id": "AXGH",
    "_score": 0.2876821,
    "_source": {
                "@version": "1",
                "@timestamp": "2019-01-21T02:33:25.905Z",
                "id": "PG1",
                "name": "Quỳnh Búp Bê",
                "age": "20",
                "heigh": "1.65",
                "weight": "45"
    }
} 

Nhìn có gì khác không nhỉ ? ==> Duplicate data. Như vậy thì mỗi lần migrate phải clean toàn bộ data trong elasticsearch đi và migrate lại ư? Phải có 1 cách nào đó chứ nhỉ? OK, hãy nhìn lại result 1 tí: - Ở record thứ 1: "_id": "AXXX"{"id": "PG1"} - Và record thứ 2: "_id": "AXGH" {"id": "PG1"} => 2 record này bị dup data và _id thì khác nhau, vậy nếu _id trùng với "id" ở MySQL thì sẽ ko bị duplicate data nữa OK, edit lại 1 tý ở file config, thử xem thế nào:

logstash_mysql.conf vẫn là file cũ nhé, add thêm "document_id" => "%{id}" ở phần output

        jdbc { 
            # Thông tin connect vào database MySQL
            jdbc_connection_string => "jdbc:mysql://localhost:3306/vietnam"
            jdbc_user => "root"
            jdbc_password => "12345"
            # Chúng ta sẽ sử dụng jdbc để connect đến MySQL (trỏ đường dẫn đến file mysql-connector-java-8.0.11.jar của bạn)
            jdbc_driver_library => "/home/xxx/Sync_Mysql_ES/lib/mysql-connector-java-8.0.11.jar"
            jdbc_driver_class => "com.mysql.jdbc.Driver"
            # our query
            # ở đây bạn select gì thì edit nhá (câu lệnh SQL như trong MySQL thôi)
            statement => "select id, name, age, heigh, weight from vietnam.girl where age >= 18"
        }
    output {
        stdout { codec => json_lines }
        elasticsearch {
            "hosts" => "localhost:9200"
            "index" => "vietnam_elasticsearch_index"
            "document_type" => "girl"
            "document_id" => "%{id}"
        }
    }

=> Clean data elasticsearch và cùng xem thử kết quả nào:

  1. Clean Data: DELETE index và tạo lại cho nhanh => tham khảo bước create index ở trên nhé

  2. sudo bin/logstash --path.settings /etc/logstash/ -f logstash_mysql.conf . Run n lần thì kết quả cũng sẽ ra như bên dưới thôi:

{
       "_index": "vietnam_elasticsearch_index",
       "_type": "girl",
       "_id": "PG1",
       "_score": 0.2876821,
       "_source": {
                    "@version": "1",
                    "@timestamp": "2019-01-21T02:30:25.905Z",
                    "id": "PG1",
                    "name": "Quỳnh Búp Bê",
                    "age": "20",
                    "heigh": "1.65",
                    "weight": "45"
                }
        }

Error when execute migrate:

Những lỗi có thể xảy ra trong quá trình sync data và cách giải quyết (mình gặp thôi):

    - Could not find logstash.yml which is typically located in $LS_HOME/config : 
        --> add parram --path.settings into command migrate : bin/logstash --path.settings /etc/logstash -f [name of file config you have defined] 
    - Logstash could not be started because there is already another instance using the configured data directory.  If you wish to run multiple instances, you must change the "path.data" setting.
        --> sudo pkill logstash 
        --> hoặc bạn có thể start 1 instance logstash khác bằng cách thêm --path.data: - bin/logstash --path.settings [another url config logstash.yml] -f logstash_mysql.conf --path.data /home/data_logstash_instance_2`

In Aws:

Trên môi trường Amazon Linux, nếu bạn sử dụng hệ sinh thái của amazon thì ở phần output bạn chỉ cần add thêm chứng thực ssl là được, like this:

output {
        stdout { codec => json_lines }
        elasticsearch {
            "hosts" => "aws:443"
            "ssl" => "true"
            "index" => "vietnam_elasticsearch_index"
            "document_type" => "girl"
            "document_id" => "%{id}"
        }
    }

Conclusion:

Như vậy, qua vài bước đơn giản, bạn đã có thể migrate data từ MySQL lên ElasticSearch rồi, khá đơn giản phải không nào, không phải viết code gì phức tạp để đọc từ DB rồi phải Push lên ElasticSearch. Chúc bạn thành công!

Last updated