鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。
1)用户维度的限流:在某一时间段内只允许用户提交一次请求,比如可以采取客户端IP或者用户ID作为限流的key。
2)商品维度的限流:对于同一个抢购商品,在某个时间段内只允许一定数量的请求进入,可以采取秒杀商品ID作为限流的key。
秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到分布式缓存,效率就会有极大提升。
秒杀系统的服务节点一定是可以弹性拓展的。如果流量来了,就可以按照流量预估进行服务节点的动态增加和摘除。比如淘宝、京东等双十一活动时,会增加大量机器应对交易高峰。
比如10万次请求同时发起秒杀请求,正常需要进行10万次库存扣减,但是由于某种原因,往往会造成多减库存或者少减库存,就会出现超卖或少卖问题。
解决超卖或者少卖问题有效的办法之一就是利用分布式锁将对同一个商品的并行数据库操作予以串行化。
秒杀场景的分布式锁应该具备如下条件:
1)一个方法在同一时间只能被一个机器的一个线程执行。
2)高可用地获取锁与释放锁。
3)高性能地获取锁与释放锁。
4)具备可重入特性。
5)具备锁失效机制,防止死锁。
6)具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
常用的分布式锁有两种:ZooKeeper分布式锁和Redis分布式锁。
秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,实际上削峰的典型实现方式就是通过消息队列实现异步处理。限流完成之后,对于后端系统而言,秒杀系统仍然会瞬时涌入大量请求,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮后端服务和数据库很重要的原因,秒杀后端需要将瞬间的高流量变成一段时间平稳的流量,常用的方法是利用消息中间件进行请求的异步处理。
通过接入网关的限流能够拦截无效的刷单请求和超出预期的那部分请求,但是,当秒杀的订单量很大时,比如有100万商品需要参与秒杀,这时后端服务层和数据库的并发请求压力至少为100万。这种请求下,需要使用消息队列进行削峰。
削峰从本质上来说就是更多地延缓用户请求,以及层层过滤用户的访问需求,遵从“最后落地到数据库的请求数要尽量少”的原则。通过消息队列可以大大地缓冲瞬时流量,把同步的直接调用转换成异步的间接推送,中间通过一个队列在入口承接瞬时的流量洪峰,在出口平滑地将消息推送出去。消息队列就像“水库”一样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
对于秒杀消息的入队可以直接在内部网关完成。内部网关在完成用户的权限验证、秒杀令牌的有效性验证之后,将秒杀消息发往消息队列即可。秒杀服务通过消息队列的订阅完成秒杀消息的消费。
常用消息队列系统:Kafka、RocketMQ、ActiveMQ、RabbitMQ、ZeroMQ、MetaMQ等。