背景:我们的优惠券系统发券是采用异步发券的模式。当优惠券发全量太大的时,因为要不断的去更新库存,这时候系统会出现热key问题,而且量越大速度越慢,同时还会导致mq消息大量堆积。大致数据如下,发放40万的券需要4个小时,近期我们要上线一个活动,预计同时需要发放100万的券,我们估算需要12个小时。
问题分析:目前业务上一个批次的库存量有上百万,而且还可以不断的追加库存,库存量越来越大,我们每次发券都会update库存, 在请求量大的情况下多个线程等待行锁时会出现超时,所以发券量越大超时的越多,速度也就越慢。
解决方案:我们采用Redis预扣库存的方式:第一次发券请求时申请固定步长的量放入Redis同时进行数据库扣减,后续每次请求都从Redis扣减,直到扣减完步长的量然后再次申请,我们假定步长是1万,那么1万次发券我们才进行一次数据库扣减库存操作,这样就解决了热key问题。
优化前后发券性能对比:
| 操作 | 消费组 | 发券数 | 发券耗时 | 速度 |
| 优化前 | 4个消费组 | 15万 | 35分钟 | 4285/分钟 |
| 优化前 | 4个消费组 | 42万 | 250分钟 | 1680/分钟 |
| 优化后 | 4个消费组 | 62万 | 53分钟 | 11698/分钟 |
效果:可以看出优化后发券速度提升了7倍。



