优惠券优惠的思路以及实践

  

前言:最近做关于优惠券的开发,但是发现优惠券量大了之后,性能完全跟不上,库中存200年万条优惠券,发一张券竟然需要5分钟之久,然后我就着手优化,最终到发一张券只需要15毫秒左右,现在把整个思路以及代码贴出来,供大家一起讨论和学习。

  

<强>简介

  

主要实现优惠券促销活动,首先创建活动,然后创建券组,采用预处理的方式提前进行制券,在第一版本主要实现,功能的基本业务,然后在分支实现,大数量和高并发问题。

  

<>强分支1.1

  

1:解决优惠券编码重复问题,原先采用的是获取数据库所有的券,然后去比对是否重复,如果库数据量达百万的时候就会出现非常缓慢,而且会出现经常制券失败等,所以此版本舍弃原先采用随机数的模式,通过推特的雪花算法来避免唯一,但是依然保留优惠券前缀和后缀。

  

2:由原来的异步采用线程修改为线程池,以为高并发时候存在大量的线程占内存空间。

  

3:由原来制券采用的循环模式修改为批量制券,而且采用分配插入优惠券,一批次目前定为5000 .

  

4:加入消息队列(采用rabbitMQ)对于某一批次添加失败,把失败的放入对列中,通过队列进行补救,已到达高可用。避免大批量优惠券来回重新导入消息队列对于异常信息拒绝解决并重返消息队列中,配置2个消费者以避免其中一个服务异常,消息处理出现死循环

  

<>强分支1.2

  

  

目的:跟踪热点数据,查询日志快速跟踪应用程序中的慢查询或慢操作,为后面的优化奠定基础

  

  

目的:快速的获取线程的异常问题,通过日志中的数据能快速修改

  

  

未做优化效率统计

  

采用数据库mysql

  

数据:添加25个有效活动,每个活动下分别有2个券组,每个券组下制券是5万张。优惠券表中250年万条记录

  

业务:一个会员消费同时满足这25个活动要送50张优惠券。

  

统计:整个发券过程经过10次统计得出大约消耗是306年代,其中每次获取优惠券耗时6 s。如果多次循环必然带来性能的瓶颈

  

更新优惠券状态大约耗时是0.5,从上我们可以看出我们的性能问题主要出在获取优惠券上。所以才1.3版本主要通过程序来解决这个问题

  

<>强分支1.3

  

目的:通过程序代码和优化数据库来提高性能

  

  

1:以前获取券组下所有的优惠券现在修改为每次只获取100条(经测试统计得出发送50张券消耗时间是106年代,每次获取优惠券大约耗时是2 s多,整体性能提升近3倍)

  

2:优化sql,加入组合索引(统计得出发送50张优惠券消耗总时间是2.5秒,每次获取优惠券大约耗时是0.015秒,整体的性能提升了近42倍)

  

3:加入本地缓存(如果一次性获取的优惠券先放入地图中,那么下次如果还有就不需要从库中获取优惠券。统计发现:10件商品,每件商品发50张优惠券

  

不加本地缓存效率耗时是7.5秒,加入本地缓存后耗时约5.5秒,整体性能提升了2 s)

  

<强>

  

4:对于发券采用批量更新来替代的循环(由上面的约5.5秒性能提升为大约4.8 s)

  

<>强分支1.4

  

目的:通过异步和消息队列来进行发券

  

<强>

  

1:通过异步进行发券,这样可以提高cpu的利用率,同时通过消息队列来保证稳定性,避免出现异常导致返回前端发券成功,但是异步制券时候出现异常在发500张优惠券的时候效率大约提升了0.5 s

  

2:对代码进行一次重构

  

把大方法修改小方法,每个小方法处理一个业务,比如获取活动,那么这个方法的职责就是获取活动,同时每个小方法尽量有返回值,这样可以增加代码的可读性

  

<>强分支1.5

  

1:采用复述做缓存、取当天有效的活动,活动下券组,券组下500张券存入缓存中。

  

2:加入定时任务,在每天12点时候更新缓存(这个时间可以通过热点数据来监控)

  

3:统计结果发现:

  

加入缓存后发送500张优惠券耗时只有2.7秒,比之前的4.8秒快了2.1秒,大大的提升了性能

  

<强>总结:代码我就不贴,大家可以自己去看。感兴趣的朋友可以在这个基础继续研发学习。在版1.6本可能加入分库分表,目前想采用的是当当的sharding-jdbc

  

源码地址
  

  

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!

优惠券优惠的思路以及实践