| 持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
问题:10个人抢200元红包,有没有什么实现思路?
方法1:
很容易能答上来的:预先将200元分成10份,分别分给不同的人。
方法2:
同样常规思路,红包金额作为临界区域变量,加锁,一次只能一个线程访问,阻塞其他访问的线程。
以上是我在面试时的答案,回答的时候就觉得自己有气无力,因此下来搜搜相关资料。
方案1:
www.infoq.cn/article/201…
用户在微信群发红包,类似于普通商品秒杀活动的商品上架;微信群中所有用户抢红包,等同于秒杀活动的查询库存;用户抢到红包打开红包,类似于秒杀动作。
但除此之外,微信抢红包有更海量的并发要求和严格的安全级别。
该系统由接入层、逻辑层、存储层和缓存构成。proxy处理api接入,server承载主要的业务逻辑,cache用于缓存库存数量,db用于数据持久化。
对于db来说具体流程是:锁库存。避免抢到的红包多余发出的红包->插入秒杀记录->更新库存
三个操作需要在同一个事务中完成。但是如果第一个到达db的请求锁住该记录,后面的请求都会阻塞等待。并发请求越多,请求阻塞越严重。
- 可以将实时扣库存移到cache中操作,内存操作成功直接给server返回,异步向db持久化。使用内存代替磁盘,提高性能。
- 使用乐观锁代替悲观锁。在db的库存记录维持一个版本号,更新库存时先获取版本号,更新库存的事务提交后,检查版本号是否已被其他事务修改,如果版本号已被修改,需要回滚事务并报错。但是
- 拆红包时使用版本号,并发抢到相同版本号的拆红包请求,只有一个可以拆包成功,其他请求需要回滚事务并返回错误,用户体验无法接受。
- 第一时间拆红包的用户一部分直接失败,而手慢后并发量小的用户拆包成功,不符合拆红包的逻辑
- 大量事务的回滚和错误的返回,无效的操作给db额外的压力。 因此微信抢红包不能使用乐观锁的方式并发抢锁
- 微信的解决方案。
-
多个抢红包请求分而治之。 用户发送微信红包,系统生成id作为红包的唯一标识,接下来对红包的操作与id关联。按照红包id根据一定的规则(如尾号取模或基于hash值分流),垂直向下划分,一个垂直链条上的server服务器,db统称一个set。各个set互相独立,且同一个红包id的所有请求分到同一个set,高度内聚。化海量为销量
-
逻辑server层请求排队。事务串行到达db,在server层使用fifo队列,等候用户进程处理。
-
增加memcached控制并发。防止server中请求队列过载导致队列被降低,从而所有请求达到db,需要增加与server同级部署的memcached,控制拆同一个红包的请求并发数。理由cas操作累增,控制进入db拆红包的请求数,超过数值拒绝服务。
-
双维度库表,保障性能稳定。分开存储历史数据和当前数据,增加以循环天分表的维度。
-