Flink进阶篇-CDC 原理、实践和优化&采集到Doris中

简介

基于doris官方用doris构建实时仓库的思路,从flinkcdc到doris实时数仓的实践。

原文 

Apache Flink X Apache Doris 构建极速易用的实时数仓架构 (qq.com)

前提-Flink CDC 原理、实践和优化

CDC 是什么

CDC 是变更数据捕获(Change Data Capture)技术的缩写,它可以将源数据库(Source)的增量变动记录,同步到一个或多个数据目的(Sink)。在同步过程中,还可以对数据进行一定的处理,例如分组(GROUP BY)、多表的关联(JOIN)等。

例如对于电商平台,用户的订单会实时写入到某个源数据库;A 部门需要将每分钟的实时数据简单聚合处理后保存到 Redis 中以供查询,B 部门需要将当天的数据暂存到 Elasticsearch 一份来做报表展示,C 部门也需要一份数据到 ClickHouse 做实时数仓。随着时间的推移,后续 D 部门、E 部门也会有数据分析的需求,这种场景下,传统的拷贝分发多个副本方法很不灵活,而 CDC 可以实现一份变动记录,实时处理并投递到多个目的地。

下图是一个示例,通过腾讯云 Oceanus 提供的 Flink CDC 引擎,可以将某个 MySQL 的数据库表的变动记录,实时同步到下游的 Redis、Elasticsearch、ClickHouse 等多个接收端。这样大家可以各自分析自己的数据集,互不影响,同时又和上游数据保持实时的同步。

CDC 的实现原理

通常来讲,CDC 分为主动查询事件接收两种技术实现模式。

对于主动查询而言,用户通常会在数据源表的某个字段中,保存上次更新的时间戳或版本号等信息,然后下游通过不断的查询和与上次的记录做对比,来确定数据是否有变动,是否需要同步。这种方式优点是不涉及数据库底层特性,实现比较通用;缺点是要对业务表做改造,且实时性不高,不能确保跟踪到所有的变更记录,且持续的频繁查询对数据库的压力较大。

事件接收模式可以通过触发器(Trigger)或者日志(例如 Transaction log、Binary log、Write-ahead log 等)来实现。当数据源表发生变动时,会通过附加在表上的触发器或者 binlog 等途径,将操作记录下来。下游可以通过数据库底层的协议,订阅并消费这些事件,然后对数据库变动记录做重放,从而实现同步。这种方式的优点是实时性高,可以精确捕捉上游的各种变动;缺点是部署数据库的事件接收和解析器(例如 Debezium、Canal 等),有一定的学习和运维成本,对一些冷门的数据库支持不够。

综合来看,事件接收模式整体在实时性、吞吐量方面占优,如果数据源是 MySQL、PostgreSQL、MongoDB 等常见的数据库实现,建议使用 Debezium 来实现变更数据的捕获(下图来自 Debezium 官方文档)。如果使用的只有 MySQL,则还可以用 Canal

从上图可以看到,Debezium 官方架构图中,是通过 Kafka Streams 直接实现的 CDC 功能。而我们这里更建议使用 Flink CDC 模块,因为 Flink 相对 Kafka Streams 而言,有如下优势:

  • Flink 的算子和 SQL 模块更为成熟和易用
  • Flink 作业可以通过调整算子并行度的方式,轻松扩展处理能力
  • Flink 支持高级的状态后端(State Backends),允许存取海量的状态数据
  • Flink 提供更多的 Source 和 Sink 等生态支持
  • Flink 有更大的用户基数和活跃的支持社群,问题更容易解决
  • Flink 的开源协议允许云厂商进行全托管的深度定制,而 Kafka Streams 只能自行部署和运维

而且 Flink Table / SQL 模块将数据库表和变动记录流(例如 CDC 的数据流)看做是同一事物的两面,因此内部提供的 Upsert 消息结构(+I 表示新增、-U 表示记录更新前的值、+U 表示记录更新后的值,-D 表示删除)可以与 Debezium 等生成的变动记录一一对应

目前 Flink CDC 支持两种数据源输入方式。

输入 Debezium 等数据流进行同步

例如 MySQL -> Debezium -> Kafka -> Flink -> PostgreSQL。适用于已经部署好了 Debezium,希望暂存一部分数据到 Kafka 中以供多次消费,只需要 Flink 解析并分发到下游的场景。

在该场景下,由于 CDC 变更记录会暂存到 Kafka 一段时间,因此可以在这期间任意启动/重启 Flink 作业进行消费;也可以部署多个 Flink 作业对这些数据同时处理并写到不同的数据目的(Sink)库表中,实现了 Source 变动与 Sink 的解耦。 

CREATE TABLE `Data_Input` (
    id BIGINT,
    actor VARCHAR,
    alias VARCHAR,
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
    'connector' = 'kafka',                             -- 可选 'kafka','kafka-0.11'. 注意选择对应的内置  Connector
    'topic' = 'YourDebeziumTopic',                     -- 替换为您要消费的 Topic
    'scan.startup.mode' = 'earliest-offset'            -- 可以是 latest-offset / earliest-offset / specific-offsets / group-offsets 的任何一种
    'properties.bootstrap.servers' = '10.0.1.2:9092',  -- 替换为您的 Kafka 连接地址
    'properties.group.id' = 'YourGroup',               -- 必选参数, 一定要指定 Group ID

    -- 定义数据格式 (Debezium JSON 格式)
    'format' = 'debezium-json',
    'debezium-json.schema-include' = 'false',
);

CREATE TABLE `Data_Output` (
    id BIGINT,
    actor VARCHAR,
    alias VARCHAR,
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
    'connector' = 'jdbc',
    'url' = 'jdbc:postgresql://postgresql.example:50060/myDatabase?currentSchema=mySchema&reWriteBatchedInserts=true', -- 请替换为您的实际 PostgreSQL 连接参数
    'table-name' = 'MyTable',   -- 需要写入的数据表
    'username' = 'user',        -- 数据库访问的用户名(需要提供 INSERT 权限)
    'password' = 'helloworld'   -- 数据库访问的密码
);

INSERT INTO `Data_Output` SELECT * FROM `Data_Input`;

如果在流计算 Oceanus 界面上,可以勾选 kafkajdbc 两个内置的 Connector:

随后直接开始运行作业,Flink 就会源源不断的消费 YourDebeziumTopic 这个 Kafka 主题中 Debezium 写入的记录,然后输出到下游的 MySQL 数据库中,实现了数据同步。

直接对接上游数据库进行同步

我们还可以跳过 Debezium 和 Kafka 的中转,使用 Flink CDC Connectors 对上游数据源的变动进行直接的订阅处理。从内部实现上讲,Flink CDC Connectors 内置了一套 Debezium 和 Kafka 组件,但这个细节对用户屏蔽,因此用户看到的数据链路如下图所示:

用法示例

同样的,这次我们有个 MySQL 数据库,需要实时将内容同步到 PostgreSQL 中。但我们没有也不想安装 Debezium 等额外组件,那我们可以新建一个 Flink SQL 作业,然后输入如下 SQL 代码(连接参数都是虚拟的,仅供参考):

CREATE TABLE `Data_Input` (
    id BIGINT,
    actor VARCHAR,
    alias VARCHAR,
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
    'connector' = 'mysql-cdc',		-- 可选 'mysql-cdc' 和 'postgres-cdc'
    'hostname' = '192.168.10.22',   -- 数据库的 IP
    'port' = '3306',                -- 数据库的访问端口
    'username' = 'debezium',        -- 数据库访问的用户名(需要提供 SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT, SELECT, RELOAD 权限)
    'password' = 'hello@world!',    -- 数据库访问的密码
    'database-name' = 'YourData',   -- 需要同步的数据库
    'table-name' = 'YourTable'      -- 需要同步的数据表名
);

CREATE TABLE `Data_Output` (
    id BIGINT,
    actor VARCHAR,
    alias VARCHAR,
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
    'connector' = 'jdbc',
    'url' = 'jdbc:postgresql://postgresql.example:50060/myDatabase?currentSchema=mySchema&reWriteBatchedInserts=true', -- 请替换为您的实际 PostgreSQL 连接参数
    'table-name' = 'MyTable',   -- 需要写入的数据表
    'username' = 'user',        -- 数据库访问的用户名(需要提供 INSERT 权限)
    'password' = 'helloworld'   -- 数据库访问的密码
);

INSERT INTO `Data_Output` SELECT * FROM `Data_Input`;

 如果在流计算页面,可以选择内置的 mysql-cdcjdbc Connector:

注意

需要使用 Flink CDC Connectors 附加组件。腾讯云 Oceanus 已经自带了 MySQL-CDC Connector,如果自行部署的话,需要下载 jar 包并将其放入 Flink 的 lib 目录下。

访问数据库时,请确保连接的用户足够权限(PostgreSQL 用户看这里,MySQL 用户看这里

Debezium JSON 格式解析类探秘

flink-json 模块中的 org.apache.flink.formats.json.debezium.DebeziumJsonFormatFactory 是负责构造解析 Debezium JSON 格式的工厂类;同样地,org.apache.flink.formats.json.canal.CanalJsonFormatFactory 负责 Canal JSON 格式。这些类已经内置在 Flink 1.11 的发行版中,直接可以使用,无需附加任何程序包。

对于 Debezium JSON 格式而言,Flink 将具体的解析逻辑放在了 org.apache.flink.formats.json.debezium.DebeziumJsonDeserializationSchema#DebeziumJsonDeserializationSchema 类中。

上图表示 Debezium JSON 的一条更新(Update)消息,它表示上游已将 id=123 的数据更新,且字段内包含了更新前的旧值,以及更新后的新值。

那么,Flink 是如何解析并生成对应的 Flink 消息呢?我们看下这个类的 deserialize 方法:

GenericRowData before = (GenericRowData) payload.getField(0);	// 更新前的数据
GenericRowData after = (GenericRowData) payload.getField(1);	// 更新后的数据
String op = payload.getField(2).toString();						// 获取 "op" 字段的类型

if (OP_CREATE.equals(op) || OP_READ.equals(op)) {	// 如果是创建 (c) 或快照读取 (r) 消息
    after.setRowKind(RowKind.INSERT);				// 设置消息类型为新建 (+I)
    out.collect(after);								// 发送给下游
} else if (OP_UPDATE.equals(op)) {				// 如果是更新 (u) 消息
    before.setRowKind(RowKind.UPDATE_BEFORE);	// 把更新前的数据类型设置为撤回 (-U)
    after.setRowKind(RowKind.UPDATE_AFTER);		// 把更新后的数据类型设置为更新 (+U)
    out.collect(before);						// 发送两条数据给下游
    out.collect(after);
} else if (OP_DELETE.equals(op)) {		// 如果是删除 (d) 消息
    before.setRowKind(RowKind.DELETE);	// 将消息类型设置为删除 (-D)
    out.collect(before);				// 发送给下游
} else {
    ...	// 异常处理逻辑
}

从上述逻辑可以看出,对于每一种 Debezium 的操作码(op 字段的类型),都可以用 Flink 的 RowKind 类型来表示。对于插入 +I 和删除 D,都只需要一条消息即可;而对于更新,则涉及删除旧数据和写入新数据,因此需要 -U+U 两条消息来对应。

特别地,在 MySQL、PostgreSQL 等支持 Upsert(原子操作的 Update or Insert)语义的数据库中,通常前一个 -U 消息可以省略,只把后一个 +U 消息用作实际的更新操作即可,这个优化在 Flink 中也有实现。

因此可以看到,Debezium 到 Flink 消息的转换逻辑是非常简单和自然的,这也多亏了 Flink 先进的设计理念,很早就提出并实现了 Upsert 数据流和动态数据表之间的映射关系。

flink-connector-debezium 模块

我们在使用 Flink CDC Connectors 时,也会好奇它究竟是如何做到的不需要安装和部署外部服务就可以实现 CDC 的。当我们阅读 flink-connector-mysql-cdc 的源码时,可以看到它内部依赖了 flink-connector-debezium 模块,而这个模块将 Debezium Embedded 嵌入到了 Connector 中。

flink-connector-debezium 的数据源实现类为 com.alibaba.ververica.cdc.debezium.DebeziumSourceFunction,它集成了 Flink 中的 RichSourceFunction 并实现了 CheckpointedFunction 以支持快照保存状态。

通常而言,对于 SourceFunction,我们可以从它的 run 方法入手分析。它的核心代码如下:

this.engine = DebeziumEngine.create(Connect.class)
    .using(properties) // 初始化 Debezium 所需的参数
    .notifying(debeziumConsumer) // 收到批量的变更消息, 则 Debezium 会回调 DebeziumChangeConsumer 来反序列化并向下游输出数据
    .using(OffsetCommitPolicy.always())
    .using(
            (success, message, error) -> {
                if (!success && error != null) {
                    this.reportError(error);
                }
            })
    .build();
...
     executor.execute(engine);  // 向 Executor 提交 Debezium 线程以启动运行

可以看到,这个 SourceFunction 使用一些预先定义的参数,初始化了一个嵌入式的 DebeziumEngine(Java 的 Runnable),然后提交给线程池(executor)去执行。这个 Debezium 线程会批量接收 binlog 信息并回调传入的 debeziumConsumer 以反序列化消息并交给 Flink 来处理。本类的其他方法主要负责初始化状态和保存快照,这里略过。

这里我们再来看一下 DebeziumChangeConsumer 的实现,它的最核心的方法是 handleBatch 。当 Debezium 收到一批新的事件时,会调用这个方法来通知我们的 Connector 进行处理。这里有个 for 循环轮询的逻辑:

for (ChangeEvent<SourceRecord, SourceRecord> event : changeEvents) {	// 轮询各个事件
    SourceRecord record = event.value();
    if (isHeartbeatEvent(record)) {		// 如果时心跳包
        // 只更新当前 offset 信息, 然后继续(不进行实际处理)
        synchronized (checkpointLock) {
            debeziumOffset.setSourcePartition(record.sourcePartition());
            debeziumOffset.setSourceOffset(record.sourceOffset());
        }
        continue;
    }

    deserialization.deserialize(record, debeziumCollector);		// 反序列化这条消息

    if (isInDbSnapshotPhase) {	// 如果处于数据库快照期, 需要阻止 Flink 检查点(Checkpoint)生成
        if (!lockHold) {
            MemoryUtils.UNSAFE.monitorEnter(checkpointLock);
            lockHold = true;
            ...
        }
        if (!isSnapshotRecord(record)) {	// 如果已经不在数据库快照期了, 就释放锁, 允许 Flink 正常生成检查点(Checkpoint)
            MemoryUtils.UNSAFE.monitorExit(checkpointLock);
            isInDbSnapshotPhase = false;
            ...
        }
    }

	// 更新当前 offset 信息, 并向下游 Flink 算子发送数据
    emitRecordsUnderCheckpointLock(
        debeziumCollector.records, record.sourcePartition(), record.sourceOffset());
}

可以看到逻辑比较简单,只需要关注 checkpointLock 这个对象:只有持有这个对象的锁时,才允许 Flink 进行检查点的生成。

当作业处于数据库快照期(即作业刚启动时,需全量同步源数据库的一份完整快照,此时收到的数据类型是 Debezium 的 SnapshotRecord),则不允许 Flink 进行 Checkpoint 即检查点的生成,以避免作业崩溃恢复后状态不一致;同样地,如果正在向下游算子发送数据并更新 offset 信息时,也不允许快照的进行。这些操作都是为了保证 Exacly-Once(精确一致)语义。

这里也解释了在作业刚启动时,如果数据库较大(同步时间较久),Flink 刚开始的 Checkpoint 永远失败(超时)的原因:只有当 Flink 完整同步了全量数据后,才可以进行增量数据的处理,以及 Checkpoint 的生成。

flink-connector-mysql-cdc 模块

而对于 flink-connector-mysql-cdc 模块而言,它主要涉及到 MySQLTableSource 的声明和实现。

我们知道,Flink 是通过 Java 的 SPI(Service Provider Interface)机制动态加载 Connector 的,因此我们首先看这个模块的 src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory 文件,里面内容指向 com.alibaba.ververica.cdc.connectors.mysql.table.MySQLTableSourceFactory

打开这个工厂类,我们可以看到它定义了该 Connector 所需的参数,例如 MySQL 数据库的用户名、密码、表名等信息,并负责 MySQLTableSource 实例的具体创建,而 MySQLTableSource 类对这些参数做转换,最终会生成一个上文提到的 DebeziumSourceFunction 对象。

因此我们可以发现,这个模块作用是一个 MySQL 参数的封装和转换层,最终的逻辑实现仍然是由 flink-connector-debezium 完成的。

MySQL CDC 常见问题 & 优化(重点Maxwell如果不设置成Full,那么update就可能没有old数据)

由于 Flink 的 CDC 功能还比较新(1.11 版本刚开始支持,1.12 版本逐步完善),因而在应用过程中,很可能会遇到有各种问题。鉴于大多数客户的数据源都是 MySQL,我们这里整理了客户常见的一些问题和优化方案,希望能够帮助到大家。

Debezium 报错:binlog probably contains events generated with statement or mixed based replication format 或 The MySQL server is not configured to use a FULL binlog_row_image

当前的 Binlog 格式被设置为了 STATEMENT 或者 MIXED, 这两种都不被 Debezium 支持。为了使用 Flink CDC 功能,需要把 MySQL 的 binlog-format 设置为 ROW

SET GLOBAL binlog_format = 'ROW';
SET GLOBAL binlog_row_image = 'FULL';

如果您使用的是腾讯云的 TencentDB for MySQL,请确认下面设置:

Debezium 报错:User does not have the 'LOCK TABLES' privilege required to obtain a consistent snapshot 或 Access denied; you need (at least one of) the SUPER, REPLICATION CLIENT privilege(s)

请对作业中指定的 MySQL 用户赋予如下权限:SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT,例如:

GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO '用户名' IDENTIFIED BY '密码';
FLUSH PRIVILEGES;

 如果您使用的数据库不允许或者不希望使用 RELOAD 进行全局锁,则还需要授予 LOCK TABLES 权限以令 Debezium 尝试进行表级锁。注意,表级锁会导致更长的数据库锁定时间!

如果希望彻底跳过锁(对数据的一致性要求不高,但要求数据库不能被锁),则可以在 WITH 参数中设置 'debezium.snapshot.locking.mode' = 'none' 参数来跳过锁操作。但请注意,同步过程中千万不要随意变更库表的结构。

前文讲过,Flink CDC Connector 在初始的全量快照同步阶段,会屏蔽掉快照的执行,因此如果 Flink Checkpoint 需要执行的话,就会因为一直无法获得 checkpointLock 对象的锁而超时。

可以设置 Flink 的 execution.checkpointing.tolerable-failed-checkpoint 参数以容忍更多的 Checkpoint 失败事件,同时可以调大 Checkpoint 周期,避免作业因 Checkpoint 失败而一直重启。

JDBC Sink 批量写入时,数据会缺失几条

如果发现数据库中的某些数据在 CDC 同步后有缺失,请确认是否仍在使用 Flink 旧版 1.10 的 Flink SQL WITH 语法(例如 WITH 参数中的 connector.type旧语法connector新语法)。

旧版语法的 Connector 在 JDBC 批量写入 Upsert 数据(例如数据库的更新记录)时,并未考虑到 Upsert 与 Delete 消息之间的顺序关系,因此会出现错乱的问题,请尽快迁移到新版的 Flink SQL 语法。

异常数据造成作业持续重启

默认情况下,如果遇到异常的数据(例如消费的 Kafka topic 在无意间混入了其他数据),Flink 会立刻崩溃重启,然后从上个快照点(Checkpoint)重新消费。由于某条异常数据的存在,作业会永远因为异常而重启。可以在 WITH 参数中加入 'debezium-json.ignore-parse-errors' = 'true' 来应对这个问题。

上游 Debezium 崩溃导致写入重复数据,结果不准

Debezium 服务端发生异常并恢复后,由于可能没有及时记录崩溃前的现场,可能会退化为 At least once 模式,即同样的数据可能被发送多次,造成下游结果不准确。

为了应对这个问题,新版的 Flink 1.12 增加了一个 table.exec.source.cdc-events-duplicate 配置项(可以编辑 flink-conf.yaml 文件来配置),建议将其设置为 true 以对这些重复数据进行去重。

但是需要注意,该选项需要数据源表定义了主键,否则也无法进行去重操作。

未来展望

在 Flink 1.11 版本中,CDC 功能首次被集成到内核中。由于 Flink 1.11.0 版本有个 严重 Bug 造成 Upsert 数据无法写入下游,我们建议使用 1.11.1 及以上版本。

在 1.12 版本上,Flink 还在配置项中增加了前文提到的 table.exec.source.cdc-events-duplicate 等选项以更好地支持 CDC 去重;还支持 Avro 格式的 Debezium 数据流,而不仅仅限于 JSON 了。另外,这个版本增加了对 Maxwell 格式的 CDC 数据流支持,

为了更好地完善 CDC 功能模块,Flink 社区创建了 FLINK-18822 以追踪关于该模块的进展。可以从中看到,Flink 1.13 主要着力于支持更多的类型(FLINK-18758),以及允许从 Debezium Avro、Canal 等数据流中读取一些元数据信息等。

而在更远的规划中,Flink 还可能支持基于 CDC 的内存数据库缓存,这样我们可以在内存中动态地 JOIN 一个数据库的副本,而不必每次都查询源库,这将极大地提升作业的处理能力,并降低数据库的查询压力。

参考文章

Flink CDC 原理、实践和优化 - 腾讯云开发者社区-腾讯云

FlinkCDC-MySql到Doris

FlinkCDC将MySQL接入Doris实战_wangleigiser的博客-CSDN博客

基于Flink CDC 和 Doris Connector 实现 MySQL分库分表数据数据实时入Doris - 知乎

Doris构建简易实时数仓 

Apache Flink X Apache Doris 构建极速易用的实时数仓架构 (qq.com)

简易版实时数仓模板 

CREATE TABLE demo_order_info (
  `order_info` STRING,
  `id` INT NOT NULL,
  primary key(id) NOT ENFORCED
) WITH ( 
  'connector' = 'mysql-cdc', 
  'hostname' = 'ip', 
  'port' = '3306', 
  'username' = '账号', 
  'password' = '密码', 
  'database-name' = '数据库', 
  'table-name' = '表名'
);

CREATE TABLE demo_order_info_detail (
  `id` int,
  `order_info_id` int,
  `order_info_detail` STRING,
  primary key(id) NOT ENFORCED
) WITH ( 
  'connector' = 'mysql-cdc', 
  'hostname' = 'ip', 
  'port' = '3306', 
  'username' = '用户', 
  'password' = '密码', 
  'database-name' = '数据库', 
  'table-name' = '表名'
);

CREATE TABLE cdc_doris_sink (
  `order_info_detail_id` int,
  `order_info_id` int,
  `order_info` STRING,
  `order_info_detail_id_order_id` int,
  `order_info_detail` STRING
) 
WITH (
  'connector' = 'doris',
  'fenodes' = 'ip',
  'table.identifier' = '数据库.表',
  'username' = '账号',
  'password' = '密码',
  'sink.properties.two_phase_commit'='true',
  'sink.label-prefix'='doris_demo_emp_003',
  'sink.properties.format' = 'json',
  'sink.properties.read_json_by_line' = 'true',
  'sink.enable-delete' = 'true'
);

insert into cdc_doris_sink
select demo_order_info_detail.id,demo_order_info.id,demo_order_info.order_info,demo_order_info_detail.order_info_id,demo_order_info_detail.order_info_detail from  demo_order_info_detail
INNER join demo_order_info
on demo_order_info.id=demo_order_info_detail.order_info_id;


等值连接里面order_info和order_detail(doris建表用的是order_detail_id作为唯一),不修改他们的id的情况下,修改其他的都是能够正常使用的
也就是修改他们的字段都能够同步过来。
添加也能够同步过来。
删除也能够同时删除dwd的表。
删除以后,后面来的数据也没有关联出来。
比如我删除了订单2
insert into lecangs_tiktok_analyze.`demo_order_info_detail` values(7,2,'wo shi chongqi de ') ;
dwd里面的表没有出来。
然后添加订单。
insert into lecangs_tiktok_analyze.`demo_order_info` (id,order_info) values(2,'orderinfo2') ; 
成功出结果
根据checkpoing重启以后的结果(从savepoint重启不用修改'sink.label-prefix'='doris_demo_emp_003')
insert into lecangs_tiktok_analyze.`demo_order_info_detail` values(8,3,'wo shi chongqi de ') ;
#修改订单id的情况。
update demo_order_info set id='11' where id='1';
#然后添加一条指向11的数据
insert into lecangs_tiktok_analyze.`demo_order_info_detail` values(9,11,'wo shi hou mian jia de 11') ;

#然后修改下order_detail的id
update demo_order_info_detail set id='11' where id='9';

上面应该还有落一层到ods,由于时间关系我直接从cdc到dwd了,应该是mysqlcdc-ods_dors,然后mysqlcdc表关联到dwd_doris
##################增,删,改都能够同步到下游###########################

大佬博客

https://hf200012.github.io/2021/10/Apache-Doris-Flink-Connector%E8%AE%BE%E8%AE%A1%E6%96%B9%E6%A1%88/

Demo:基于 Flink SQL 构建流式应用 | Jark's Blog 

https://github.com/wuchong/flink-sql-demo/blob/master/docker-compose.yml 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
课程总体架构请观看89讲。数据仓库是一个面向主题的、集成的、随时间变化的、但信息本身相对稳定的数据集合,用于对管理决策过程的支持。数据仓库的应用有:1.数据分析、数据挖掘、人工智能、机器学习、风险控制、无人驾驶。2.数据化运营、精准运营。3.广告精准、智能投放等等。数据仓库是伴随着企业信息化发展起来的,在企业信息化的过程,随着信息化工具的升级和新工具的应用,数据量变的越来越大,数据格式越来越多,决策要求越来越苛刻,数据仓库技术也在不停的发展。数据仓库有两个环节:数据仓库的构建与数据仓库的应用。随着IT技术走向互联网、移动化,数据源变得越来越丰富,在原来业  务数据库的基础上出现了非结构化数据,比如网站log,IoT设备数据,APP埋点数据等,这些数据量比以往结构化的数据大了几个量级,对ETL过程、存储都提出了更高的要求。互联网的在线特性也将业务需求推向了实时化 ,随时根据当前客户行为而调整策略变得越来越常见,比如大促过程库存管理,运营管理等(即既有远期策略型,也有短期操作型)。同时公司业务互联网化之后导致同时服务的客户剧增,有些情况人工难以完全处理,这就需要机器 自动决策 。比如欺诈检测和用户审核。总结来看,对数据仓库的需求可以抽象成两方面: 实时产生结果、处理和保存大量异构数据。本课程基于真实热门的互联网电商业务场景为案例讲解,结合分层理论和实战对数仓设计进行详尽的讲解,基于Flink+DorisDB实现真正的实时数仓,数据来及分析,实时报表应用。具体数仓报表应用指标包括:实时大屏分析、流量分析、订单分析、商品分析、商家分析等,数据涵盖全端(PC、移动、小程序)应用,与互联网企业大数据技术同步,让大家能够学到大数据企业级实时数据仓库的实战经验。本课程包含的技术: 开发工具为:IDEA、WebStorm Flink 1.11.3Hadoop 2.7.5Hive 2.2.0ZookeeperKafka 2.1.0、Spring boot 2.0.8.RELEASESpring Cloud Finchley.SR2Flume 、Hbase 2.2.6DorisDB 0.13.9、RedisVUE+jQuery+Ajax+NodeJS+ElementUI+Echarts+Datav等课程亮点: 1.与企业接轨、真实工业界产品2.DorisDB高性能分布式数据库3.大数据热门技术Flink最新版4.真正的实时数仓以及分层设计5.海量数据大屏实时报表6.数据分析涵盖全端(PC、移动、小程序)应用7.主流微服务后端系统8.数据库实时同步解决方案9.涵盖主流前端技术VUE+jQuery+Ajax+NodeJS+ElementUI+Echarts+Datav10.集成SpringCloud实现统一整合方案11.互联网大数据企业热门技术栈12.支持海量数据的实时数仓报表分析13.支持全端实时实时数仓报表分析14.全程代码实操,提供全部代码和资料 15.提供答疑和提供企业技术方案咨询企业一线架构师讲授,代码在老师的指导下企业可以复用,提供企业解决方案。  版权归作者所有,盗版将进行法律维权。 
上层应用业务对实时数据的需求,主要包含两部分内容:1、 整体数据的实时分析。2、 AB实验效果的实时监控。这几部分数据需求,都需要进行的下钻分析支持,我们希望能够建立统一的实时OLAP数据仓库,并提供一套安全、可靠的、灵活的实时数据服务。目前每日新增的曝光日志达到几亿条记录,再细拆到AB实验更细维度时,数据量则多达上百亿记录,多维数据组合下的聚合查询要求秒级响应时间,这样的数据量也给团队带来了不小的挑战。OLAP层的技术选型,需要满足以下几点:1:数据延迟在分钟级,查询响应时间在秒级2:标准SQL交互引擎,降低使用成本3:支持join操作,方便维度增加属性信息4:流量数据可以近似去重,但订单行要精准去重5:高吞吐,每分钟数据量在千W级记录,每天数百亿条新增记录6:前端业务较多,查询并发度不能太低通过对比开源的几款实时OLAP引擎,可以发现Doris和ClickHouse能够满足上面的需求,但是ClickHouse的并发度太低是个潜在的风险,而且ClickHouse的数据导入没有事务支持,无法实现exactly once语义,对标准SQL的支持也是有限的。所以针对以上需求Doris完全能解决我们的问题,DorisDB是一个性能非常高的分布式、面向交互式查询的分布式数据库,非常的强大,随着互联网发展,数据量会越来越大,实时查询需求也会要求越来越高,DorisDB人才需求也会越来越大,越早掌握DorisDB,以后就会有更大的机遇。本课程基于真实热门的互联网电商业务场景为案例讲解,具体分析指标包含:AB版本分析,下砖分析,营销分析,订单分析,终端分析等,能承载海量数据的实时分析,数据分析涵盖全端(PC、移动、小程序)应用。整个课程,会带大家实践一个完整系统,大家可以根据自己的公司业务修改,既可以用到项目去,价值是非常高的。本课程包含的技术:开发工具为:IDEA、WebStormFlink1.9.0DorisDBHadoop2.7.5Hbase2.2.6Kafka2.1.0Hive2.2.0HDFS、MapReduceFlume、ZookeeperBinlog、Canal、MySQLSpringBoot2.0.8.RELEASESpringCloud Finchley.SR2Vue.js、Nodejs、Highcharts、ElementUILinux Shell编程等课程亮点:1.与企业接轨、真实工业界产品2.DorisDB高性能分布式数据库3.大数据热门技术Flink4.支持ABtest版本实时监控分析5.支持下砖分析6.数据分析涵盖全端(PC、移动、小程序)应用7.主流微服务后端系统8.天级别与小时级别多时间方位分析9.数据库实时同步解决方案10.涵盖主流前端技术VUE+jQuery+Ajax+NodeJS+ElementUI11.集成SpringCloud实现统一整合方案12.互联网大数据企业热门技术栈13.支持海量数据的实时分析14.支持全端实时数据分析15.全程代码实操,提供全部代码和资料16.提供答疑和提供企业技术方案咨询企业一线架构师讲授,代码在老师的指导下企业可以复用,提供企业解决方案。  版权归作者所有,盗版将进行法律维权。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

工作变成艺术

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

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

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

打赏作者

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

抵扣说明:

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

余额充值