当前位置: 首页 > news >正文

Doris(六)--通过 Canal 同步数据到 Doris 中

pre 开启 mysql Binlog

网上有众多方法,自行百度。

查询是否成功,在 mysql 客户端输入

show BINARY LOGS;

出现如下提示,即表示 big log 正常开启。 

1,下载 canal 服务端

传送门

注意:下载 canal.deployer-xxx 版本即可。admin 是 deployer 的管理端。

2,上传到服务器的指定位置并解压

tar xzvf canal.deployer-1.1.6.tar.gz

注意,这个 deployer 解压之后直接是零散文件夹,建议先创建一个文件夹后,在这个文件夹里面进行解压

 3,配置实例

进入 conf 文件夹后,创建实例文件夹

cd conf/
mkdir test

从 example 文件夹中,拷贝instance.properties到当前文件夹

cp ../example/instance.properties .

 4,编辑实例文件

4.1 源数据库位置

//源数据位置
canal.instance.master.address=127.0.0.1:3306
//源数据 binlog 名字
canal.instance.master.journal.name=
//源数据 biglog 偏移量
canal.instance.master.position=

4.2 连接源数据库的用户名和密码

//连接源数据库用户名
canal.instance.dbUsername=canal
//连接源数据库密码
canal.instance.dbPassword=canal

4.3 编辑完,保存退出

5,编辑 canal 的配置文件

cd ..
vim canal.properties

5.1 加入新加的实例,已逗号分割

canal.destinations = example

6,部署客户端

这里客户端可以根据 canal 的 api 文档自行开发。

这里贴一些关键代码

{protected final static Logger logger = LoggerFactory.getLogger(CanalClientApplication.class);private static String ADDRESS = ConfigUtils.getConfigValue("application.properties", "canal.address");private static int PORT = Integer.parseInt(ConfigUtils.getConfigValue("application.properties", "canal.port"));private static String DESTINATION = ConfigUtils.getConfigValue("application.properties", "canal.destination");private static String USERNAME = ConfigUtils.getConfigValue("application.properties", "canal.username");private static String PASSWORD = ConfigUtils.getConfigValue("application.properties", "canal.password");private static String SUBSCRIBER = ConfigUtils.getConfigValue("application.properties", "canal.subscriber");public static void main(String args[]) {SpringApplication.run(CanalClientApplication.class,args);System.out.println("数据同步服务启动成功");// 创建链接logger.info("Trying to connect to " + ADDRESS + ":" + PORT);CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(ADDRESS,PORT), DESTINATION, USERNAME, PASSWORD);int batchSize = 1000;try {logger.info("...");connector.connect();logger.info("connected");connector.subscribe(SUBSCRIBER);connector.rollback();logger.info("CanalClient Application started successfully!");while (true) {Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据long batchId = message.getId();int size = message.getEntries().size();logger.info("当前 message 信息为:{}",message);if (batchId == -1 || size == 0) {try {Thread.sleep(1000);} catch (InterruptedException e) {}} else {DataProcessor.process(message.getEntries());}connector.ack(batchId); // 提交确认// connector.rollback(batchId); // 处理失败, 回滚数据}} catch (Exception e) {e.printStackTrace();logger.error("Canal Client exit with error.", e);System.exit(-2);} finally {connector.disconnect();}}}
{protected final static Logger logger = LoggerFactory.getLogger(DataProcessor.class);private static String DATABASE = ConfigUtils.getConfigValue("application.properties", "canal.database");private static String TABLE = ConfigUtils.getConfigValue("application.properties", "canal.table");private static String OPERATOR = ConfigUtils.getConfigValue("application.properties", "canal.operator");private static String CANAL_OUTPUT = ConfigUtils.getConfigValue("application.properties", "canal.output");private static DorisUtil dorisUtil;private static MySQLUtil mySQLUtil;public static void process(List<CanalEntry.Entry> entrys) {for (CanalEntry.Entry entry : entrys) {if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {continue;}CanalEntry.RowChange rowChage = null;try {rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());} catch (Exception e) {throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),e);}CanalEntry.EventType eventType = rowChage.getEventType();if (eventType == CanalEntry.EventType.TRUNCATE && OPERATOR.contains("TRUNCATE")) {if (StringUtils.isEmpty(DATABASE) ||(entry.getHeader().getSchemaName()!=null && isContain(DATABASE.split(","),entry.getHeader().getSchemaName()))) {if (StringUtils.isEmpty(TABLE) ||(entry.getHeader().getTableName() != null && isContain(TABLE.split(","), entry.getHeader().getTableName()))) {logger.info("TRUNCATE TABLE " + entry.getHeader().getTableName());if (CANAL_OUTPUT.contains("mysql")) {mySQLUtil = MySQLUtil.getInstance();try {mySQLUtil.mySQLTruncate(entry.getHeader().getSchemaName(), entry.getHeader().getTableName());} catch (SQLException e) {e.printStackTrace();logger.error("MySQL执行同步truncate出错,dataBase:" + entry.getHeader().getSchemaName() + ",table:" + entry.getHeader().getTableName());}}if (CANAL_OUTPUT.contains("doris")) {dorisUtil = DorisUtil.getInstance();try {dorisUtil.dorisTruncate(entry.getHeader().getSchemaName(), entry.getHeader().getTableName());} catch (SQLException e) {e.printStackTrace();logger.error("Doris执行同步truncate出错,dataBase:" + entry.getHeader().getSchemaName() + ",table:" + entry.getHeader().getTableName());}}}}}for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {// 过滤database, table, operatorif (StringUtils.isEmpty(DATABASE) ||(entry.getHeader().getSchemaName()!=null && isContain(DATABASE.split(","),entry.getHeader().getSchemaName()))) {if (StringUtils.isEmpty(TABLE) ||(entry.getHeader().getTableName()!=null && isContain(TABLE.split(","),entry.getHeader().getTableName()))) {if (CANAL_OUTPUT.contains("mysql")) {mySQLUtil = MySQLUtil.getInstance();try {if (eventType == CanalEntry.EventType.DELETE && OPERATOR.contains("DELETE")) {mySQLUtil.mySQLDelete(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getBeforeColumnsList());} else if (eventType == CanalEntry.EventType.INSERT && OPERATOR.contains("INSERT")) {mySQLUtil.mySQLInsert(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getAfterColumnsList());} else if (eventType == CanalEntry.EventType.UPDATE && OPERATOR.contains("UPDATE")) {mySQLUtil.mySQLUpdate(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getBeforeColumnsList(), rowData.getAfterColumnsList());} else {// nothing to do}} catch (SQLException e) {logger.error("MySQL执行同步" + eventType + "出错,dataBase:"+entry.getHeader().getSchemaName()+",table:"+entry.getHeader().getTableName(), e);}}if (CANAL_OUTPUT.contains("doris")) {dorisUtil = DorisUtil.getInstance();try {if (eventType == CanalEntry.EventType.DELETE && OPERATOR.contains("DELETE")) {dorisUtil.dorisDelete(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getBeforeColumnsList());} else if (eventType == CanalEntry.EventType.INSERT && OPERATOR.contains("INSERT")) {dorisUtil.dorisInsert(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getAfterColumnsList());} else if (eventType == CanalEntry.EventType.UPDATE && OPERATOR.contains("UPDATE")) {dorisUtil.dorisUpdate(entry.getHeader().getSchemaName(), entry.getHeader().getTableName(), rowData.getBeforeColumnsList(), rowData.getAfterColumnsList());} else {// nothing to do}} catch (SQLException e) {logger.error("MySQL执行同步" + eventType + "出错,dataBase:"+entry.getHeader().getSchemaName()+",table:"+entry.getHeader().getTableName(), e);}}}}}}}public static boolean isContain(String[] list, String value) {if (list == null || value == null) return false;for (String lv : list) {if (value.trim().equals(lv.trim())) {return true;}}return false;}private static void printColumn(String database, String table, List<CanalEntry.Column> columns) {for (CanalEntry.Column column : columns) {logger.info(database + "-" + table + "-" + column.getName() + " : " + column.getValue() + " update=" + column.getUpdated());}}}

7,启动 canal 服务端

在 canal 根目录下,执行如下命令

./bin/startup.sh 

8,启动 canal 客户端

因为我用的 jar,所以,启动 jar 包就行了。

9,待完成事项

1,doris 官方文档上有通过 binLog 同步数据到 doris 中的方法,这部分待实现。

2,当前客户端写法单一。一旦canal 服务端重启,应用自动停机。待优化。

相关文章:

Doris(六)--通过 Canal 同步数据到 Doris 中

pre 开启 mysql Binlog 网上有众多方法&#xff0c;自行百度。 查询是否成功&#xff0c;在 mysql 客户端输入 show BINARY LOGS; 出现如下提示&#xff0c;即表示 big log 正常开启。 1&#xff0c;下载 canal 服务端 传送门 注意&#xff1a;下载 canal.deployer-xxx …...

快手Java一面,全是基础

现在已经到了面试招聘比较火热的时候&#xff0c;准备面试的过程中&#xff0c;一定要多看面经&#xff0c;多自测&#xff01; 今天分享的是一位贵州大学的同学分享的快手一面面经。 快手一面主要会问一些基础问题&#xff0c;也就是比较简单且容易准备的常规八股&#xff0…...

未来芯片设计领域的药明康德——青芯如何在N个项目间游走平衡

总部位于上海张江的青芯半导体&#xff08;CyanSemi&#xff09;&#xff0c;ASIC定制设计是其核心业务之一。 青芯在单纯的设计服务维度之上&#xff0c;打造了从设计到生产的一套完整ASIC定制业务&#xff0c;不仅做芯片设计&#xff0c;还提供封装、测试服务&#xff0c;也…...

【跟小嘉学 Rust 编程】十九、高级特性

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

pandas由入门到精通-数据清洗-缺失值处理

pandas-02-数据清洗&预处理 A.缺失值处理1. Pandas缺失值判断2. 缺失值过滤2.1 Series.dropna()2.2 DataFrame.dropna()3. 缺失值填充3.1 值填充3.2 向前/向后填充文中用S代指Series,用Df代指DataFrame 数据清洗是处理大型复杂情况数据必不可少的步骤,这里总结一些数据清…...

Redis 教程 - 主从复制

Redis 教程 - 主从复制 Redis 支持主从复制&#xff08;Master-Slave Replication&#xff09;&#xff0c;通过主从复制可以将一个 Redis 服务器&#xff08;主节点&#xff09;的数据复制到其他 Redis 服务器&#xff08;从节点&#xff09;&#xff0c;以实现数据的冗余备份…...

[递归] 子集 全排列和组合问题

1.1 子集I 思路可以简单概括为 二叉树&#xff0c;每一次分叉要么选择一个元素&#xff0c;要么选择空&#xff0c;总共有n次&#xff0c;因此到n1进行保存结果&#xff0c;返回。像这样&#xff1a; #include <cstdio> #include <vector> #include <algorithm&…...

ELK安装、部署、调试(四)KAFKA消息队列的安装和部署

1.简介 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c;搜索和其他用户的行动&#xff09;是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通…...

半导体晶片机器视觉测量及MARK点视觉定位

半导体晶片机器视觉测量及MARK点视觉定位 客户的需求: 检测内容&#xff1a; SMT行业晶片位置角度与PCB板Mark点位置的测试测量 检测要求&#xff1a; 精度0.04mm&#xff0c;移动速度100mm/s 视觉可行性分析: 对样品进行了光学实验&#xff0c;并进行图像处理&#xff0c…...

ranger无法同步用户问题解决

1.首先就是定位日志,日志目录 cd /var/log/ranger/usersync 定位到问题报错如下: LdapDeltaUserGroupBuilder.getUsers() failed with exception:java.naming.AuthticationExceptiom :[LDAP:error code 49 - Invalid Credentials]:remaing name ‘ouPeople,dc*.dccom’ 解决办法…...

使用通信顺序进程(CSP)模型的 Go 语言通道

在并发编程中&#xff0c;许多编程语言采用共享内存/状态模型。然而&#xff0c;Go 通过实现 通信顺序进程&#xff08;CSP&#xff09;模型来区别于众多。在CSP中&#xff0c;程序由不共享状态的并行进程组成&#xff1b;相反&#xff0c;它们通过通道进行通信和同步操作。因此…...

VPN网关

阿里云VPN网关(VPN Gateway&#xff0c;简称VPN)是一款基于Internet&#xff0c;通过加密通道将企业数据中心、办公网或终端与专有网络(VPC) 安全可靠连接起来的服务。 VPN网关提供IPsec-VPN和SSL-VPN两种。 网络连接方式应用场景IPsec-VPN支持在企业本地数据中心、企业办公网…...

产品展示视频制作的要点

制作产品展示视频时通过精心策划的视频剧本和拍摄手法&#xff0c;可以准确地呈现活动的目的、主题和特点&#xff0c;让观众更好地理解和认同活动的意义。深圳产品活动视频制作公司老友记小编还为您整理了以下一些重要的制作要点&#xff1a; 1.明确目标受众&#xff1a;了解你…...

appium+python自动化测试

获取APP的包名 1、aapt即Android Asset Packaging Tool&#xff0c;在SDK的build-tools目录下。该工具可以查看apk包名和launcherActivity 2、在android-sdk里面双击SDK-manager,下载buidl-tools 3、勾选build-tools&#xff0c;随便选一个版本&#xff0c;我这里选的是24的版…...

【AI辅助办公】PDF转PPT,移除水印

PDF转PPT 将PDF上传链接即可转换成PPT。​​​​​​ ​​​​​​​ https://www.camscanner.com/pdftoppthttps://www.camscanner.com/pdftoppt​​​​​​​​​​​​​​移除水印 第一步&#xff1a;打开视图-宏 第二步&#xff1a;输入宏名&#xff08;可以是人以文字…...

ssm农业视频实时发布管理系统源码

ssm农业视频实时发布管理系统源码108 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm package com.controller;import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; impo…...

【100天精通python】Day48:python Web开发_WSGI接口与使用

目录 1 WSGI接口 1.1 CGI 简介 1.2 WSGI 简介 1.3 定义 WSGI 接口 1.3.1 应用程序&#xff08;Application&#xff09; 1.3.2 服务器&#xff08;Server&#xff09; 1.4 WSGI 接口的使用示例 1.5 WSGI接口的优势 1 WSGI接口 上一节实现了静态服务器&#xff0c;但是当…...

Understanding Lockup Cells

工具会分析扫描链和EDT逻辑之间的控制时序元素的时钟的时序关系,当必须要同步时钟并保持数据完整性时插入边沿触发寄存器(lockup cells)。 可以使用report_edt_lockup_cells命令来展示工具已经插入的lockup cells的详细报告。 Lockup Cell Insertion 工具会分析控制时序元…...

javaCV实现java图片ocr提取文字效果

引入依赖&#xff1a; <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version></dependency> 引入中文语言训练数据集&#xff1a;chi_sim GitHub - tesseract-ocr…...

七牛云OSS存储

前言: 七牛云的存储项目的附件,需要开发一套七牛云的工具类,可以使用该工具类进行七牛云服务器进行文件的上传与下载操作; 七牛云的文档学习: 相关的依赖项的配置: <dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

STM32标准库-ADC数模转换器

文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”&#xff1a;输入模块&#xff08;GPIO、温度、V_REFINT&#xff09;1.4.2 信号 “调度站”&#xff1a;多路开关1.4.3 信号 “加工厂”&#xff1a;ADC 转换器&#xff08;规则组 注入…...