秒杀算是多线程挣钱临界资源的综合运用,不必定非要用多线程来解决,其本质是要在诸多约束状况下,尽量高效的解决问题。前端
高并发,cache,锁机制web
基于缓存架构redis,Memcached的先进先出队列。redis
稍微大一点的秒杀,确定是分布式的集群的,并发来自于多个节点的JVM,synchronized全部在JVM上加锁是不行了数据库
数据库压力后端
秒杀超卖问题缓存
如何防止用户来刷, 黑名单?IP限制?服务器
利用memcached的带原子性特性的操做作并发控制多线程
秒杀简单设计方案架构
好比有10件商品要秒杀,能够放到缓存中,读写时不要加锁。 当并发量大的时候,可能有25我的秒杀成功,这样后面的就能够直接抛秒杀结束的静态页面。进去的25我的中有15我的是不可能得到商品的。因此能够根据进入的前后顺序只能前10我的购买成功。后面15我的就抛商品已秒杀完。并发
好比某商品10件物品待秒. 假设有100台web服务器(假设web服务器是Nginx + Tomcat),n台app服务器,n个数据库
第一步 若是Java层作过滤, 能够在每台web服务器的业务处理模块里作个计数器AtomicInteger(10)=待秒商品总数,decreaseAndGet()>=0的继续作后续处理, <0的直接返回秒杀结束页面,这样通过第一步的处理只剩下100台*10个=1000个请求。
第二步, memcached 里以商品id做为key的value放个10, 每一个web服务器在接到每一个请求的同时, 向memcached服务器发起请求, 利用memcached的decr(key,1)操做返回值>=0的继续处理, 其他的返回秒杀失败页面,这样通过第二步的处理只剩下100台中最快速到达的10个请求。
第三步, 向App服务器发起下单操做事务。
第四步, App服务器向商品所在的数据库请求减库存操做(操做数据库时能够 "update table set count=count-1 where id=商品id and count>0;" update 成功记录数为1, 再向订单数据库添加订单记录, 都成功后提交整个事务, 不然的话提示秒杀失败,用户进入支付流程。
2、那么后端的数据库在高并发和超卖下会遇到什么问题呢
首先MySQL自身对于高并发的处理性能就会出现问题,通常来讲,MySQL的处理性能会随着并发thread上升而上升,可是到了必定的并发度以后会出现明显的拐点,以后一路降低,最终甚至会比单thread的性能还要差。
其次,超卖的根结在于减库存操做是一个事务操做,须要先select,而后insert,最后update -1。最后这个-1操做是不能出现负数的,可是当多用户在有库存的状况下并发操做,出现负数这是没法避免的。
最后,当减库存和高并发碰到一块儿的时候,因为操做的库存数目在同一行,就会出现争抢InnoDB行锁的问题,致使出现互相等待甚至死锁,从而大大下降MySQL的处理性能,最终致使前端页面出现超时异常。
针对上述问题,如何解决呢? 淘宝的高大上解决方案:
I:关闭死锁检测,提升并发处理性能。
II:修改源代码,将排队提到进入引擎层前,下降引擎层面的并发度。
III:组提交,下降server和引擎的交互次数,下降IO消耗。
解决方案1:将存库从MySQL前移到Redis中,全部的写操做放到内存中,因为Redis中不存在锁故不会出现互相等待,而且因为Redis的写性能和读性能都远高于MySQL,这就解决了高并发下的性能问题。而后经过队列等异步手段,将变化的数据异步写入到DB中。
优势:解决性能问题
缺点:没有解决超卖问题,同时因为异步写入DB,存在某一时刻DB和Redis中数据不一致的风险。
解决方案2:引入队列,而后将全部写DB操做在单队列中排队,彻底串行处理。当达到库存阀值的时候就不在消费队列,并关闭购买功能。这就解决了超卖问题。
优势:解决超卖问题,略微提高性能。
缺点:性能受限于队列处理机处理性能和DB的写入性能中最短的那个,另外多商品同时抢购的时候须要准备多条队列。
解决方案3:将写操做前移到MC中,同时利用MC的轻量级的锁机制CAS来实现减库存操做。
优势:读写在内存中,操做性能快,引入轻量级锁以后能够保证同一时刻只有一个写入成功,解决减库存问题。
缺点:没有实测,基于CAS的特性不知道高并发下是否会出现大量更新失败?不过加锁以后确定对并发性能会有影响。
解决方案4:将提交操做变成两段式,先申请后确认。而后利用Redis的原子自增操做,同时利用Redis的事务特性来发号,保证拿到小于等于库存阀值的号的人均可以成功提交订单。而后数据异步更新到DB中。
优势:解决超卖问题,库存读写都在内存中,故同时解决性能问题。
缺点:因为异步写入DB,可能存在数据不一致。另可能存在少买,也就是若是拿到号的人不真正下订单,可能库存减为0,可是订单数并无达到库存阀值。
总结
一、前端三板斧【扩容】【限流】【静态化】
二、后端两条路【内存】+【排队】
https://mp.weixin.qq.com/s/rO4Ric1bpNJgwuBFO8x3gw