最近对一个老项目进行优化升级

项目简介:

通过预设的模型,结合部品属性、历史销量,预测未来十二个月的销量。

现状:

1、老项目已在使用,数据库和应用服务器都采用的很好的服务器,每次计算5W个品种,30个模型,耗时5小时。

2、因为某些原因,项目推广时只能使用个人电脑(2核4线程,数据库为远程连接),而又需要对所有部品进行试算,单机环境下几天还没有算完,马上要到交付客户时间点了。

经过调研,

1、该项目代码结构清晰

2、分层较多且类库命名容易使人在理解上产生混淆,不利于运维。

3、最重要的一点,单线程串行计算,效率低下,个人电脑下单品种需要大概1分钟。

优化过程:

1、因为试算结果的交付时间特别紧迫,而对项目内部模型处理一知半解,未能很好的查到系统瓶颈,一时不好对项目代码进行处理,因此直接简单的使用Orleans进行封装,采用多台电脑分布式计算,先在客户要求的时间内计算一版结果应对项目推广。

2、通过上述处理,前期推广完成,并采集了自定义的一些日志,结合代码分析,得出结论:模型计算非常快,数据读取较慢,而数据保存从一开始的很快到特别慢且会发生失败。另外,代码分析结果为线程资源完全未利用上、数据库操作无批量。

     制定优化策略为,利用生产者-消费者模式批量读取数据、批量消费数据,并将线程资源利用上,若仍然不达标,再考虑分布式处理。

3、落地处理

     3.1 将模型参数加载、模型计算和模型保存三块分开为三部分,每部分建立多个线程并行处理,并利用BlockingQueue和信号量进行线程同步,然后设定生产者数据容量上限参数、生产者每批读取品种数参数、触发生产者数据读取的阈值(在消费线程消费到该值时触发新数据读取)、各部分线程数参数、批量数据保存量参数。 这期间,既要防止线程空转、控制内存占用,又要尽可能提升各部分的效率。

     3.2 对于数据的批量保存,对四种方式进行了对比

             使用Begin End块批处理多行SQL文本(SQL 文本大小和缓存区大小难以控制)

             使用ODP Bulk导入DataTable(只支持单表内部事务操作,失败时回滚会耗费更长时间)

             使用Command BIndByName进行参数数组批量操作(对网络要求高,网络不稳定时容易失败,但是支持整体事务)

             使用async方式异步操作SQL(如果使用await,那么和串行在整体时间耗费上区别不大)

       最终,考虑最终环境是内网连接,采用了Command BIndByName进行参数数组批量操作,并进行了多批次完整品种测算,无异常发生。

      3.3 分布式作为最后一个优化点,考虑采用Orleans或者自建,鉴于实际情况,暂未实现。

  经过优化,全部品种在单机的测算完成时间稳定在30分钟左右,已然达标。

  这其中的运行环境影响:客户端请求量特别小、 应用服务器的CPU及内存的要求不高、数据库IO和网络IO要求高。

12-31 16:28