canal实现mysql同步Elasticsearch数据&&linux中安装ELK

前言

在之前有说过在windows中安装elasticsearch和kibana 但是没有过多的介绍linux中使用 现在我想大部分的公司所使用的服务器都是linux,当然也不会排除少数的windows系统 刚好我这边之前在阿里云购买了一台linux服务器 在大数据时代 elasticsearch友好的帮助了查询上的优化 但是如果说我想要把mysql中的数据同步实现在elasticsearch中 那么可以用到一些工具来实现 比如elk中的logstation以及canal等。今天我将用canal来对mysql同步es的实现,所以我这边将不会介绍logstation的安装以及使用 将使用canal来替代。有想去了解的可以去其他地方查阅资料。

ElasticSearch安装

下载安装包&&添加es用户

首先下载很简单,直接步入官网选择系统即可,链接如下

https://www.elastic.co/cn/products/elasticsearch

下载后直接找一个文件夹下放入解压即可,我下载的是8.1.2版本的,解压指令我放入下面,下载好后添加一个es用户 指令也在下面,
注意:后面发现版本太高对JDK的有一定的要求,8以上的版本仅支持JDK17 故所有请尽量选择低版本es,我这里有6.6.0版本的链接,此链接支持1.8版本 最好使用此版本,步骤一致 只是我下面介绍的版本不同
请在下面的kibana也使用6.6.0版本!!!

https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-6-0
//cd到指定目录下解压
tar -zxvf elasticsearch-8.1.2-linux-x86_64.tar.gz

在这里插入图片描述

//添加es用户
useradd esroot
//设置密码
passwd esuser

上面的操作完成后说明你的准备工作已完成,下面进入解压后的config文件夹中 因为有两个地方需要修改一下

cd /java/es/elasticsearch-8.1.2/config

在这里插入图片描述

//elasticsearch.yml需要修改的地方
node.name: node-1 #配置当前es节点名称(默认是被注释的,并且默认有一个节点名)
cluster.name: my-   application #默认是被注释的,并且默认有一个集群名
path.data: /home/es/data # 数据目录位置
path.logs: /home/es/logs # 日志目录位置
network.host: 0.0.0.0   #绑定的ip:默认只允许本机访问,修改为0.0.0.0后则可以远程访问
cluster.initial_master_nodes: ["node-1","node-2"] #默认是被注释的 设置master节点列表 用逗号分隔

Elasticsearch基于Lucene的,而Lucene底层是java实现,因此我们需要配置jvm参数。编辑jvm.options
修改配置为
在这里插入图片描述
修改/etc/security/limits.conf文件 增加配置
vi /etc/security/limits.conf
在文件最后,增加如下配置:

* soft nofile 65536
* hard nofile 65536

在这里插入图片描述
wq!退出
在/etc/sysctl.conf文件最后添加一行 vm.max_map_count=655360 添加完毕之后,执行命令: sysctl -p

启动

上面这些完成后基本上就完成了es的安装。下面就看启动上了。既然是新用户,那么我们肯定要授权 将es文件夹下的所有目录的所有权限迭代给esuser用户

chgrp -R esroot ./es
chown -R esroot ./es
chmod 777 es

进入es文件夹下执行./bin/elasticsearch即可启动了,后台启动在执行后面加一个 -d即可也就是./bin/elasticsearch -d
注意:elasticSearch对系统配置有一定要求 我之前的1核2G已趟过浑水 启动后直接性能爆满 所以系统至少要在2核8G以上在尝试
在这里插入图片描述
后面我将服务器调至上面的2核8G的勉强还是可以运行起来的,我版本后面是更换至了7.6.1版本 因为我服务器的JDK是1.8的,所以只能是使用8以下的版本,访问成功!
在这里插入图片描述

ElasticSearch HEAD安装

下载&&安装

地址:

https://github.com/mobz/elasticsearch-head

解压

unzip elasticsearch-head.zip

配置

进入head文件下执行:

npm install

如果是执行报错在后面加一个-g即可

设置跨域

修改es的elasticsearch.yml文件

//进入查看文件
vim /java/elk/elasticsearch-7.6.1/config/elasticsearch.yml

//修改配置
#配置开启跨域
http.cors.enabled: true
#配置允许任何域名访问
http.cors.allow-origin: "*"

修改完es配置后需要重启es,切换es账号输入指令ps -ef|grep elasticsearch查看es的端口号
在这里插入图片描述
然后直接kill掉即可 执行./bin/elasticsearch -d指令启动es即可

启动ElasticSearch HEAD

在后台启动指令如下

nohup npm run start &

启动后可查看9100端口号
在这里插入图片描述
到这里可视化工具就安装好了 直接访问试试
在这里插入图片描述
注意:连接那里填入linux的ip,不然是连接本地

Kibana安装

下载&&安装

上面安装的elasticsearch也是7.6.1版本 所以kibana也是此版本 版本最好保持一致
下载地址:

https://www.elastic.co/cn/downloads/past-releases/kibana-7-6-1

解压

tar -zxvf kibana-7.6.1-linux-x86_64.tar.gz

修改以下三个地方

#kibana端口号
server.port: 5601
//远程连接要这个 不然远程连接不了
server.host: "0.0.0.0"
//ip
elasticsearch.hosts: ["http://这里写你的ip:9200"]

之前创建了一个esroot的用户 现在也要用这个用户来启动 如果非要root启动就要用以下指令

./kibana --allow-root

设置权限并启动

#文件权限
chown -R esroot /java/elk/kibana
# 转用户
su esroot
#在kibana的bin下执行指令(后台登陆 不后台登陆就不要&即可)
./bin/kibana &

启动后连接试试:

http://你的ip地址:5601/app/kibana

在这里插入图片描述

配置

canal安装

介绍

译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

基于日志增量订阅和消费的业务包括

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理
    在这里插入图片描述

mysql配置

对于自建 MySQL , 需要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下

[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复

注意:阿里云RDS for MySQL,默认打开了binlog,并且默认有binlog dump权限,没有任何权限binlog设置,可以跳过这一步

授权渠道 链接 MySQL 账户 作为 MySQL slave 的权限,如果现有账户可以直接授予

CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

重启mysql
一、 启动
使用 service 启动:service mysql start
二、停止

使用 service 启动:service mysql stop

三、重启
使用 service 启动:service mysql restart

下载&&安装

当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x
根据官方文档,目标系统支持MySQL、kafka、elasticsearch、hbase、rocketMQ、pulsar等。
下载路径:

https://github.com/alibaba/canal/releases

在这里插入图片描述
下载canal服务端(canal.deployer-1.1.4.tar.gz)和客户端(canal.adapter-1.1.4.tar.gz)

deployer测试

修改/deployer/conf/example目录下的instance.properties文件以下内容即可
在这里插入图片描述
然后进入bin目录下执行startup.sh即可开启

搭建SpringBoot框架&&引入依赖

在这里插入图片描述
引入依赖

<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.client</artifactId>
    <version>1.1.0</version>
</dependency>

ClientSample代码

ClientSample代码:https://github.com/alibaba/canal/wiki/ClientExample
上面链接是阿里巴巴给的源代码,也就是下面的代码 记得修改ip为adapter的

package com.example.canal.test;
import java.net.InetSocketAddress;
import java.util.List;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.common.utils.AddressUtils;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
/**
 * @author: Fujii
 * @date: 4/13/2022 8:19 PM
 * @description:
 */
public class SimpleCanalClientExample {


    public static void main(String args[]) {
        // 创建链接
        CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("这里填入adapter的ip",
                11111), "example", "", "");
        int batchSize = 1000;
        int emptyCount = 0;
        try {
            connector.connect();
            connector.subscribe(".*\\..*");
            connector.rollback();
            int totalEmptyCount = 120;
            while (emptyCount < totalEmptyCount) {
                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据
                long batchId = message.getId();
                int size = message.getEntries().size();
                if (batchId == -1 || size == 0) {
                    emptyCount++;
                    System.out.println("empty count : " + emptyCount);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                } else {
                    emptyCount = 0;
                    // System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);
                    printEntry(message.getEntries());
                }

                connector.ack(batchId); // 提交确认
                // connector.rollback(batchId); // 处理失败, 回滚数据
            }

            System.out.println("empty too many times, exit");
        } finally {
            connector.disconnect();
        }
    }

    private static void printEntry(List<Entry> entrys) {
        for (Entry entry : entrys) {
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
                continue;
            }

            RowChange rowChage = null;
            try {
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
                        e);
            }

            EventType eventType = rowChage.getEventType();
            System.out.println(String.format("================&gt; binlog[%s:%s] , name[%s,%s] , eventType : %s",
                    entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
                    entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
                    eventType));

            for (RowData rowData : rowChage.getRowDatasList()) {
                if (eventType == EventType.DELETE) {
                    printColumn(rowData.getBeforeColumnsList());
                } else if (eventType == EventType.INSERT) {
                    printColumn(rowData.getAfterColumnsList());
                } else {
                    System.out.println("-------&gt; before");
                    printColumn(rowData.getBeforeColumnsList());
                    System.out.println("-------&gt; after");
                    printColumn(rowData.getAfterColumnsList());
                }
            }
        }
    }

    private static void printColumn(List<Column> columns) {
        for (Column column : columns) {
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());
        }
    }

}

然后直接运行main,运行后我在一个测试表中添加一条数据试试
在这里插入图片描述
可在日志处观察到变更信息,标志着deployer监听mysql binlog变更成功
在这里插入图片描述
上面是deployer的效果 下面我们再来看看adapter

adapter测试

canal adapter 的 Elastic Search 版本支持6.x.x以上,adapter的目录和deployer很相似,主要需要修改的地方也是application.yml文件 yml文件对格式的要求很高 有一点偏差都会出现错误,所以我这边直接远程下载到本地使用notepad工具来编写 当然有能力的小伙伴也可以使用下面的指令进行编写,看自己的习惯吧,我个人比较喜欢下载到本地

vi /java/canal/adapter/conf/application.yml

下面是官方文档地址,也就是我下面这段yml文件。可以参考如下:

https://github.com/alibaba/canal/wiki/Sync-ES
server:
  port: 8081
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    default-property-inclusion: non_null
 
canal.conf:
  mode: tcp # 客户端的模式,可选tcp kafka rocketMQ
  flatMessage: true # 扁平message开关, 是否以json字符串形式投递数据, 仅在kafka/rocketMQ模式下有效
  zookeeperHosts:    # 对应集群模式下的zk地址
  syncBatchSize: 1000 # 每次同步的批数量
  retries: 0 # 重试次数, -1为无限重试
  timeout: # 同步超时时间, 单位毫秒
  accessKey:
  secretKey:
  consumerProperties:
    canal.tcp.server.host: 127.0.0.1:11111 #设置canal-server的地址
    canal.tcp.zookeeper.hosts:
    canal.tcp.batch.size: 500
    canal.tcp.username:
    canal.tcp.password:
  srcDataSources:
    defaultDS:
      url: jdbc:mysql://你的ip地址:3306/campus?useUnicode=true&charaterEncoding=utf-8&useSSL=false
      username: canal
      password: canal
  canalAdapters:
  - instance: example # canal instance Name or mq topic name
    groups:
    - groupId: g1
      outerAdapters:
      - name: logger
      - name: es6
        hosts: 你的ip地址:9200 # 127.0.0.1:9200 for rest mode
        properties:
          mode: rest # or rest
          security.auth: elastic:elastic #  only used for rest mode
          cluster.name: name #es名称

adapter将会自动加载 conf/es 下的所有.yml结尾的配置文件,不需要的文件可删除,只配置需要的yml文件。修改如下配置,esMapping信息,包括 index,type,sql,其中sql尽量保证不要换行,在文本编辑器中编辑成一行,在粘贴进去,否则可能会出问题(还是由于yml格式问题)
此处的sql的字段别名即是es字段名,不写别名,默认原名即是es字段名,有关详细说明,可参见官方文档

https://github.com/alibaba/canal/wiki/Sync-ES

etlCondition 可以注释掉,我们默认任何条件都同步

dataSourceKey: defaultDS # 源数据源的key, 对应上面配置的srcDataSources中的值
destination: example  # canal的instance或者MQ的topic
groupId: g1 # 对应MQ模式下的groupId, 只会同步对应groupId的数据
esMapping:
  _index: student # es 的索引名称
  _id: _id  # 将Mysql表里的id对应上es上的_id, 如果不配置该项必须配置下面的pk项_id则会由es自动分配
  _type: _doc
  upsert: true
  sql: "SELECT
         id AS _id,
         name,
         age
        FROM
         student"        # sql映射
  #etlCondition: "where p.id>={}"   #etl的条件参数
  commitBatch: 3000   # 提交批大小                       

编辑好yml文件后直接在文件夹下执行以下指令

bin/startup.sh

启动后如下图说明启动成功!
在这里插入图片描述
启动后可在mysql尝试插入数据 在adapter.log文件中查看到监听信息,下面先来在数据库添加一条数据试试

在这里插入图片描述
在这里插入图片描述

下面打开adapter.log的实时日志监控可以看到有信息输出出来,这里是有两条 第一条是监听读取mysql的数据 第二条是添加进入es的信息在这里插入图片描述
查看es 我这里用的head可视化工具 所以可以直接查看
在这里插入图片描述

问题

索引找不到

ESSyncService - sync error, es index: mytest_user

1.可能是es还没创建该索引
2.es版本号太高,目前canal支持7.以下的版本 所以最好是6.的版本

找不到es类型

ERROR c.a.o.c.client.adapter.es.core.monitor.ESConfigMonitor - esMapping._type

1.加上_type: _doc

目前我在配置中是遇到这两个问题,还是比较顺利吧 在版本号这里花了不少时间 后面在网上看了些资料才知道的 好了 这期就到这

多表SQL关联异常

java.lang.RuntimeException: java.lang.RuntimeException: com.alibaba.fastsql.sql.parser.ParserException

解决方案:关联的id加上即可

结束语
若要前行,就要离开你现在停留的地方!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

藤井大叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值