阅读 185

Logstash-input-jdbc实现与MySql解耦同步数据到ES

这是我参与更文挑战的第6天,活动详情查看 更文挑战

随着业务数据的增长,Mysql压力增大,单表储存会严重影响读写的高效性,为解决这一问题,分表分库和历史数据迁移等解决方案就应运而生了,但在某些场景下这些解决方案还是存在问题,例如聚合查询等。而ElasticSearch作为实时的分布式搜索和分析引擎,能够快速查询和处理海量数据,高可用可扩展,通过ES,可以轻松做到保证查询效率的聚合查询,已有不少大型互联网企业成功使用案例,是值得一试的技术。

使用了一段时间ES之后,发现对数据的实时插入对网络带宽有比较大的消耗,且高并发时对服务器产生的压力也不小,所以能不能定时地去查询sql数据库,保持数据的同步,来解耦这个问题呢?

经过调研,实现与Mysql同步工具基本有以下几种:

  • logstash-input-jdbc:官方推荐的插件,Ruby编写的
  • go-mysql-elastic:Go编写,国内作者
  • python-mysql-replication: Python编写
  • elasticsearch-jdbc:Java编写
  • elasticsearch-river-mysql:已经很少维护

0. 安装 ElasticSearch

本文不再赘述ES的安装过程。

1. 下载 Logstash

官网链接: Download Logstash 以6.1.1版本为例:

wget https://artifacts.elastic.co/downloads/logstash/logstash-6.1.1.zip
# 等待下载完毕,执行解压
unzip logstash-6.1.1.zip
复制代码

2. 安装 logstash-input-jdbc 插件

进入解压好的目录 cd logstash-6.1.1

root用户执行:sudo bin/logstash-plugin install logstash-input-jdbc

补充:后面查阅一些文章说logstash5.x以上版本自带了这个插件,但我已经安装了,就不再验证,这里应该可以直接略过此步,后面如果报错再回来折腾。

安装过程会有点慢,我在本地一次成功了,服务器上卡在Installing logstash-input-jdbc不动,第二天早上又试了下又成功了,如果一直不行尝试以下方法,执行:

cd logstash-6.1.1
wget https://github.com/logstash-plugins/logstash-input-jdbc/archive/v4.3.1.zip
unzip logstash-input-jdbc-4.3.1.zip
cd logstash-input-jdbc-4.3.1/
复制代码

再执行:

vi Gemfile
复制代码

修改 source 的值 为: "https://ruby.taobao.org""https://gems.ruby-china.org"

保存完继续执行:

vi logstash-input-jdbc.gemspec
复制代码

找到这一行:

s.files = `git ls-files`.split($\)
复制代码

改为:

s.files = [".gitignore", "CHANGELOG.md", "Gemfile", "LICENSE", "NOTICE.TXT", "README.md", "Rakefile", "lib/logstash/inputs/jdbc.rb", "lib/logstash/plugin_mixins/jdbc.rb", "logstash-input-jdbc.gemspec", "spec/inputs/jdbc_spec.rb"]
复制代码

继续执行:

gem build logstash-input-jdbc.gemspec

cd ..
bin/plugin install logstash-input-jdbc-4.3.1.gem
复制代码

该方法属于手动安装,需要你指定插件版本,参照plugins-inputs-jdbc官方文档查看插件当前的最新版本号。

3. 关联Mysql数据库

下载一个mysql连接jar包:mysql-connector-java-6.0.6

进入logstash创建一个conf文件,执行:

cd logstash-6.1.1/config
vim jdbc.conf
复制代码

编辑粘贴以下内容:

input {
	    jdbc {
	    	# 刚才下载的jar包路径
	        jdbc_driver_library =>"/opt/mysql-connector-java-6.0.6.jar"
	        jdbc_driver_class =>"com.mysql.jdbc.Driver"
	        # 数据库地址
	        jdbc_connection_string =>"jdbc:mysql://192.168.0.1:3306/myTest?characterEncoding=UTF-8&useSSL=false"
	        jdbc_user =>"root"
	        jdbc_password =>"123456"
	        # 定时查询
	        schedule =>"* * * * *"
	        # 执行的sql语句,两种形式
	        #statement_filepath => "/opt/test.sql"
	        statement =>"SELECT * FROM tname"
	    }
	}
	output {
	    elasticsearch {
	    	# 转换ES索引
	        index =>"name_index"
	        document_type =>"name_type"
	        # 关联表中的id字段,对应索引id
	        document_id =>"%{id}"
	        template_overwrite => true
	        hosts =>["127.0.0.1:9200"]
	    }
	}
复制代码

选择filepath形式执行sql语句的话需要额外创建一个sql文件,在里面编写sql语句,这里省略。

返回到logstash-6.1.1目录,然后执行:

bin/logstash -f config/jdbc.conf
复制代码

等待一会,会看到终端输出了刚才写的sql语句,因为开启了schedule,根据以上配置大概30s就会执行一次sql查询,增量更新到ES的索引。需要注意的是,对于更新操作,目前插件都不能实现。

浏览器访问 http://服务器ip:9200/name_index/name_type/_search ,即可看到同步的数据。

最后将进程挂载后台让它一直做定时查询即可。

4. 操作数据

参考官方视图工具 kibana 选择对应版本,下载到本地,解压,进入config/kibana.yml 修改 elasticsearch.url为你服务器的ES地址,运行 bin/kibana 浏览器访问 http://localhost:5601 ,即可在本地连接线上ES服务器,比较常用的功能例如 Dev Tools

Elasticsearch: 权威指南

5. 多个数据表查询

input {
            jdbc {
                jdbc_driver_library =>"/opt/mysql-connector-java-6.0.6.jar"
                jdbc_driver_class =>"com.mysql.jdbc.Driver"
                jdbc_connection_string =>"jdbc::3306/?characterEncoding=UTF-8&useSSL=false"
                jdbc_user =>""
                jdbc_password =>""
                schedule =>"* * * * *"
                statement_filepath => "/opt/order_goods.sql"
                #statement =>"SELECT * FROM tname"
                                        type => "jdbc_order_goods"
            }
                        jdbc {
                jdbc_driver_library =>"/opt/mysql-connector-java-6.0.6.jar"
                jdbc_driver_class =>"com.mysql.jdbc.Driver"
                jdbc_connection_string =>"jdbc::3306/?characterEncoding=UTF-8&useSSL=false"
                jdbc_user =>""
                jdbc_password =>""
                schedule =>"* * * * *"
                statement_filepath => "/opt/user.sql"
                                        type => "jdbc_user"
            }
        }

output {
                if[type] == "jdbc_order_goods"{
        elasticsearch {
                hosts =>["127.0.0.1:9200"]
                                        index =>"order_goods_index"
                document_type =>"order_goods_type"
                document_id =>"%{id}"
        }
    }
    if[type] == "jdbc_user"{
        elasticsearch {
                hosts =>["127.0.0.1:9200"]
                index => "user_index"
                document_type => "user_type"
                document_id => "%{id}"
        }
    }
}
复制代码
文章分类
后端