一、现公司解决秒杀方案:
1. 利用Redis原子性自增接口incr 2. Redis缓存 + 异步同步数据到数据库 优点:解决超卖问题,库存读写都在内存中,故同时解决性能问题。 缺点:由于异步写入DB,可能存在数据不一致。另可能存在少买,也就是如果拿到号的人不真正下订单,可能库存减为0,但是订单数并没有达到库存阀值。二、秒杀过程:
-
Uid 和 prodid 非空判断
-
连接redis
-
拼接key
-
- 库存key
- 秒杀成功用户key
-
获取库存,如果库存null,秒杀还没有开始
-
判断用户是否重复秒杀操作:使用set集合数据结构存储
-
判断如果商品数量,库存数量小于1,秒杀结束
-
秒杀过程
-
- 库存-1: redis.decr(key)
- 把秒杀成功用户添加清单里面: redis.sadd(userkey,uid)
三、Redis事务:秒杀并发
(一)使用工具:ab测试
- CentOS 6默认安装
- CentOS 7 需要手动安装
(二)安装
- 联网: yum install httpd-tools
- 无网络:
apr-1.4.8-3.el7.x86_64.rpm
apr-util-1.5.2-6.el7.x86_64.rpm
httpd-tools-2.4.6-67.el7.centos.x86_64.rpm
(三)测试命令
vim postfile 模拟表单提交参数,以&符号结尾;存放当前目录。 内容:prodid=0101&ab -n 2000 -c 200 -k -p ~/postfile -T application/x-www-form-urlencoded http://127.0.0.1:8081/Seckill/doseckill
(四)最常遇见的问题:
1. 超卖问题 : 解决方案:通过乐观锁解决,缺点:存在库存遗留库存及连接超时 2. 连接超时: connect-timeout 解决方案:连接池 3. 连接限制:connection-refused 解决方案:ab测试增加-r参数:ab -n 2000 -c 100 -r -p postfile -T 'application/x-www-form-urlencoded' http://127.0.0.1:8080/seckill/doseckill
4. 库存遗留问题:已经秒光,可是还有库存
乐观锁造成的问题,先点的没秒到,后点的可能秒到了
解决方案: LUA脚本,通过lua脚本解决争抢问题,实际上是redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题
(五)常见秒杀解决方案:
1、前端方案:
A:扩容 加机器,这是最简单的方法,通过增加前端池的整体承载量来抗峰值。 B:静态化 将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。 C:限流 一般都会采用IP级别的限流,即针对某一个IP,限制单位时间内发起请求数量。 或者活动入口的时候增加游戏或者问题环节进行消峰操作。 D:禁止重复提交:用户提交之后按钮置灰,禁止重复提交 F:有损服务 最后一招,在接近前端池承载能力的水位上限的时候,随机拒绝部分请求来保护活动整体的可用性。2、后端方案:
缓存 + 队列 Redis是一个分布式缓存系统,支持多种数据结构,我们可以利用Redis轻松实现一个强大的秒杀系统。 利用redis记录读取实时库存。一旦库存不足,立即抛出异常。反馈给前端。如果库存足够,通过rpc调用通知订单微服务系统生成订单。得到订单系统的生成成功的反馈以后,在秒杀微服务系统中生成一个本地订单记录,在数据库增销量减库存。 Redis 提供了 INCR/DECR/SETNX 命令,把RMW三个操作转变为一个原子操作 Redis 是使用单线程串行处理客户端的请求来操作命令,所以当 Redis 执行某个命令操作时,其他命令是无法执行的,这相当于命令操作是互斥执行的四、Redis可能存在的问题:
-
缓存穿透:
-
缓存穿透现象:
- 缓存穿透解决方案:
-
缓存击穿:
- 缓存击穿现象;
- 缓存击穿解决方案:
-
缓存雪崩:
- 缓存雪崩解决方案: