adsl固定ip-window7桌面主题

fastdb
2023年4月4日发(作者:aboboo)

如何设计千万级数据的java对账系统之⼆

在讲解对账系统设计前先画个⼤致的草图说明下背景

我们为什么这样做

公⽹对账:简单的可以说就是⼀个⼤平台部署了很多应⽤⽐如⽀付接⼝基础平台对账服务等应⽤,主要⽤于对外当然公⽹的系统架构整体

布局⽐较复杂这⾥暂且不去表述这个⼤平台架构,对于公⽹对账就是对外拉取所有的通道对账单⽂件和公⽹平台的本⾝的数据库订单做对

私⽹对账:简单来说就是⼀个个项⽬应⽤(公⽹和私⽹都有各⾃的数据库数据结构⼀样只是公⽹的数据包含了所有的私⽹的各个项⽬的数据

具体数据如何同步⽬前暂且不表)对于私有云对账就是把公⽹对账过程中拉取的第三⽅对账单⽂件和公⽹平台订单统⼀打包压缩的解密成⽂

件通过内⽹传输后再解密解压使⽤私⽹内的数据库的数据对账

问题⼀:为啥是这种模式

因为整个公⽹⼤平台部署在多个异地提供多种服务,特别是⽀付服务,⽽私⽹针对⼀个个⼦项⽬应⽤主要⽬的就是⽤来给银⾏机构登录⽤

来对账清分使⽤,同时某些原因私⽹不提供外⽹的能⼒所以需要搭建这种模式,当然公⽹私⽹数据库如何同步的问题是个很⼤的话题此处

暂且不表

问题⼆:为啥公⽹对完账后私⽹还要对账⼀次

⽤公⽹对账后会将通道对账⽂件和本平台订单⽂件打包内⽹给私⽹进⾏⼆次对账,这样做主要⽬的在于⽤使⽤者主要使⽤私⽹的环境对账

清分,⽽私⽹的数据库有可能和公⽹数据库有点细微差别(⽐如对账费率有点不同),所以⽤私⽹对账才能保证对账的准确性。另外假如私⽹

不想和第三⽅对账对账(也就是本地对账),我们可以直接将公⽹对账结果copy给私⽹,对账结果速度⾮常快。

对于这种模式公⽹的服务器⼀般配置⽐较⾼同时配置了多台服务器,⽽对于私⽹相当于将对账任务做了划细所以私⽹我们基本部署是单台

服务器

讲完了上述背景后,聊下系统变更历史

V1.0时代技术选型spring+mybatis+memcached+jdbc

这种⽅式⽐较直接就是多线程下载通道对账单然后下载对账单的⽂件解析成⾃⼰适配的dto放⼊内存然后把订单从读库⾥读出放到内存⾥

⼀⼀⽐对这种使⽤⽅式针对数据量不⼤时可以⽤,当量⼤是⽐较吃内存

这⾥⽤到了⼏个技术点:

1.预热数据

使⽤memached对于对账系统⽐较特殊⼀般都是使⽤的昨⽇的订单数据拉取的基础服务数据也是昨天的数据所以此处可以定时任务在凌

晨的时候将需要的数据预热缓存

将订单数据和对账按商户id进⾏hash到⼀个队⾥⾥这样便于扩展,当时考虑使⽤redis对账但是考虑到私⽹不能安装redis,同时redis单

台对账肯定不⾏,所以这⾥直接⽤jvm队列机制内存操作这⾥订单基于hash对列起到缓冲作⽤数据量不是很⼤时也不会导致内存溢出

并发对账

读取订单备库时(已按时间分区)每个线程拉取6个⼩时的订单也就是4*6=24,将数据拉取此处直接使⽤jdbc拉取后⾯批量⼊库也直接

⽤jdbc不再使⽤mybatis

每个hash队列对账完后需要主动释放资源当负载过⾼需要(),当然这⾥的GC优化是根据不同场景去做了调优具体不再表述私

⽹的GC收集器parnew+cms收集器堆配置4g永久代1g

由于我们的私⽹对账的项⽬对于公⽹来说数据相当于被切割了细⼩的服务,同时基于某些原因私⽹有些服务⽐如redis等很多中间件不能安

装针对私⽹的对账⽬前采⽤的是改⽅案

V2.0时代

V2.0主要是对1.0结构调整和使⽤了redis

技术选型spring+mybatis+memcached+jdbc+redis

对账⼤致流程:jdbcJob->distributor->aggregator->preposer->exporter

jdbcJob并发拉取订单

distributor分发器,订单分发

aggregator聚合器,聚合汇总

preposer前置器,输出前置处理

exporter输出器,输出-⼊库

Distributor:

1.修改任务状态-加锁updateBillStatus通过数据库Status更新是否成功使⽤数据库乐观锁拉取对账单任务

2.拉取账单:下载第三⽅账单(延签)-解析对账单到BufferedReader读取到redis内存

并发对账分发聚合:

拉取订单拆分:

拉取订单的时间跨度是6个⼩时*拉取订单的并发数是4个=24(⼀天的量)

初始化分发池:

初始化聚合池:

*1)求sumcount等操作

*2)商户、渠道信息等查询回填

*3)商户费率查询,⼿续费计算等

*4)银联多费率、封顶值、品牌费计算等

*5)其他计算

分发队列DataQueue:队列容量=100000阻塞队列=ArrayBlockingQueue

distribute:发数据根据商户id运⽤hash算法找到分发路径

4.订单⽐对

a.先从redis订单拷贝到本地内存thirdMap

分批次拉取平台数据库表Jobhash对和对账单同⼀个队列

c.第三⽅对账单和平台数据库⽐对记录:

需要对账:

1).⽐⾦额====⼀致获取对平的订单的对账结果--》分发队列DataQueue分发

2).⽐⾦额====不⼀致进⼊异常订单

3).平台有第三⽅没有进⼊异常订单平台挂账

本地对账:获取对平的订单的对账结果dto--》分发队列DataQueue分发对账结果dto

第三⽅有,本地没有:代表平台改天没有数据或平台库⾥都没这笔订单:

成功订单,调⽤第三⽅接⼝去同步订单的状态,时间⾦额并写⼊数据库继续⽐对

记录平台少订单的异常记录

d:分发队列DataQueueDataAggregator做聚合汇总:统计笔数⾦额商户⼿续费第三⽅⼿续费

f:数据输出器:

*1)数据前置预处理
ExportPreposer-->⼊库前的处理:对汇总后的数据进⾏⾦额处理,如抹零

*2)商户⽇结⼊库

*3)银联商户⽇结⼊库

*4)其他明细⼊库

⼊库后最后触发GC

改时代系统也有很多问题,⽐如hash散列不⼀致导致某个队列内存占⽤过⾼,还有⽐如redis挂掉了怎么办,另外订单⼀⼀⽐对过程中对

内存的消耗也很⾼总之问题较多,但是基本满⾜⽬前场景需求即可⽆需过多设计

V3.0

V3.0⽬前主要是对数据库的改造上,订单改造,订单表和订单明细表合⼆为⼀去掉不必要索引,将对账适配的使⽤字符串⽐对,内存⽐对换

成fastDB等此处这⾥不再讲述

⽬前系统公⽹使⽤v2.0私⽹使⽤v1.0效果还是可以

更多推荐

fastdb