mysql kafka binlog_利用Binlog和Kafka实时同步mysql数据到Elasticsearch(三) - Binlog日志生产消息到Kafka...

该博客介绍了如何使用Binlog中间件监听MySQL的binlog,将变动数据转化为JSON格式并发送到Kafka队列,然后通过Kafka中间件将数据写入Elasticsearch。项目结构包括BinlogMiddleware和KafkaMiddleware,涉及的技术包括Mysql、Kafka和Elasticsearch。具体实现包括创建SpringBoot项目,配置binlog和Kafka参数,定义数据传输对象,以及实现binlog监听客户端。
摘要由CSDN通过智能技术生成

目录

前言

- 项目模块

BinlogMiddleware

1、binlog中间件,负责解析binlog,把变动的数据以json形式发送到kafka队列。

KafkaMiddleware

2、kafka中间件,负责消费kafka队列中的Message,把数据写入Elasticsearch中。

- 基础服务

(1)Mysql

(2)Kafka(用于存放mysql变动消息,存放于Kafka队列)

(3)Elasticsearch

- 项目源码

简介:

BinlogMiddleware服务主要负责监听Binlog日志,并将其发送到Kafka队列(及Kafka生产者)。

本示例模拟监听teemoliu数据库的user、role表。为了方便表结构设计的很简单,均只含有id、name两个属性。

中间件写进Kafka队列的消息格式如下:

{"event":"teemoliu.user.update","value":[1,"TeemoLiu"]}

{"event":"teemoliu.role.insert","value":[1,"管理员"]}

项目结构如下:

5acb30ec8347

image.png

1、创建SpringBoot项目。

5acb30ec8347

image.png

2、导入maven引用。

com.github.shyiko

mysql-binlog-connector-java

0.16.1

com.alibaba

fastjson

1.2.49

org.springframework.kafka

spring-kafka

org.apache.kafka

kafka-clients

1.1.1

3、配置文件如下:

# 停用服务端口

spring.main.web-environment=false

# binlog配置

server.id=1

binlog.host=localhost

binlog.port=3306

binlog.user=root

binlog.password=root

# 指定监听的表格

binlog.database.table=teemoliu.user,teemoliu.role

# kafka

spring.kafka.bootstrap-servers=localhost:9092

kafka.topic=binlog

kafka.partNum=3

kafka.repeatNum=1

4、创建Binlog数据传输对象

public class BinlogDto {

private String event;

private Object value;

public BinlogDto(String event, Object value) {

this.event = event;

this.value = value;

}

public BinlogDto() {

}

public String getEvent() {

return event;

}

public void setEvent(String event) {

this.event = event;

}

public Object getValue() {

return value;

}

public void setValue(Object value) {

this.value = value;

}

}

5、创建Kafka数据传输对象

public class Message {

private Long id;

private String msg;

private Date sendTime;

public Message(Long id, String msg, Date sendTime) {

this.id = id;

this.msg = msg;

this.sendTime = sendTime;

}

public Message() {

}

public Long getId() {

return id;

}

public void setId(Long id) {

this.id = id;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public Date getSendTime() {

return sendTime;

}

public void setSendTime(Date sendTime) {

this.sendTime = sendTime;

}

}

6、binlog监听BinlogClientRunner

@Component

public class BinlogClientRunner implements CommandLineRunner {

@Value("${binlog.host}")

private String host;

@Value("${binlog.port}")

private int port;

@Value("${binlog.user}")

private String user;

@Value("${binlog.password}")

private String password;

// binlog server_id

@Value("${server.id}")

private long serverId;

// kafka话题

@Value("${kafka.topic}")

private String topic;

// kafka分区

@Value("${kafka.partNum}")

private int partNum;

// Kafka备份数

@Value("${kafka.repeatNum}")

private short repeatNum;

// kafka地址

@Value("${spring.kafka.bootstrap-servers}")

private String kafkaHost;

// 指定监听的数据表

@Value("${binlog.database.table}")

private String database_table;

@Autowired

KafkaSender kafkaSender;

@Async

@Override

public void run(String... args) throws Exception {

// 创建topic

kafkaSender.createTopic(kafkaHost, topic, partNum, repeatNum);

// 获取监听数据表数组

List databaseList = Arrays.asList(database_table.split(","));

HashMap tableMap = new HashMap();

// 创建binlog监听客户端

BinaryLogClient client = new BinaryLogClient(host, port, user, password);

client.setServerId(serverId);

client.registerEventListener((event -> {

// binlog事件

EventData data = event.getData();

if (data != null) {

if (data instanceof TableMapEventData) {

TableMapEventData tableMapEventData = (TableMapEventData) data;

tableMap.put(tableMapEventData.getTableId(), tableMapEventData.getDatabase() + "." + tableMapEventData.getTable());

}

// update数据

if (data instanceof UpdateRowsEventData) {

UpdateRowsEventData updateRowsEventData = (UpdateRowsEventData) data;

String tableName = tableMap.get(updateRowsEventData.getTableId());

if (tableName != null && databaseList.contains(tableName)) {

String eventKey = tableName + ".update";

for (Map.Entry row : updateRowsEventData.getRows()) {

String msg = JSON.toJSONString(new BinlogDto(eventKey, row.getValue()));

kafkaSender.send(topic, msg);

}

}

}

// insert数据

else if (data instanceof WriteRowsEventData) {

WriteRowsEventData writeRowsEventData = (WriteRowsEventData) data;

String tableName = tableMap.get(writeRowsEventData.getTableId());

if (tableName != null && databaseList.contains(tableName)) {

String eventKey = tableName + ".insert";

for (Serializable[] row : writeRowsEventData.getRows()) {

String msg = JSON.toJSONString(new BinlogDto(eventKey, row));

kafkaSender.send(topic, msg);

}

}

}

// delete数据

else if (data instanceof DeleteRowsEventData) {

DeleteRowsEventData deleteRowsEventData = (DeleteRowsEventData) data;

String tableName = tableMap.get(deleteRowsEventData.getTableId());

if (tableName != null && databaseList.contains(tableName)) {

String eventKey = tableName + ".delete";

for (Serializable[] row : deleteRowsEventData.getRows()) {

String msg = JSON.toJSONString(new BinlogDto(eventKey, row));

kafkaSender.send(topic, msg);

}

}

}

}

}));

client.connect();

}

}

Spring Boot可以很方便地整合各种组件和框架,包括Elasticsearch、Canal和Kafka。下面简单介绍一下如何使用Spring Boot整合这个组件实现MySQL数据同步Elasticsearch的功能。 1. 集成Easy Elasticsearch 首先需要在pom.xml中引入Easy Elasticsearch的依赖: ``` <dependency> <groupId>com.jdon</groupId> <artifactId>easy-elasticsearch</artifactId> <version>1.0.0</version> </dependency> ``` 然后在application.properties中配置Elasticsearch的地址: ``` spring.elasticsearch.rest.uris=http://localhost:9200 ``` 2. 集成Canal Canal是阿里巴巴开源的一款MySQL数据增量订阅&消费组件,可以实时监听MySQLbinlog并将数据同步到其他存储介质,比如KafkaElasticsearch。 在pom.xml中引入Canal的依赖: ``` <dependency> <groupId>com.alibaba.otter</groupId> <artifactId>canal-client</artifactId> <version>1.1.5</version> </dependency> ``` 然后在application.properties中配置Canal的参数: ``` canal.server.host=localhost canal.server.port=11111 canal.destination=test canal.username= canal.password= ``` 3. 集成Kafka Kafka是一款分布式的消息队列,可以将数据异步地发送到其他系统或存储介质。 在pom.xml中引入Kafka的依赖: ``` <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.3.4.RELEASE</version> </dependency> ``` 然后在application.properties中配置Kafka的参数: ``` spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=test-group ``` 4. 实现数据同步 首先需要创建一个Canal客户端,实现Canal的监听器接口,监听到MySQLbinlog变化时将数据发送到Kafka。 ``` @Component public class CanalClient implements CanalEventListener { @Autowired private KafkaTemplate<String, String> kafkaTemplate; @Override public void onEvent(CanalEvent canalEvent) { List<CanalEntry.Entry> entries = canalEvent.getEntries(); for (CanalEntry.Entry entry : entries) { CanalEntry.EntryType entryType = entry.getEntryType(); if (entryType == CanalEntry.EntryType.ROWDATA) { CanalEntry.RowChange rowChange; try { rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue()); } catch (Exception e) { throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(), e); } if (rowChange != null) { String tableName = entry.getHeader().getTableName(); for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) { Map<String, String> dataMap = new HashMap<>(); for (CanalEntry.Column column : rowData.getAfterColumnsList()) { dataMap.put(column.getName(), column.getValue()); } kafkaTemplate.send(tableName, new Gson().toJson(dataMap)); } } } } } } ``` 然后创建一个Kafka消费者,将数据Kafka读取出来,再通过Easy Elasticsearch数据同步Elasticsearch。 ``` @Component public class KafkaConsumer { @Autowired private ElasticsearchTemplate elasticsearchTemplate; @KafkaListener(topics = "test") public void processMessage(String message) { Gson gson = new Gson(); Type type = new TypeToken<Map<String, String>>(){}.getType(); Map<String, String> dataMap = gson.fromJson(message, type); IndexQuery indexQuery = new IndexQueryBuilder() .withId(dataMap.get("id")) .withObject(dataMap) .build(); elasticsearchTemplate.index(indexQuery); } } ``` 最后启动Spring Boot应用程序,就能实现MySQL数据同步Elasticsearch的功能了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值