基础编程学习快乐每一天
首页
留言
Siddim.com
当前位置:
首页
>
编程知识库
>
后端开发知识
>
用Redis轻松实现秒杀系统+面试考点
用Redis轻松实现秒杀系统+面试考点
阅读
2
2021-11-02
推荐一位大神朋友
什么是秒杀
秒杀场景一般会在电商网站举行一些活动或者节假日在
12306
网站上抢票时遇到。对于电商网站中一些稀缺或者特价商品,电商网站一般会在约定时间点对其进行限量销售,因为这些商品的特殊性,会吸引大量用户前来抢购,并且会在约定的时间点同时在秒杀页面进行抢购。
秒杀系统场景特点
秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。
秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。
秒杀业务流程比较简单,一般就是下订单减库存。
秒杀架构设计理念
限流:鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。
削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。
异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。
内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘
IO
,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。
可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。
架构方案
一般秒杀系统架构
设计思路
将请求拦截在系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。
充分利用缓存:利用缓存可极大提高系统读写速度。
消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。
前端方案
浏览器端(js):
页面静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过
CDN
来抗峰值。
禁止重复提交:用户提交之后按钮置灰,禁止重复提交
用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取
IP
限流
后端方案
服务端控制器层(网关层)
限制
uid
(
UserID
)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问
uid
,限制访问频率。
服务层
上面只拦截了一部分访问请求,当秒杀的用户量很大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有
100W
用户同时抢
100
台手机,服务层并发请求压力至少为
100W
。
采用消息队列缓存请求:既然服务层知道库存只有
100
台手机,那完全没有必要把
100W
个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。
利用缓存应对读请求:对类似于
12306
等购票业务,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。
利用缓存应对写请求:缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到
Redis
缓存中,所有减库存操作都在
Redis
中进行,然后再通过后台进程把
Redis
中的用户秒杀请求同步到数据库中。
数据库层
数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。
案例:利用消息中间件和缓存实现简单的秒杀系统
Redis
是一个分布式缓存系统,支持多种数据结构,我们可以利用
Redis
轻松实现一个强大的秒杀系统。
我们可以采用
Redis
最简单的
key
-
value
数据结构,用一个原子类型的变量值(
AtomicInteger
)作为
key
,把用户
id
作为
value
,库存数量便是原子变量的最大值。对于每个用户的秒杀,我们使用
RPUSH
key
value
插入秒杀请求, 当插入的秒杀请求数达到上限时,停止所有后续插入。
然后我们可以在台启动多个工作线程,使用
LPOP
key
读取秒杀成功者的用户
id
,然后再操作数据库做最终的下订单减库存操作。
当然,上面
Redis
也可以替换成消息中间件如
ActiveMQ
、
RabbitMQ
等,也可以将缓存和消息中间件 组合起来,缓存系统负责接收记录用户请求,消息中间件负责将缓存中的请求同步到数据库。
面试
曾经被问过好多次怎样实现秒杀系统的问题。昨天又被问到了。因此这里把我设想的实现秒杀系统的价格设计分享出来。供大家参考。
秒杀系统的架构设计
秒杀系统,是典型的短时大量突发访问类问题。对这类问题,有三种优化性能的思路:
写入内存而不是写入硬盘
异步处理而不是同步处理
分布式处理
用上这三招,不论秒杀时负载多大,都能轻松应对。更好的是,
Redis
能够满足上述三点。因此,用
Redis
就能轻松实现秒杀系统。
用我这个方案,无论是电商平台特价秒杀,
12306
火车票秒杀,都不是事:)
下面介绍一下为什么上述三种性能优化思路能够解决秒杀系统的性能问题:
写入内存而不是写入硬盘
传统硬盘的读写性能是相当差的。
SSD
硬盘比传统硬盘快
100
倍。而内存又比
SSD
硬盘快
10
倍以上。因此,写入内存而不是写入硬盘,就能使系统的能力提升上千倍。也就是说,原来你的秒杀系统可能需要
1000
台服务器支撑,现在
1
台服务器就可以扛住了。你可能会有这样的疑问:写入内存而不是持久化,那么如果此时计算机宕机了,那么写入的数据不就全部丢失了吗?如果你就这么倒霉碰到服务器宕机,那你就没秒到了,有什么大不了?
最后,后面真正处理秒杀订单时,我们会把信息持久化到硬盘中。因此不会丢失关键数据。
Redis
是一个缓存系统,数据写入内存后就返回给客户端了,能够支持这个特性。
异步处理而不是同步处理
像秒杀这样短时大并发的系统,在性能负载上有一个明显的波峰和长期的波谷。为了应对相当短时间的大并发而准备大量服务器来应对,在经济上是相当不合算的。
因此,对付秒杀类需求,就应该化同步为异步。用户请求写入内存后立刻返回。后台启动多个线程从内存池中异步读取数据,进行处理。如用户请求可能是
1
秒钟内进入的,系统实际处理完成可能花
30
分钟。那么一台服务器在异步情况下其处理能力大于同步情况下
1800
多倍!
异步处理,通常用
MQ
(消息队列)来实现。
Redis
可以看作是一个高性能的
MQ
。因为它的数据读写都发生在内存中。
分布式处理
好吧。也许你的客户很多,秒杀系统即使用了上面两招,还是捉襟见肘。没关系,我们还有大招:分布式处理。如果一台服务器撑不住秒杀系统,那么就多用几台服务器。
10
台不行,就上
100
台。分布式处理,就是把海量用户的请求分散到多个服务器上。一般使用
hash
实现均匀分布。
这类系统在大数据云计算时代的今天已经有很多了。无非是用
Paxos
算法和
Hash
Ring
实现的。
Redis
Cluster
正是这样一个分布式的产品。
使用Redis实现描述系统
Redis
和
Redis
Cluster
(分布式版本),是一个分布式缓存系统。其支持多种数据结构,也支持
MQ
。
Redis
在性能上做了大量优化。因此使用
Redis
或者
Redis
Cluster
就可以轻松实现一个强大的秒杀系统。
基本上,你用
Redis
的这些命令就可以了。
RPUSH key value
插入秒杀请求
当插入的秒杀请求数达到上限时,停止所有后续插入。
后台启动多个工作线程,使用
LPOP key
读取秒杀成功者的用户
id
,进行后续处理。
或者使用
LRANGE
key
start
end
命令读取秒杀成功者的用户
id
,进行后续处理。
每完成一条秒杀记录的处理,就执行
INCR
key
_
num
。一旦所有库存处理完毕,就结束该商品的本次秒杀,关闭工作线程,也不再接收秒杀请求。
要是还撑不住,该怎么办
也许你会说,我们的客户很多。即使部署了
Redis
Cluster
,仍然撑不住。那该怎么办呢?
记得某个伟人曾经说过:办法总比困难多!
下面,我们具体分析下,还有哪些情况会压垮我们架构在
Redis
(
Cluster
)上的秒杀系统。
脚本攻击
如现在有很多抢火车票的软件。它们会自动发起
http
请求。一个客户端一秒会发起很多次请求。如果有很多用户使用了这样的软件,就可能会直接把我们的交换机给压垮了。
这个问题其实属于网络问题的范畴,和我们的秒杀系统不在一个层面上。因此不应该由我们来解决。很多交换机都有防止一个源
IP
发起过多请求的功能。开源软件也有不少能实现这点。如
linux
上的
TC
可以控制。流行的
Web
服务器
Nginx
(它也可以看做是一个七层软交换机)也可以通过配置做到这一点。一个
IP
,一秒钟我就允许你访问我
2
次,其他软件包直接给你丢了,你还能压垮我吗?
交换机撑不住了
可能你们的客户并发访问量实在太大了,交换机都撑不住了。
这也有办法。我们可以用多个交换机为我们的秒杀系统服务。
原理就是
DNS
可以对一个域名返回多个
IP
,并且对不同的源
IP
,同一个域名返回不同的
IP
。如网通用户访问,就返回一个网通机房的
IP
;电信用户访问,就返回一个电信机房的
IP
。也就是用
CDN
了!
我们可以部署多台交换机为不同的用户服务。用户通过这些交换机访问后面数据中心的
Redis
Cluster
进行秒杀作业。
总结
有了
Redis
Cluster
的帮助,做个支持海量用户的秒杀系统其实
So
Easy
!
这里介绍的方案虽然是针对秒杀系统的,但其背后的原理对其他高并发系统一样有效。
最后,我们再重温一下高性能系统的优化原则:
写入内存而不是写入硬盘
异步处理而不是同步处理
分布式处理
感谢阅读,希望对你有所帮助 :)
来源:
blog
.
csdn
.
net
/
zxc456733
/
article
/
details
/
78864986
以上数据来源于网络,如有侵权,请联系删除。
上一篇:
辗转各大厂面试一遍,总结了这些面试问题
下一篇:
这5道String面试题,能全答对的人不到10%~
评论
(0)
提交
类别
基础编程学习
HTML
PHP
Python
编程知识库
后端开发知识
热门文章
Java并发中的同步容器与并发容器,你了解多少?
Innodb中的事务隔离级别和锁的关系,难倒一半面试者!
SpringBoot + minio实现分片上传、秒传、续传
面试官:你知道消息队列如何保证数据不丢失吗?
JAVA知识 Java8新特性
面试官:谈谈为什么要限流,有哪些限流方案?
说说动态代理与静态代理区别
面试官:思考Tomcat 类加载器为什么要违背双亲委派模型?
boot-admin 基于SpringBoot的后台权限管理系统,可作为脚手架,用于快速搭建项目
SpringBoot+Vue+App+硬件实现智能家居系统项目