Flink 通过 paimon 关联维表,内存降为原来的1/4

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益:

  1. 了解大厂经验
  2. 拥有和大厂相匹配的技术等

希望看什么,评论或者私信告诉我!

文章目录

  • 一、前言
  • 二、优化
    • 2.1 分析 Iceberg lookup 部分源码
    • 2.2 切换到 paimon 维表
    • 2.3 paimon 维表原理分析
    • 2.4 是不是一定要通过 iceberg 替换 paimon 才能降低内存
  • 三、总结


一、前言

线上实时任务,通过 FlinkSQL 关联 Iceberg 维表,维表大搞有 60w,首先通过 FlinkSQL关联 Iceberg 维表上线了,经过一番调优后:TaskManager Memory 给到了 16G,但通过监控可以轻易的发现 Heap 没下来过 10GB

图片.png

二、优化

2.1 分析 Iceberg lookup 部分源码

因为 Iceberg 的 lookup 是公司内部自己实现的,就不贴源码了,但核心一点就是,look up 维表 cache 的数据会存在内存中,这就是为什么堆内存没有下来过 10GB

2.2 切换到 paimon 维表

TaskManager Memory 给到了 4G,程序运行的轻轻松松,另外为了增加 rocksdb 性能,也适当的增加了 rocksdb 的内存

图片.png

为了替换 paimon 后内存可以下降那么多呢?

2.3 paimon 维表原理分析

首先来看一下 FlinkSQL look up paimon 的维表的源码,这里我们以 flink1.15 为例。
下载完 paimon 源码后,找到 moudle paimon-flink-1.15

图片.png
通过 OldLookupFunction 类中的

public void eval(Object... values) {
    function.lookup(GenericRowData.of(values)).forEach(this::collect);
}

可以知道调用的 FileStoreLookupFunction.lookup 方法

public Collection<RowData> lookup(RowData keyRow) {
    try {
        checkRefresh();

        InternalRow key = new FlinkRowWrapper(keyRow);
        if (partitionLoader != null) {
            InternalRow partition = refreshDynamicPartition(true);
            if (partition == null) {
                return Collections.emptyList();
            }
            key = JoinedRow.join(key, partition);
        }

        List<InternalRow> results = lookupTable.get(key);
        List<RowData> rows = new ArrayList<>(results.size());
        for (InternalRow matchedRow : results) {
            rows.add(new FlinkRowData(matchedRow));
        }
        return rows;
    } catch (OutOfRangeException e) {
        reopen();
        return lookup(keyRow);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

通过 checkRefresh 方法,一路跟踪到 FileStoreLookupFunction.refresh 方法

private void refresh() throws Exception {
    lookupTable.refresh();
}

这里呢,我们就以没有主键的 paimon 表为例,继续追踪,追踪到 FullCacheLookupTable.refresh 方法,让,后继续追踪,最后到了 FullCacheLookupTable.refreshRow 方法 ,继续追踪直到 NoPrimaryKeyLookupTable.refreshRow 方法

protected void refreshRow(InternalRow row, Predicate predicate) throws IOException {
    joinKeyRow.replaceRow(row);
    if (row.getRowKind() == RowKind.INSERT || row.getRowKind() == RowKind.UPDATE_AFTER) {
        if (predicate == null || predicate.test(row)) {
            state.add(joinKeyRow, row);
        }
    } else {
        throw new RuntimeException(
                String.format(
                        "Received %s message. Only INSERT/UPDATE_AFTER values are expected here.",
                        row.getRowKind()));
    }
}

在这里我们可以看到 cache 的数据存到的 state 中,继续看 state 是如何实现的

RocksDBListState<InternalRow, InternalRow> state

也就是说,维表的cache被存到了 rocksdb 中,这一块内存在 Flink 中属于 off-heap,并且通过 manager menory 控制。
rocksdb这一块,如果不太了解的话,可以理解为 mysql,mysql 里面可以存放 TB 级的数据,但它的占用的内存却很少,rocksdb 也是类似的

2.4 是不是一定要通过 iceberg 替换 paimon 才能降低内存

答案是否定了,开头提到了之所以 iceberg 维表占用内存大,主要的原因是因为内部的实现方式:cache 到内存中了。

三、总结

本文通过实际案例,详细介绍了如何通过替换维表实现FlinkSQL任务内存占用的优化。作者通过分析Iceberg lookup部分源码,发现其cache的数据会存在内存中,导致内存占用过大。作者将维表替换为paimon,通过分析paimon维表的原理,发现其cache的数据存储在rocksdb中,从而实现了内存占用的降低。本文对于需要进行FlinkSQL任务内存优化的读者具有一定的参考价值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/655217.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何破解navicat16

先安装好没破解的navicat16 以管理员身份运行 ‘无限试用Navicat.bat’ 复制这个 点击属性 打开文件所属位置 把复制的文件粘贴进去 直接启动navicat16

常用批处理命令及批处理文件编写技巧

一常用批处理命令 1.查看命令用法&#xff1a;命令 /? //如&#xff1a;cd /? 2.切换盘符目录&#xff1a;cd /d D:\test 或直接输入 d: //进入上次d盘所在的目录 3.切换目录&#xff1a;cd test 4.清屏:cls 5.“arp -a” //它会列出当前设备缓存中的所有…

Golang项目代码组织架构实践

Golang在项目结构上没有强制性规范&#xff0c;虽然这给了开发者很大的自由度&#xff0c;但也需要自己沉淀一套可行的架构。本文介绍了一种项目布局&#xff0c;可以以此为参考设计适合自己的 Golang 项目组织模式。原文: Golang Project Layout Go 有很多强制的或是约定俗成的…

【Mac】Ulysses for Mac(优秀的markdown写作软件) v34.3中文版安装教程

软件介绍 哪款markdown写作软件最好用&#xff1f;小编推荐您使用尤利西斯&#xff1a;Ulysses mac版&#xff01;这是mac上一款优秀的markdown写作工具。Ulysses mac版具备全新的Soulmen写作坏境&#xff0c;采用了革命性的功能增强&#xff0c;结合了最好的部分最小标记&…

60. UE5 RPG 使用场景查询系统(EQS,Environment Query System)实现远程敌人寻找攻击位置

UE的Environment Query System&#xff08;EQS&#xff09;是环境查询系统&#xff0c;它是UE4和UE5中用于AI决策制定过程中的数据采集和处理的一个强大工具。EQS可以收集场景中相关的数据&#xff0c;利用生成器&#xff08;Generator&#xff09;针对用户的测试&#xff08;T…

mysql 按区间统计 3 分钟维度

根据 UNIX_TIMESTAMP 去掉分钟后的的位数 思路如下select UNIX_TIMESTAMP(now()) 当前时间 秒,now() 当前时间,FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(CURRENT_TIMESTAMP) / (3 * 60)) * (3 * 60)) 3分钟为分隔去掉多余位数当前时间 秒 当前时间 3分钟为分隔去掉多余…

【NumPy】全面解析NumPy的where函数:高效条件操作指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

哈希冲突的常见解决方法【附C++代码】

在C中&#xff0c;哈希表是一种常用的数据结构&#xff0c;用于实现快速的插入、删除和查找操作。 哈希表的核心在于哈希函数&#xff0c;它将输入的关键字转换为一个数组索引。然而&#xff0c;不同的关键字可能映射到相同的索引&#xff0c;这种情况称为哈希冲突。 有效地解…

k8s中的集群调度

文章目录 k8s中的集群调度Pod 创建流程 通过指定节点来创建pod所在的node节点通过标签来指定pod创建在哪个节点上pod 的亲和性Pod的亲和性和反亲和性亲和性&#xff08;Affinity&#xff09;反亲和性&#xff08;Anti-Affinity&#xff09; 污点与容忍污点&#xff08;Taint&am…

2024年,史上最强的数据库资料集合

&#x1f4a8;&#x1f3f9;&#x1f300; 2024年&#xff0c;史上最强的数据库资料集合 N种数据库的全方位整理&#xff1a; mysql&#xff0c;mariaDB&#xff0c;Percona Server&#xff0c;Redis&#xff0c;RocksDB&#xff0c;Cassandra&#xff0c;CouchDB&#xff0c…

【LeeCode算法】第67题:二进制求和

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;将a和b两个字符串转换成十进制&#xff0c;然后将相加的结果转换回文本的二进制。 2. 代码&#xff1a; char* addBinary(char* a, char* b) {int a_len strlen(a);i…

保障餐饮场所安全:可燃气体报警器专业检测的必要性

在餐饮行业&#xff0c;火灾隐患一直是备受关注的问题。为了有效预防和及时发现可燃气体泄漏&#xff0c;可燃气体报警器的专业检测周期显得尤为重要。 今天&#xff0c;佰德和大家一起来深入了解一下可燃气体报警器的专业检测周期&#xff0c;若您对此有不同的观点或其他的问…

鸿蒙ArkUI-X跨语言调用说明:【平台桥接开发指南(Android)BridgePlugin】

BridgePlugin (平台桥接) 本模块提供ArkUI端和Android平台端消息通信的功能&#xff0c;包括数据传输、方法调用和事件调用。需配套ArkUI端API使用&#xff0c;ArkUI侧具体用法请参考[Bridge API]。 说明&#xff1a; 开发前请熟悉鸿蒙开发指导文档&#xff1a; gitee.com/li-…

OSPF优化——OSPF减少LSA更新量2

二、特殊区域——优化非骨干区域的LSA数量 不是骨干区域、不能存在虚链路 1、不能存在 ASBR 1&#xff09;末梢区域 该区域将拒绝 4、5LSA的进人&#xff0c;同时由该区域连接骨干0区域的ABR 向该区域&#xff0c;发布一条3类的缺省路由; 该区域内每台路由器均需配置&#xf…

1---Linux下进程的概念(逻辑推导,全干货无废话)

一、进程和程序&#xff1a; 1.1什么是程序&#xff1f; 程序由代码、数据、逻辑、接口和文档组成的一组按特定顺序执行的计算机指令&#xff0c;用于实现特定功能或解决问题。程序存储在磁盘上。 1.2什么是进程&#xff1f; 进程是一个正在执行的程序实例&#xff0c;包含程…

LLM提示工程的技巧

1. 从简单开始&#xff08;Start Simple&#xff09; 避免在一开始就增加太多的复杂性。 从简单的提示开始&#xff0c;然后在后续提示中添加更多信息和上下文。 这样&#xff0c;提示就是一个迭代过程&#xff0c;提示在此过程中进一步发展。 从简单的开始&#xff0c;就有足…

Matplotlib绘图指南:从基础绘图到多子图展示

目录 前言 导入模块 第一点&#xff1a;绘制图像 第二点&#xff1a;保存图像 第三点&#xff1a;多图形的绘制 第四点&#xff1a;绘制多子图 总结 前言 在数据可视化中&#xff0c;Matplotlib是一款强大的Python库&#xff0c;提供了丰富的功能来绘制各种类型的图表。…

【Linux】自己实现一个bash进程

bash就是命令行解释器&#xff0c;就是Linux操作系统让我们看到的&#xff0c;与用户进行交互的一种外壳&#xff08;shell&#xff09;&#xff0c;当然了bash也是一个进程&#xff0c;它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进…

Python零基础一天丝滑入门教程(非常详细)

目录 第1章 初识python 第1节 python介绍 1.为什么要学习Python&#xff1f; 2.python排名 3.python起源 4.python 的设计目标 第2节 软件安装 第2章 快速上手&#xff1a;基础知识 第1节 Python3 基础语法 Python 变量 字面量 数据类型转换 Python3 注释 数据类…

《java数据结构》--队列详解

一.认识队列&#x1f431; 初识队列&#x1f638; 队列和栈类似都对数据的存取有着严格的要求&#xff0c;不同的是栈遵循先进后出的原则&#xff0c;而队列遵循先进先出的原则&#xff0c;栈是只有一端可以存取&#xff0c;队列是一端存&#xff0c;一端取。这里我来画一个图…