Flink CDC 2.0 实现原理剖析

在对于有主键的表做初始化模式,整体的流程主要分为5个阶段:

1.Chunk切分;

在这里插入图片描述

2.Chunk分配;(实现并⾏读取数据&CheckPoint)

在这里插入图片描述

3.Chunk读取;(实现⽆锁读取)

在这里插入图片描述

读取可以分为5个阶段
1)SourceReader读取表数据之前先记录当前的Binlog位置信息记为低位点;
2)SourceReader将⾃身区间内的数据查询出来并放置在buffer中;
3)查询完成之后记录当前的Binlog位置信息记为⾼位点;
4)在增量部分消费从低位点到⾼位点的Binlog(注意:在binlog读取阶段做);
5)根据主键,对buffer中的数据进⾏修正并输出(注意:在binlog读取阶段做)。
通过以上5个阶段可以保证每个Chunk最终的输出就是在⾼位点时该Chunk中最新的数据,但是⽬前只是做到了保
证单个Chunk中的数据⼀致性。

4.Chunk汇报;

在这里插入图片描述

5.Chunk分配;

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

 /**
  *  此过程 SourceRecord 上兵法执行,互不影响,假设一个任务同步三张表t1 /t2 / t3 被切分为 6 个切片,由于并发执行,其高低水位在binlog 上的位置的一种可能是
  * @param lowWatermarkEvent
 * @param highWatermarkEvent
 * @param snapshotRecords
 * @param binlogRecords
 * @return
 */
private static List<SourceRecord> upsertBinlog(
        SourceRecord lowWatermarkEvent,
        SourceRecord highWatermarkEvent,
        Map<Struct, SourceRecord> snapshotRecords,
        List<SourceRecord> binlogRecords) {
    // upsert binlog events to snapshot events of split
    if (!binlogRecords.isEmpty()) {
        for (SourceRecord binlog : binlogRecords) {
            Struct key = (Struct) binlog.key();
            Struct value = (Struct) binlog.value();
            if (value != null) {
                Envelope.Operation operation =
                        Envelope.Operation.forCode(
                                value.getString(Envelope.FieldName.OPERATION));
                switch (operation) {
                    case CREATE:
                    case UPDATE:
                        Envelope envelope = Envelope.fromSchema(binlog.valueSchema());
                        Struct source = value.getStruct(Envelope.FieldName.SOURCE);
                        Struct after = value.getStruct(Envelope.FieldName.AFTER);
                        Instant fetchTs =
                                Instant.ofEpochMilli(
                                        (Long) source.get(Envelope.FieldName.TIMESTAMP));
                        SourceRecord record =
                                new SourceRecord(
                                        binlog.sourcePartition(),
                                        binlog.sourceOffset(),
                                        binlog.topic(),
                                        binlog.kafkaPartition(),
                                        binlog.keySchema(),
                                        binlog.key(),
                                        binlog.valueSchema(),
                                        envelope.read(after, source, fetchTs));
                        snapshotRecords.put(key, record);
                        break;
                    case DELETE:
                        snapshotRecords.remove(key);
                        break;
                    case READ:
                        throw new IllegalStateException(
                                String.format(
                                        "Binlog record shouldn't use READ operation, the record is %s.",
                                        binlog));
                }
            }
        }
    }

    final List<SourceRecord> normalizedRecords = new ArrayList<>();
    normalizedRecords.add(lowWatermarkEvent);
    normalizedRecords.addAll(formatMessageTimestamp(snapshotRecords.values()));
    normalizedRecords.add(highWatermarkEvent);

    return normalizedRecords;
}

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

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

private MySqlBinlogSplit createBinlogSplit() {
        final List<MySqlSchemaLessSnapshotSplit> assignedSnapshotSplit =
                snapshotSplitAssigner.getAssignedSplits().values().stream()
                        .sorted(Comparator.comparing(MySqlSplit::splitId))
                        .collect(Collectors.toList());

        Map<String, BinlogOffset> splitFinishedOffsets =
                snapshotSplitAssigner.getSplitFinishedOffsets();
        final List<FinishedSnapshotSplitInfo> finishedSnapshotSplitInfos = new ArrayList<>();

        BinlogOffset minBinlogOffset = null;
        for (MySqlSchemaLessSnapshotSplit split : assignedSnapshotSplit) {
            // find the min binlog offset
            BinlogOffset binlogOffset = splitFinishedOffsets.get(split.splitId());
            if (minBinlogOffset == null || binlogOffset.isBefore(minBinlogOffset)) {
                minBinlogOffset = binlogOffset;
            }
            finishedSnapshotSplitInfos.add(
                    new FinishedSnapshotSplitInfo(
                            split.getTableId(),
                            split.splitId(),
                            split.getSplitStart(),
                            split.getSplitEnd(),
                            binlogOffset));
        }

        // the finishedSnapshotSplitInfos is too large for transmission, divide it to groups and
        // then transfer them

        boolean divideMetaToGroups = finishedSnapshotSplitInfos.size() > splitMetaGroupSize;
        return new MySqlBinlogSplit(
                BINLOG_SPLIT_ID,
                minBinlogOffset == null ? BinlogOffset.INITIAL_OFFSET : minBinlogOffset,
                BinlogOffset.NO_STOPPING_OFFSET,
                divideMetaToGroups ? new ArrayList<>() : finishedSnapshotSplitInfos,
                new HashMap<>(),
                finishedSnapshotSplitInfos.size());
    }

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flink CDC(Change Data Capture)是Flink的一个功能模块,用于从数据源(如数据库)中捕获变化,并将变化的数据以流的形式传输到Flink的DataStream中进行处理。下面是Flink CDC的工作原理: 1. 数据源连接: Flink CDC首先与数据源建立连接,通常是与关系型数据库进行连接。它会监控数据库的日志或者使用特定的协议与数据库进行交互,以便实时捕获数据源中的变化。 2. 变更日志解析: 一旦与数据源建立连接,Flink CDC会解析数据源的变更日志(如MySQL的binlog),识别出插入(INSERT)、更新(UPDATE)、删除(DELETE)等操作,并提取出变更前后的数据。 3. 变更数据传输: 解析出的变更数据将被转换为Flink的DataStream,并通过网络传输到Flink集群中。这些数据以流的形式被持续地传输到Flink任务中进行处理。 4. 数据处理: 在Flink任务中,开发人员可以定义特定的数据处理逻辑,对捕获到的变更数据进行实时处理和分析。可以使用Flink提供的各种算子和函数来实现转换、聚合、过滤等操作。 5. 结果输出: 处理后的结果可以根据需要输出到不同的目标,如文件系统、消息队列、数据库等。Flink提供了各种输出连接器和Sink函数,可以将结果输出到不同的存储或服务中。 总结: Flink CDC通过与数据源建立连接,捕获数据源的变化,并将变更数据以流的形式传输到Flink任务中进行实时处理和分析。它利用数据源的变更日志或者特定的协议来实现数据捕获,然后将捕获到的数据转换为Flink的DataStream进行处理。这样可以实现对数据源变化的实时感知和实时处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值