数字中国·星火文集 | 物流核算系统性能调优实战
发布时间:2022-06-27

物流核算系统性能调优实战

神州控股

宁尚军

物流企业在经营中总会遇到上下游结费问题,,按大类可以分为“应收”、、、、“应付”两部分。。。。应收是物流企业收上游客户的钱,,应付是物流企业付给下游运输或其他合作伙伴的费用。。如果只有一家上游一家下游,,那结费没有任何难度,,,,手工也能算清楚账务。。而行业中物流企业的实际情况,,,,是面对众多的客户和下游合作伙伴,,,而且对于第三方物流企业,,每个客户提出的合同模式都有较大差异,,,这种情况就会把结账前的对账工作变成一个“力气活儿”,,,,每个月几万张的物流待结费单据,,,结费方式不同、、结费项目不同、、单价不同,,,一旦算错,,,,要么被质疑,,,,要么承受损失。。这时候就需要物流核算系统(BMS)来解决数据汇集和算账的问题。。。

核算系统是对物流生产活动收入与费用进行管理的系统,,费用类型包含物流生产各环节产生各种费用,,,,如运费、、、仓储费、、操作费、、包装费、、、高端服务费、、、、人力费、、资产费、、、装修费等。。。通常会从运输系统、、仓储系统、、人力系统、、、资产等系统的接入待结费单据,,,然后每天凌晨完成所有单据费用计算。。。

其主要特点是:

• 系统日均访问量不大,,,,用户一般是财务核算人员,,几十人的规模;

• 系统使用时间点比较集中,,,,结账日前后三天会有数百万单量的费用因为改单和总汇算而有大量计算,,,对系统压力集中;

• 系统运算量大,,,,月均千万单;

• 系统导出量大,,,,月均千万单;

为能支持这类特点的系统在高峰期正常运行,,需要对系统不断优化。。。。今天这篇文章,,,就是结合神州控股智慧产业链下的物流业务和系统,,,分享一下调优的思路。。我们的核算系统目前是3.0版本,,,,目前用的是MySQL数据库,,之前老版本使用的是Oracle数据库。。。。因为Oracle数据库单库性能比MySQL强大很多,,所以在3.0新版本上做性能调优就显得更加困难。。。。

1.

开发前,,,,总结老版系统的问题避免重蹈覆辙

老版系统是Oracle库,,,,使用存储过程实现业务逻辑比较多,,给数据库带来压力大。。

对“查询返回结果集行数”没有限制最大范围,,单量小的时候没什么问题,,,但是单量大的时候已经就不适用了,,,,导致数据库负载过高。。

没有合理控制事务,,有些事务过于大并且处理业务逻辑过多,,,大事务长期占用数据库资源从而不能及时释放。。

根据以上总结出的老版系统问题,,,新系统不再使用存储过程把所有业务逻辑用程序代码来实现,,,,数据库的查询做了最大条数的限制。。。。为了能使用上MySQL只读库来分压,,在业务处理过程中查询与计算费用过程不启用事务,,,只有最后保存数据时候才开启事务。。。。

2.

加强与产品经理沟通,,,,去掉不必要的计算

核算系统3.0刚上线时候发现合并单据业务用时很长需要优化,,合单逻辑是把每天符合合单规则的单据合并成一单,,,,3183个承运商与85个平台4天的合单,,,,就要1082220次合并单据查询。。。了解业务后发现并不是所有承运商在85个平台上有业务,,,也并不是所有承运商需要合单,,优化方案是在合单之前先筛选出符合条件的承运商和平台合单,,有效的查询只有23308次,,,,这样减少了1058912次没必要的查询;从而大大提高合并单据的效率。。

3.

串行变并行,,通过多线程提高效率

运输费用计算有合并单据、、、计算费用、、、记入账单三个模块,,并且过程是顺序执行的。。。

经过讨论,,发现已经合单的单据没必要等到合单模块结束后再计算费用,,,三个串行的模块是可以并行。。。经过优化后把运输费用定时拆解四个并行的小任务合单任务、、合单、、计算费用、、、记入账单,,

每个小任务完成后会把单据流转到后面的任务。。而且每个小任务的定时的线程数量是可配置,,在双十一大促期间根据硬件承受能力,,,适当调高的线程数量应对突然高涨的单量。。。。

4.

巧用数据库事务ACID解决大量费用同时入账单并发问题

为了保证账单的准确性账单金额改变是通过版本号更新,,,,每更新一次版本号加1,,当存在并发更新金额时候,,,,只会一条可更新成功,,,避免了账单金额错误的问题。。这种设计有它的优点,,,,对人力、、、、资产、、、、装修这种单量小的费用计算很适用,,,并发的概率很小,,,即使并发了可以再重新计算一次。。。

而计算运单费用的情况复杂,,,,同一个承运商的单据费用是集中计算,,,大量的费用同时记入同一个账单内,,从而造成不可避免的并发。。我最先的解决方案是加锁控制,,,,当并发时候只有抢到锁才能更新账单其他更新任务锁等待,,,,这个方案来避免账单不一致再重新计算。。。

但是同一个承运商的单据费用是集中计算的,,加锁后造成了大量排队影响了效率,,并且我使用的是redisson分布式锁有超时时间限制,,,,还是没根本解决重新计算的问题。。。后来不得不放弃用版号控制并发的设计,,,改用利用数据库事务ACID特性,,把更新交给了数据库完成,,,利用数据库自身行锁完美地解决了这个问题。。

5.

总结

以上,,,是我在实际工作中总结出来的一些零散的思路。。。。通过这些问题的解决,,我也有些小感悟,,,,方式方法上要从业务逻辑、、、、实现思路、、技术运用多维度不断尝试。。心里要坚信问题肯定能解决,,,一定不要半途放弃。。。。这类性能问题一般都不是能轻易解决的,,一定咬住问题不放,,,以坚定必胜的信念来对待才可能走到成功点。。。一点心得,,分享给大家,,希望我们每个技术人都能感受这种攻克难题时的成就感!!

站点地图