需求场景:广告平台——广告分发模块,必须控制广告的分发量,同一广告位可以分发多个广告。
实现一:
系统启动时读取有效的广告物料,按照(KEY:APP_ADVERSION_ADPOSITION,VALUE:LIST<MATERIAL>),(KEY:METERIAL_ID,VALUE:REMAIN_NUM)整理好,存入redis。
读取KEY:APP_ADVERSION_ADPOSITION不加锁
for循环LIST<MATERIAL>:检测REMAIN_NUM,将REMAIN_NUM大于0的广告物料作为可用物料放入待选举队列,带权重随机选举物料,物料分发之前的操作:
ACTION_0 -> redis SETNX加锁,再读取一次被选中物料的剩余次数
ACTION_1 -> 大于0,减一,将新的剩余次数写回redis,解锁,返回物料给客户端展示;
ACTION_2 -> 将被选中的物料从待选举队列中移除,重新选举,GOTO ACTION_0
一对N(多个物料)压测结果:
嗯,这还勉强看得。
然而可用广告物料只剩下一个时候惨案来了,tps降到了700左右,什么垃圾解决方案?!
这时候技术终极老大提出了要求:想办法不加锁!!
呃——
眯眼了半天——
忽然,redis不是有个自增的incr command么
实现二:
基础操作同实现一一致。
物料分发之前的操作调整为如下:
ACTION_0 -> this.redisTemplate.opsForHash().increment(ConstantUtil.SYSTEM_MATERIAL_REMAIN_KEY, String.valueOf(adConfigMaterialVO.getAdConfigMaterialId()), -1);
ACTION_1 -> 大于0,返回物料给客户端展示;
ACTION_2 -> 将被选中的物料从待选举队列中移除,重新选举,GOTO ACTION_0
压测:
10倍性能提升!
可用场景:秒杀、抢号、截流 and 一切你所知的高并发需要限量的场景!