券是促销系统的必备东西,将券导出Excel文件,也是常见的业务。如果但是导出20w券需要十几分钟,那是不可忍受的。
导出Excel文件的步骤如下:
- 根据预设的数量,生成一批券。
- 将券以Excel文件导出。
我们需要优化每一个步骤!
如何高效地生成一批券?
直写db是不可接受的。通过这种方式生成1k张券问题不大,但想要快速生成1w张、20w张,就需要更好的手段。那就是分批次异步生成。
改进过程如下:
1、通过类似snowflake算法生成20w券号。
2、将20w个券号,分成50份,通过rabbitmq以异步的形式出去,委托集群上的所有机器进行消费,将券写入数据库。
注意事项:
- 如果券还未完全生成好,提友好提示用户券正在生成。
- 可以使用redis锁,防止券被重复导出。
- 消费端做好重复消费的处理。
有了券之后,如何高效导出为Excel文件?
答案时采用并发写入。20w张券可以写到4个sheet中,每个sheet最多可容纳63356条件记录(包括标题)。一个sheet对应一个线程,这样就有4个线程同时写入,性能应该会有所提升。
并发写入要注意2个问题:
- 如何计算sheet的数量?如何计算每个sheet需要记录的coupon范围?
引入Map<Integer,Integer>数据结构。map的长度,就是sheet的数量。key代表coupon的开始位置,value代表结束位置。 - 如果控制并发写入?
使用线程池来执行任务。
使用CountDownLatch协调子任务。每个子线程完成任务后,更新CountDownLatch,直至为0,则主线程就可以继续执行。
在此方案上进行压测:导出在小数据量的券,时间是缩短了,但导出到20w张券的时间还是很长。
经过分析,使用HSSFWorkbook来导出Excel时,HSSFWorkBook会把所有记录留在内存中,建议使用SXSSFWorkbook来解决大数据导出的问题。它可以限制内存保留的记录行数,超过的记录会写入硬盘。适合于适合追加数据的场景,不适合于频繁修改的场景。
将poi到3.9版本后,替换HSSFWorkBook为SXSSFWorkbook,新的测试结果为:在小数据量的情况下,响应时间是秒级。导出20w张券大约花了10秒。这个时间是可以接受。
总结
分而治之是提高性能的常见手段,既可以通过mq来达到目的,也可通过线程池。