得物供应链复杂业务实时数仓建设之路

news2024/12/22 17:14:41

1 背景

得物供应链业务是纷繁复杂的,我们既有 JIT 的现货模式中间夹着这大量的仓库作业环节,又有到仓的寄售,品牌业务,有非常复杂的逆向链路。在这么复杂的业务背后,我们需要精细化关注人货场车的效率和成本,每一单的及时履约情况,要做到这一点我们需要各粒度和维度的数据来支撑我们的精细化管理。

1.1 业务早期

业务早期,业务反馈我们后台管理系统某些报表查询慢。查询代码可知,如下图:

这种现象一般表现为:

  • 大表 JOIN,rdbms 不擅长做数据聚合,查询响应慢,调优困难;

  • 多表关联,索引优化,子查询优化,加剧了复杂度,大量索引,读库磁盘空间膨胀过快;

  • 数据量大,多维分析困难,跨域取数,自助拉到实时数据困难等。

一方面原因是系统设计之初,我们主要关注业务流程功能设计,事务型业务流程数据建模,对于未来核心指标的落地,特别是关键实时指标落地在业务快速增长的情况下如何做到非常好的支撑。mysql 在此方面越来越捉襟见肘。

另外一方面原因是 mysql 这种 oltp 数据库是无法满足实时数据分析需求的,我们需要探索一套实时数据架构,拉通我们的履约,仓储,运配等各域的数据,做有效串联,因此我们开始了我们的实时数据架构探索,下图是我们一些思考。

附:数据视角的架构设计也是系统架构设计的重要组成部分。

2 架构演变

2.1 原始阶段

2.1.1 通过 Adb(AnalyticDB for MySQL)完成实时 join

通过阿里云 DTS 同步直接将业务库单表实时同步到 Adb,通过 Adb 强大的 join 能力和完全兼容 mysql 语法,可以执行任意 sql,对于单表大数据量场景或者单表和一些简单维表的 join 场景表现还是不错的,但是在业务复杂,复杂的 sql rt 很难满足要求,即使 rt 满足要求,单个 sql 所消耗的内存,cpu 也不尽人意,能支撑的并发量很有限。

2.1.2 通过 Otter 完成大宽表的建设

基于 Canal 开源产品,获取数据库增量日志数据并下发,下游消费增量数据直接生成大宽表,但是宽表还是写入 mysql 数据库,实现单表查询,单表查询速度显著提升,无 olap 数据库的常见做法,通过宽表减少 join 带来的性能消耗。

但是存在以下几个问题:

  • 虽然 otter 有不错的封装,通过数据路由能做一些简单的数据拼接,但在调试上线复杂度上依然有不小的复杂度;
  • otter 伪装 mysql 从库同时要去做 etl 逻辑,把 cdc 干的活和实时 ETL 的活同时干了,耦合度较高。

2.2 实时架构 1.0

2.2.1 flink+kafka+ClickHouse

在上述调研尝试后都没有解决根本的问题,我们开始把目标建立标准的实时数仓的思路上来,在 20 年 olap 没有太多的可选项,我们把目标放在 clickhouse 上。

  • 为了保证顺序 append 每次写入都会生成一个 part 文件,满足一定条件后台定时合并。

  • 非常弱的 update delete,不能保证原子性和实时性。* clickhouse 只适合数据量大,业务模型简单,更新场景少的场景。

  • 存算不分离,复杂查询影响 clickhouse 写入。

因为 clickhouse 的这些特性,尤其是不支持 upsert 的情况下,我们通常需要提前把大宽表的数据提前在 flink 聚合好,并且供应链数据生命周期长,作业流程也长如:

  • 货物的生命周期较短时长为一周,长周期时长超过 1 个月;

  • 库内环节异常的多,从卖家发货到收货、分拣、质检、拍照、鉴别、防伪、复查、打包、出库、买家签收等十几个甚至更多的环节,一张以商品实物 id 为主键的大宽表,需要 join 几十张业务表

  • 供应链系统早期设计没有每张表都会冗余唯一单号(入库单,作业单,履约单)这样的关键字段,导致没办法直接简单的 join 数据。

  • 在这样一个架构下,们的 flink 在成本上,在稳定性维护上,调优上做的非常吃力。

附:clickhouse 不支持标准的 upsert 模式,可以通过使用 AggregatingMergeTree 引擎字段类型使用 SimpleAggregateFunction(anyLast, Nullable(UInt64)) 合并规则取最后一条非 null 数据可以实现 upsert 相似的功能,但读时合并性能有影响。

2.3 实时架构 2.0

2.3.1 flink+kafka+hologres

因此我们迫切的希望有支持 upsert 能力的 olap 数据库,同时能搞定供应链写多少的场景,也能搞定我们复杂查询的场景,我们希望的 olap 数据至少能做到如下几点:

  • 有 upsert 能力,能对 flink 大任务做有效拆分;

  • 存算分离,复杂业务计算,不影响业务写入,同时能平滑扩缩容;

  • 有一定的 join 能力带来一些灵活度;

  • 有完善的分区机制,热数据查询性能不受整体数据增长影响;

  • 完善的数据备份机制。

这样一个行列混合的 olap 数据库,支持 upsert,支持存算分离,还是比较符合我们的预期。

目前这样一套架构支持了供应链每天数千人的报表取数需求,以及每天 10 亿数据量的导出,访问量在得物所有 to B 系统中排名靠前。

2.3.2 我们遇到的一些问题

多时间问题如何设置 segment_key,选择哪个业务字段作为 segment_key 供应链几十个环节都有操作时间,在不带 segment_key 的情况下性能如何保障,困扰了我们一段时间。

设置合理的 segment_key 如有序的时间字段,可以做到完全顺序写。每个 segment 文件都有个 min,max 值,所有的时间字段过来只需要去比较下在不在这个最小值最大值之间(这个动作开销很低),不在范围内直接跳过,在不带 segment_key 查询的条件下,也能极大的降低所需要过滤的文件数量。

批流融合背景:业务快速发展过程中,持续迭代实时任务成为常态。供应链业务复杂,环节多,流程往往长达一个月周期之久,这就导致 state ttl 设置周期长。job 的 operator 变化(sql 修改),checkpoint 无法自动恢复,savepoint 恢复机制无法满足,比如增加 group by 和 join。重新消费历史数据依赖上游 kafka 存储时效,kafka 在公司平台一般默认都是存储 7 天,不能满足一个月数据回刷需求场景。

方案:通过批流融合在 source 端实现离线 + 实时数据进行数据读取、补齐。

(1)离线按 key 去重,每个 key 只保留一条,减少消息量下发。(2)离线和实时数据合并,使用 last_value 取相同主键最新事件时间戳的一条数据。(3)使用 union all + group by 方式是可作为代替 join 的一个选择。(4)实时数据取当日数据,离线数据取历史数据,防止数据漂移,实时数据需前置一小时。

Join 算子乱序

  • 问题分析

由于 join 算子是对 join 键做 hash 后走不同的分片处理数据 ,开启了 2 个并发后,再因为 header_id 字段的值变化,detail 表 2 次数据流走到了 2 个不同的 taskmanage,而不同的线程是无法保证输出有序性的 ,所以数据有一定的概率会乱序输出,导致期望的结果不正确,现象是数据丢失。

  • 解决办法

通过 header inner join detail 表后,拿到 detail_id,这样再次通过 detail_id join 就不会出现(join 键)的值会从 null 变成非 null 的情况发生了,也就不会乱序了。

insert into sinkSelect detail.id,detail.header_id,header.idfrom detailleft join (    Select detail.id AS detail_id,detail.header_id,header.id    from header     inner join detail    on detail.header_id  =  header.id ) headerNewon detail.id  =  headerNew.detail_id

2.3.3 Hologres or starrocks

这里也聊聊大家比较关注的 hologres 和 starrocks,starrocks 从开源开始也和我们保持了密切联系,也做了多次的深入交流,我们也大致列了两者之间的一些各自优势和对于我们看来一些不足的地方。

3 其他做的一些事情

3.1 开发提效工具——flink 代码生成器

参考 MyBatis gennerator 一些思想,利用模板引擎技术,定制化模板来生成 flink sql。可以解决代码规范,和提升开发效率。基本可以通过代码配置来生成 flink sql。

3.2 开发提效工具——可视化平台

直接通过配置的方式,在线写 sql,直接生成页面和接口,一键发布,同时引入缓存,锁排队机制解决高峰访问性能问题。

动态配置接口,一键生成 rpc 服务:

动态配置报表:

4 未来规划

当前架构依然存在某种程度的不可能三角,我们需要探索更多的架构可能性:

(1)利用写在 holo,计算在 mc 避免 holo 这种内存数据库,在极端查询内存被打爆的问题,利用 mc 的计算能力可以搞定一些事实表 join 的问题提升一些灵活度。

(2) 借助 apache hudi 推进湖仓一体,hudi 做批流存储统一,flink 做批流计算统一,一套代码,提供 5-10 分钟级的准实时架构,缓解部分场景只需要准时降低实时计算成本。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Malware Dev 03 - 隐匿之 Command Line Spoofing 原理解析

写在最前 如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里: https://discord.gg/9XvvuFq9Wb我拥有 OSCP,OSEP,OSWE,OSED&…

浅分析BIG-建筑展示系统

一、主页(主要界面)重点疑点(需要解决)1.云平台实时同步。是否可以电脑与hololens2同步或链接?并可以传输信息提醒?一级界面(启动界面)1.交互式启动激活效果(触发按钮旋转…

TCP协议三次握手的原因是什么?为什么不用两次握手和4次握手?

今天复习了TCP协议的三次握手,对上一篇C网络编程有了更深的理解。当时考研的时候计网学过,这里再总结一下分享。网图都是截图来的,侵删。TCP协议属于传输层协议,上面的应用层协议包括HTTP、FTP之类,应用层协议是最接近…

Prometheus 监控云Mysql和自建Mysql(多实例)

本文您将了解到 Prometheus如何配置才能监控云Mysql(包括阿里云、腾讯云、华为云)和自建Mysql。 Prometheus 提供了很多种Exporter,用于监控第三方系统指标,如果没有提供也可以根据Exporter规范自定义Exporter。 本文将通过MySQL server exporter 来监控…

通达信波段主图指标公式,源码简洁原理却不简单

通达信波段主图指标公式的核心语句也就4句&#xff0c;后面的语句都是为了画图的。公式看起来比较简单&#xff0c;原理也比较巧妙&#xff0c;但是理解起来有些困难。 直接上源码&#xff1a; HH:HHV(H,5); LL:LLV(L,5); TH:BARSLAST(H>REF(HH,1)); TL:BARSLAST(L<REF(…

K8s(v1.25.1) 高可用集群(3 Master + 5 Node) Ansible 剧本部署(CRI使用docker,cri-docker)

写在前面 分享一个 k8s 高可用集群部署的 Ansible 剧本以及涉及到的一些工具的安装博文内容涉及&#xff1a;从零开始 一个 k8s 高可用 集群部署 Ansible剧本编写&#xff0c;编写后搭建 k8s 高可用 集群一些集群常用的 监控&#xff0c;备份工具安装&#xff0c;包括&#xff…

边缘计算:万字长文详解高通SNPE inception_v3推理实战

本文主要讲解利用高通SNPE进行神经网络推理&#xff0c;主要参考&#xff1a; 上手SNPE&#xff0d;推理inception_v3 - 知乎 文中是容器做的&#xff0c;在conda环境下做一样的&#xff0c;没问题&#xff0c;已跑通。 在anaconda环境中使用conda命令安装cuda、cudnn、tens…

数据结构与算法系列之单链表

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; 这里写目录标题test.hSList.h注意事项一级指针与二级指针的使用assert的使用空…

内大892复试真题19年

内大892复试真题19年 1. 统计低于平均分的人数2. 输出数组中最大值3. 一元二次方程求根4. 字符串数组平移(反转法)5. 矩阵乘法(分治+strassen思想)1. 统计低于平均分的人数 问题 代码 #include <iostream>using namespace std;// 函数声明 double avgFunc

0098 Mysql01

1.登录Mysql mysql -uroot -p密码 2.Mysql常用命令 退出:exit 查看mysql有哪些数据库&#xff1a;show databases;(以分号结尾) 选择使用某个数据库&#xff1a;use sys; (表示正在使用一个名叫sys得数据库) 创建数据库&#xff1a;create database bjpowernode; 查看某个数…

FFmpeg入门 - 格式转换

1、音频分⽚(plane)与打包(packed)解码出来的AVFrame,它的data字段放的是视频像素数据或者音频的PCM裸流数据,linesize字段放的是对齐后的画面行长度或者音频的分片长度:/*** For video, size in bytes of each picture line.* For audio, size in bytes of each plane.** For …

Python3 入门教程||Python3 条件控制||Python3 循环

Python3 条件控制 if语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 Python 中 if 语句的一般形式如下所示&#xff1a; if condition_1:statement_block_1 流程图如下所示&#xff1a; 这种if语句只有在符合条件的时候才会执行代…

华大Flash檫写导致重启异常问题

一、华大Flash写入注意事项由Flash操作说明我们可以看出重要一点&#xff0c;就是檫写Flash函数地址需要定义在32K之前&#xff08;即0x8000之前&#xff09;&#xff0c;否则将写入失败。二、先上的错误的源代码这个代码是我应用中导致硬件卡死重启的&#xff0c;其实也不算错…

FreeSWITCH 呼入系统的简要设计

文章目录1. 呼入处理方案2. 细节处理1. a-leg 的拨号计划2. originate 呼叫坐席1. 呼入处理方案 使用 FreeSWICTH 的 ESL 模块&#xff0c;一个简单的呼入处理时序如下图所示&#xff0c;关键步骤做如下补充: 用户呼入到 FreeSWITCH 实例&#xff0c;a-leg 创建FreeSWITCH 根据…

DC真实数据都有哪些?Filecoin为DC数据存储的解决方案又是什么?

对于生活在数字时代的我们而言&#xff0c;数据或许就和平日呼吸的空气一样&#xff0c;已经不需要我们再去思考其概念。我们的日常生活中无时无刻都有数据的身影&#xff0c;日常的购物消费、出行、学习、记录&#xff0c;当我们每天生活有数字化加持的小区里&#xff0c;工作…

网上图书资料管理系统

技术&#xff1a;Java、JSP等摘要&#xff1a;Internet带给我们的不仅是无穷的信息&#xff0c;更为我们带来了很多的便利。在这个科技高速发展的时代&#xff0c;网络应用十分广泛&#xff0c;所以许多人愿意通过网络来使他们的生活变得更加的方便。网上图书资料管理系统的出现…

Spring Cloud(微服务)学习篇(五)

Spring Cloud(微服务)学习篇(五) 1 nacos配置文件的读取 1.1 访问localhost:8848/index.html并输入账户密码后进入nacos界面并点击配置列表 1.2 点击右侧的号 1.3 点击加号后,进入新建配置界面,并做好如下配置 1.4 往下翻动,点击发布按钮 1.5 发布成功后的界面 1.6 在pom.xml…

ChatGPT解答:PYQT5 的mwindow源码文件里面写了很多的函数方法,随着时间的推移越来越多,代码行数太多,影响了性能,如何解决

ChatGPT解答&#xff1a; PYQT5 的mwindow源码文件里面写了很多的函数方法&#xff0c;随着时间的推移越来越多&#xff0c;代码行数太多&#xff0c;影响了性能&#xff0c;如何解决 以下为可复制的内容与实例&#xff1a; PYQT5 的mwindow源码文件里面写了很多的函数方法&a…

第一道pwn栈溢出题

代码和解题思路来自启明星辰的《ctf安全竞赛入门》&#xff0c;当然还有好多热心的师傅们的指导。1.代码&#xff1a;#include "stdio.h" void shell() {system("/bin/sh"); } void vuln() {printf("Please input your name:\n");char s[8];gets…

实现pdf文件预览

前言 工作上接到的一个任务&#xff0c;实现pdf的在线预览&#xff0c;其实uniapp中已经有对应的api&#xff1a;uni.openDocument(OBJECT)&#xff08;新开页面打开文档&#xff0c;支持格式&#xff1a;doc, xls, ppt, pdf, docx, xlsx, pptx。&#xff09;**实现了相关功能…