关于秒杀系统的一系列问题

阻塞队列怎么么实现?超卖问题?整体怎么实现?

5 设计一个秒杀系统
特点:高并发,请求量远大于库存量,只有少数能成功;逻辑比较简单,下单减库存;
设计理念:**限流,**只有少部分流量能进入后端;削峰,将瞬间的高流量转换成平稳的流量(比如异步处理)。内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。分布式处理。
流程:前端秒杀界面-服务端控制器(网关)-服务层-数据库层
前端浏览器可做的:将页面能静态的元素都用静态(静态不涉及服务端),通过CDN对抗峰值;禁止重复提交:用户提交之后按钮置灰,禁止重复提交;用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流。
服务端控制器层(网关层)
限制uid(UserID)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。

服务层
1、采用消息队列缓存请求:既然服务层知道库存只有100台手机,那完全没有必要把100W个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。
2、利用缓存应对读请求:对类似于12306等购票业务,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。
3、**利用缓存应对写请求:**缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。(redis就是非关系数据库,可以在内存处理数据,读写比较快)
秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。

在这里插入图片描述
总结:秒杀系统特点是瞬间高并发峰值。
第一就是前端限流
比如按钮只能点一次,IP限流;
比如静态页面,用户浏览商品等常规操作,并不会请求到服务端。只有到了秒杀时间点,并且用户主动点了秒杀按钮才允许访问服务端。
比如使用CDN,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
比如提高参加的门槛,会员才能参加;比如分批抢,这些都是产品经理的问题了,不算技术问题。
第二点:由于只有少部分商品,所以大部分用户都是返回失败,下单成功才会写库存。是典型的读多写少的场景,该用缓存了。
针对读多写少场景,大量读请求可能会击沉数据库,所以可以用缓存比如redis。可能会遇到缓存击穿(热点数据永不过期,加锁),穿透(接口校验,布隆过滤器,返回固定值并写缓存),雪崩(过期时间打散)等问题要注意解决。更多的话可以用redis集群,以及涉及集群的一些问题。

第三点就是针对库存问题。
比如真正的秒杀商品的场景,不是说扣完库存,就完事了,如果用户在一段时间内,还没完成支付,扣减的库存是要加回去的。所以,在这里引出了一个预扣库存的概念
以及库存超卖问题?我们在减库存一般先检查库存量是否大于0,是的话就执行减库存,但是这两个操作不是原子操作,所以很有可能检查大于0,但是在减库存之前被别的用户买完了。
解决方法可以是加互斥锁,这样就不会出现多个线程访问同一个共享变量的情况。但是性能太低了。

**乐观锁:用CAS,版本号解决,适用于读多写少的场景。**效率高一点。

在这里插入图片描述真正并发量大的是秒杀功能,下单和支付功能实际并发量很小。所以,我们在设计秒杀系统时,有必要把下单和支付功能从秒杀的主流程中拆分出来,特别是下单功能要做成mq异步处理的。
如果使用mq,需要关注以下几个问题:
消息丢失问题:原因有很多,比如:网络问题、broker挂了、mq服务端磁盘问题等(解决思路,消费前,先写入消息表,转态为待处理,只有成功消费,回调函数修改状态为已处理,每隔一段时间检查消息表,待处理就重试)
重复消费:本来消费者消费消息时,在ack应答的时候,如果网络超时,本身就可能会消费重复的消息。但由于消息发送者增加了重试机制,会导致消费者重复消息的概率增大。那么,如何解决重复消息问题呢?(加一张消息处理表,先判断表里有没有,有就直接返回,没有就下单并且加入到处理表,要保证原子操作)

(总结:前端限流(按钮,ip,CDN) 读多写少加缓存(缓存相关问题),库存超卖问题解决(乐观锁悲观锁),消息队列异步处理下单支付操作(削峰)消费丢失重复问题)

消息队列有哪些实现形式?

消息队列的作用:解耦,异步,削峰。
解耦就是生产者和很多消费者解耦,A只需要把消息写到队列中,不关心谁用,消费者挂了或者超时都跟A无关。
异步削峰:比如A是主要压力业务也就是秒杀,而下单支付都是次要业务,如果一次要搞完就会让主要业务延迟太久,锁争用太多,崩溃,队列先暂存秒杀成功,其他的次要任务不急着实现。

有成熟的rabitMQ,kafka等,以及有阻塞队列,有界无界的,链表形式的等等。

猜你喜欢

转载自blog.csdn.net/weixin_53344209/article/details/130274373