实现目标
基于MySql的Binlog实现Mysql表实时同步到ES。
实现方案
1、总体技术方案基于Kafka的Connect技术。具体技术内容,不做介绍,网上有相关文章,本文章主要解决如何配置,因为网上大部分配置都是只能简单运行,只能插入,不能实现数据按照主键进行更新和删除同步的。
2、基于debezium的MySqlConnector插件,完成Mysql同步到Kafka。 此插件的机制与阿里的canal一样,基于模拟slave读取MySql Binlog。读取数据后通过配置将数据转换,实时同步到Kafka。
3、基于confluent的elasticsearch.sink插件,将Kafka的数据实时同步到ES。confluent是基于Kafka Connect技术,实现多种数据源格式导入导出的工具平台。本文章只需要下载免费版就可以,主要是拿到里面的kafka-connect-elasticsearch,如果不下载整个confluent,网上能找到kafka-connect-elasticsearch也可以。
具体实现
1、安装Kafka,见网上文章。
2、配置connect-standalone.properties,服务有单机模式和集群模式,这里介绍单机模式。此文件在kafka安装目录的config文件夹下。
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# These are defaults. This file just demonstrates how to override some settings.
bootstrap.servers=192.188.2.59:9092
# The converters specify the format of data in Kafka and how to translate it into Connect data. Every Connect user will
# need to configure these based on the format they want their data in when loaded from or stored into Kafka
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter
# Converter-specific settings can be passed in by prefixing the Converter's setting with the converter we want to apply
# it to
key.converter.schemas.enable=true
value.converter.schemas.enable=true
offset.storage.file.filename=/tmp/connect.offsets
# Flush much faster than normal, which is useful for testing/debugging
offset.flush.interval.ms=10000
# Set to a list of filesystem paths separated by commas (,) to enable class loading isolation for plugins
# (connectors, converters, transformations). The list should consist of top level directories that include
# any combination of:
# a) directories immediately containing jars with plugins and their dependencies
# b) uber-jars with plugins and their dependencies
# c) directories immediately containing the package directory structure of classes of plugins and their dependencies
# Note: symlinks will be followed to discover dependencies or plugins.
# Examples:
# plugin.path=/usr/local/share/java,/usr/local/share/kafka/plugins,/opt/connectors,
plugin.path=/data/soft/kafka_2.12-2.5.0/plugins
主要配置内容
bootstrap.servers=192.188.2.59:9092 配置Kafka的地址。
plugin.path=/data/soft/kafka_2.12-2.5.0/plugins 配置所使用插件的存放目录。
本例中需要将两个插件存放在此目录:debezium-connector-mysql、和kafka-connect-elasticsearch。
3、下载debezium-connector-mysql,下载地址https://repo1.maven.org/maven2/io/debezium/debezium-connector-mysql/0.9.5.Final/debezium-connector-mysql-0.9.5.Final-plugin.tar.gz。
4、在config目录下建立mysql-source.properties文件并配置如下信息。
name=mysql_connect_source
connector.class=io.debezium.connector.mysql.MySqlConnector
database.hostname=ip
database.port=3306
database.user=dbuser
database.password=dbpassword
database.server.id=serverid
database.server.name=mysql
database.whitelist=users
table.whitelist=user,dept
database.history.kafka.bootstrap.servers=192.188.2.59:9092
database.history.kafka.topic=topic
include.schema.changes=true
database.history.skip.unparseable.ddl=true
transforms=unwrap,changetopic
transforms.unwrap.type=io.debezium.transforms.UnwrapFromEnvelope
transforms.unwrap.operation.header=true
transforms.unwrap.drop.tombstones=true
transforms.unwrap.delete.handling.mode=none
transforms.unwrap.operation.header=true
transforms.changetopic.type=org.apache.kafka.connect.transforms.RegexRouter
transforms.changetopic.regex=(.*)
transforms.changetopic.replacement:$1-smt
配置详解
name=mysql_connect_source 运行的服务名称
connector.class=io.debezium.connector.mysql.MySqlConnector 插件运行的类
database.hostname=ip 数据库IP
database.port=3306 数据库端口
database.user=dbuser 数据库连接用户名
database.password=dbpassword 数据库连接密码
database.server.id=serverid 数据库的serverId,数据库中执行sql : show variables like 'server_id' 查看结果
database.server.name=mysql 生成的在kafka的topic前缀。
database.whitelist=users 同步到kafka的数据库白名单
table.whitelist=user,dept 同步到kafka的表白名单
database.history.kafka.bootstrap.servers=192.188.2.59:9092 保存历史变更信息的kafka,可以是当前用于同步数据的kafka。
database.history.kafka.topic=topic 保存表结构变化的topic
database.history.skip.unparseable.ddl=true
include.schema.changes=true 是否将表结构变化信息同步过去
transforms=unwrap,changetopic
transforms.unwrap.type=io.debezium.transforms.UnwrapFromEnvelope
transforms.unwrap.operation.header=true
transforms.unwrap.drop.tombstones=true
transforms.unwrap.delete.handling.mode=none
transforms.unwrap.operation.header=true
transforms.changetopic.type=org.apache.kafka.connect.transforms.RegexRouter
transforms.changetopic.regex=(.*)
transforms.changetopic.replacement:$1-smt
transforms是转换器,因为debezium读取后的统一格式,别的插件不能读懂,需要转换后才能读懂。可以先不配置transforms内容运行看效果,这样有利于理解原始数据结构。
io.debezium.transforms.UnwrapFromEnvelope目的是将原始数据的Envelope格式内容过滤掉,数据的payload内容是最终同步到es的数据内容。
transforms.unwrap.drop.tombstones=true 必须是true否则会同步一条message是空的数据,空的数据不容易解析(无论你同步后的数据是什么,格式什么样,只要从kafka读取的插件能读懂就行,但是message是空的记录kafka-connect-elasticsearch是不能直接被读不懂的,是会报错的)
transforms.unwrap.delete.handling.mode=none 意思是对于数据库的删除操作,如何处理。在这里我们有两种方式可以选择,
1、配置none,这时payload数据将被转换成null,kafka-connect-elasticsearch对于null的数据执行删除。即找到Kafka key对应于es索引_id对应的记录,执行索引删除。这样就实现了es与mysql删除操作同步的效果。
2、配置rewrite,这时payload会增加一个字段__deleted,如果mysql执行删除,这个字段是true,执行插入和更新,这个字段是false。es可以根据__deleted是 true 或是 false 来判别此记录是否在mysql中被删除了。
transforms.changetopic.type=org.apache.kafka.connect.transforms.RegexRouter
transforms.changetopic.regex=(.*)
transforms.changetopic.replacement:$1-smt
是生成对应topic的规则。
debezium的其他配置可以参看文档 https://docs.confluent.io/current/connect/debezium-connect-mysql/mysql_source_connector_config.html
transforms的配置要看使用那个包了。confluent提供的包如下
https://docs.confluent.io/current/connect/transforms/index.html
5、下载confluent, https://www.confluent.io/download,下载 Self-managed software免费版
6、下载后 查看confluent目录/share/java/kafka-connect-elasticsearch,将kafka-connect-elasticsearch目录拷贝到第1步
设置的plugin.path=/data/soft/kafka_2.12-2.5.0/plugins目录内。
或运行confluent的bin目录下的 confluent-hub install confluentinc/kafka-connect-elasticsearch:latest下载最新包。获取后拷贝到相应目录下。
7、在config目录下建立es-sink.properties文件并配置如下信息。
name=es-sink
connector.class=io.confluent.connect.elasticsearch.ElasticsearchSinkConnector
tasks.max=1
topics=mysql.users.users_temp-smt
key.ignore=false
write.method=upsert
connection.url=http://192.198.30.22:9200
type.name=es_sink
behavior.on.null.values=delete
transforms= key
transforms.key.type=org.apache.kafka.connect.transforms.ExtractField$Key
transforms.key.field=id
配置说明
topics=mysql.users.user-smt 同步到es的kafka topic
key.ignore=false 必须配置false,否则es生成的_id不是mysql表的id,这样是不能实现更新和删除的,网上很多配置是true,是没有意义的,只能做一次同步而已,不是我们所要的生产效果。
write.method=upsert
connection.url=http://192.198.30.22:9200
type.name=es_sink
behavior.on.null.values=delete 对于payload是null的处理,这里配置为delete,即es对应_id的数据执行删除。
transforms= key
transforms.key.type=org.apache.kafka.connect.transforms.ExtractField$Key
transforms.key.field=id 指定同步过来的字段那个字段是主键,主键将成为索引的_id值,即实现更新和删除。
8、启动服务 在Kafka目录下执行 bin/connect-standalone.sh config/connect-standalone.properties config/mysql-source.properties config/es-sink
集群模式启动connect-distributed.sh和相应的properties配置文件。
9、如果没报错,启动后查看运行状态
http://192.188.2.59:8083/connectors查看启动的所有connector服务
http://192.188.2.59:8083/connectors/服务名称/status 查看每个服务的状态。