财务数据处理问题及解决方案分享
一、平台介绍
财务自营计费主要承接京东自营数据在整个供应链中由C端转B端的功能实现,在整个供应链中属于靠后的阶段了,系统主要功能是计费和向B端的汇总。
二、问题描述
近年来自营计费数据量大增,有百亿+的数据量,一天中汇总占据了一半的数据库资源。
1、每天从单表千万W+中定位几万数据执行汇总,即全库全表执行group by操作,32库*32表,每天要花12小时处理。
2、汇总期间,系统基本停滞,导致了消息、任务处理慢,积压多,数据无法及时计费。
3、数据库压力大,有随时崩溃的风险。
4、影响供应商体验,大促期间供应商要实时查看销售数据,出战报,系统无法及时响应。
三、原技术介绍
系统汇总核心是依靠MySQL物理机在每库每表通过group by进行,汇总是按费用类型分而治之,每种类型汇总维度不一样,每次如有新的汇总维度引入,需从前到后,写一遍新的汇总逻辑,主要是锁定新维度的数据范围,确定新的group by 字段,之前逻辑还得回归测试,很蠢是吧,我也觉得。
四、解决问题的思路和办法
根据以上的背景和问题,确定大致的解决问题思路
1、首先要脱离MySQL汇总,数据库是很脆弱的,要保护数据库,不然量级一直递增,总有天塌的一天。
2、顺带解决新需求重复开发的弊端。
五、实践过程描述
由于量大,业务上允许T+1处理,既然是离线数据处理,一般都能想到spark,spring batch,finlk等,在技术调研阶段,主要考虑成熟性,社区活跃度,主要采用spark技术。按照汇总的流程划分4个步骤。以下内容为了通俗易懂,简化了逻辑进行简单描述下。
1、数据抓取
汇总前数据,就是业务数据,type泛指业务数据中划分数据费用类型的字段,ou、dept泛指源数据的维度,可以是别的一个或者多个字段,amount就是要汇总求和的字段,此处用金额表示。
配置表,就是针对源数据衍生出来的,配置数据可以由很多个,是泛指,本系统只用到了一张。type表示费用类型用来和源数据关联使用,关联可以用一个或者多个字段关联,此处用一个字段举例,merge_key是汇总的字段,字段取值是从源数据的表结构的一个或者多个字段组成。invoice_type,代表汇总后的结果集需要填充的公共字段,此处用发票类型来泛指。可以根据填充的字段扩充,扩充的话在配置表中往后增加列即可。如下示例图以单个字段表达这个意思。
2、规则匹配
进行第一次加工,即把源数据中的每一行和配置表中的唯一一行关联,如下图,特殊说明下,源数据的每一行,在配置表中有且仅有一行配置可以关联上,即left join,无法关联上的,即无配置,过滤掉,不进行汇总。第一步骤加工操作是在内存中操作完成。
然后进行第二步骤加工,此步骤我们需要把从配置表中取出的merger_key字段进一步解析成当前left join后的行所对应字段的具体值。解析后的结果如下图,此步骤说明下,根据merger_key的字段,比如第一行ou,获取本行对应列的字段值,就是81,原理是通过Java反射实现,现在已有各种开源的工具包可以直接用,如spring的表达式等工具。以此类推,也能获取多个字段的值,多个字段可以按照一定的连接符号拼接,此图以_拼接。填充字段也同步进行添加。
3、数据汇总
规则匹配数据加工完毕后,我们只需要对加工完毕后的merger_key字段进行汇总,汇总引擎中只需要按照固定的汇总字段(此处举例是第二步骤加工完毕后的merger_key字段),汇总的逻辑就能够固化下来,只需要1个通用sql即可实现所有费用类型的汇总,最终产生的汇总结果。
4、汇总结果
汇总后的数据和通过原技术实现汇总出来的数据能保持一样的结果,同时还能填充一些公共的字段。如下图,其中绿色的2行源数据,按ou汇总在结果表中变成1行;橙色的3行源数据按dept汇总在结果表中变成2行;黄色的源数据按ou、dept字段汇总变成3行。
最后把这个汇总结果回写到MySQL即可。
六、实践过程思考和效果评价
1、在测试环境验证的过程中,测试表和线上表表数量级别不一样,初上线时,读取数据超慢。由于spark读取单表速度很快,读取分库分表数据效率直线下降,此处采用多线程方式去读符合条件的未汇总数据,最后汇总一个大集合。
2、上线稳定运行一段时间后,性能对比图,主要是通过剥离了MySQL中执行group by的操作,汇总时长下降了,数据库性能提高了,进而处理消息和异步任务能力也提高了,牵一发而影响全局。
3、后续有新的汇总需求上线时,通过配置即可实现新维度汇总功能,简化了研发工作,提高了需求交付时效。弊端也是有的,目前汇总维度的字段必须要从主表里取,因为spark读取业务数据只读取了主表,未读取扩展表。后续对hive表数据质量有信心,可以改成spark直接读取hive表,或者读es,ck等库。
4、通过spark框架引入、把大库汇总从在线改成离线,缓解了数据库压力,数据库性能提升后,从而也提升了计费的实效性,同时还增加了系统的稳定性,提升了供应商体验。
作者:王石根
来源:京东云开发者社区 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一文详解应用安全防护ESAPI
本文分享自华为云社区《应用安全防护ESAPI》,作者: Uncle_Tom。 1. ESAPI 简介 OWASP Enterprise Security API (ESAPI)是一个免费、开源的web应用程序安全控制库,使程序员更容易编写风险较低的应用程序。ESAPI库旨在使程序员更容易对现有应用程序进行安全性改造。ESAPI库也是新开发的坚实基础。 考虑到特定语言的差异,所有OWASP ESAPI版本都有相同的基本设计: 有一组安全控制接口。例如,定义了传递给安全控件类型的参数类型。 每个安全控制都有一个参考实现。例如:基于字符串的输入验证。例如,Java 的 org.owasp.ESAPI.reference.FileBasedAuthenticator 的 ESAPI,而其他参考实现则是成熟的企业级参考实现,例如,org.oasp.ESAPI.reference.DefaultEncoder 或 org.owasp.ESAPI.reference.DefaultValidator。 每个安全控件都有自己的实现(可选)。这些类中可能包含应用程序逻辑,这些逻辑可能由您的组织开发或为您...
- 下一篇
安卓动态链接库文件体积优化探索实践
背景介绍 应用安装包的体积影响着用户下载量、安装时长、用户磁盘占用量等多个方面,据Google Play统计,应用体积每增加6MB,安装的转化率将下降1%。 安装包的体积受诸多方面影响,针对dex、资源文件、so文件都有不同的优化策略,在此不做一一展开,本文主要记录了在研发时针对动态链接库的文件体积裁剪优化方案。 我开发的链接库使用rust语言开发,通过安卓jni接口实现java层和native层之间的相互调用。为什么使用rust主要有以下几个方面的考虑: 1.稳。安卓的JNI接口调用复杂,又涉及到native层的内存管理,随着代码量的增加,代码的安全稳定性会受到很大的挑战。使用rust开发,开发者几乎不需要考虑GC的问题,只要开发的时候按照规范老老实实写代码并且通过了编译器的检查,基本上就很难把程序写崩,这一点在代码上线后也确实得到了验证。 2.安全。传统使用C、C++开发的代码编译完成以后,如果不加保护,很容易使用反汇编工具破解,市面上比较成熟的工具如IDA、ghidra等都可以将汇编代码还原到高级语言。使用rust编译的产物,内部函数间的调用规约和传统都不一样,目前市面上还没有相...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2整合Thymeleaf,官方推荐html解决方案