随着业务数据的增长,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}"
}
}
}