订单新旧客状态处理方案优化
一、问题原因
1、线上发现一个数据问题,在2015年1月12号到2月4号,有一部分订单出现“新旧客”标识与“佣金比例”不匹配。
2、分析发现问题原因是2月5号上线了新的版本,更改了订单新旧客的判断标准;上线后的代码通过25天同步任务,修改了部分之前25天的“新旧客”状态,但是并没有修改相应的佣金比例。
二、处理需求
1、由于佣金比例经过了方案修改,无法通过SQL精确查出所有的异常订单,所以需要通过程序遍历所有订单,找出订单之前的新旧客状态,并且进行修改。
2、订单时间段:1月12号-2月4号
3、订单量:700W订单
4、问题订单预估:1W
三、初步方案
1、处理方案:
1)首先分页取出当前CPS数据库的所有订单
2)使用订单号通过order-api按照以前的逻辑,进行判断所有订单的新旧客状态
3)将上一步判断的新旧客状态与现有数据库里面的状态进行对比,如果有差异,则将差异信息写入redis
4)将redis里的差异订单,更新到数据库中
2、程序流程图:
3、运行结果:
程序运行后,可以正确更新订单的新旧客状态。但是程序性能出现问题,生产者线程存在阻塞,运行非常缓慢。更新一天的数据需要5个小时,而且越往后越慢。
4、问题原因:
1)查询CPS库中订单方法有问题,直接对25天的订单进行分页,造成了查询速度缓慢,严重影响了数据库性能。
2)查询SQL的排序方式有问题,增加了额外的数据库开销。
3)生产者线程中,采用串行的方式进行查库、两次查询order-api、比较数据等操作,影响了生产的速度。
四、优化后方案
1、优化点:
1)查询条件切片,将查询条件切分为2个小时一段,提升SQL查询速度
2)排序方式按照数据库里现有的顺序,采用顺序排序,使得无需增加额外开销
3)将生产者进行拆分,按照流水线模式,切分为多个生产者,进行并行数据生产。
2、程序流程图:
3、运行结果:能正确处理所有异常订单,并且效率超高。处理速度达到了4分钟一天,700万订单花费一个半小时。
4 、缺陷:由于采用多个线程池进行并行处理,效率高的同时造成了CPS占用飙升,使用率达到了100%,监控中心告警。
五、优化总结
在以上的两个方案中,可以总结出几个程序优化的方法:
1、 SQL优化:
1) 做查询时,要考虑到总体的数据量。对查询条件进行切分,再进行分页查询。同时查询条件一定要走索引。
2) 排序尽量顺序排序,减少数据库的性能消耗
2、 设计模式:
1) 对性能要求较高时,可以采用多线程的方式进行程序处理。
2) 更进一步,使用生产消费模式。将业务逻辑拆分成一个个处理单元,进行多线程池的并行处理。这样可以极大的提升程序性能;但同时能带来大量的系统资源消耗,要根据机器性能谨慎使用。
3、 线程回收:
在使用多线程的时候,必须具备完善的线程回收机制。例如在无数据时回收线程,或者在一个时间段之后回收,以保证CPU不被过多的占用。