电商项目实战经验

高并发电商项目

    • 利用Redis解决超卖和限时问题
    • 利用令牌桶算法完成接口限流操作
    • Nginx负载均衡
    • 流量防刷
    • 隐藏秒杀接口
    • MQ削峰处理

利用Redis解决超卖和限时问题

秒杀商品实体类:
电商项目实战经验_第1张图片
通过任务调度功能,判断当前时间是否到达活动时间
数据库sql语句:映射Dao层
电商项目实战经验_第2张图片
通过**@Scheduled(cron = “0/5 * * * * ?”)注解实现每5秒执行一次startSecKill()**,查询活动是否开启
**findUnstartSecKill()**的返回值是秒杀的所有商品,但是在我的数据库中只写了一件商品,所以只返回一件商品信息
如果返回的值为空,说明活动还未到达开始时间。如果返回不为空,那么说明活动已经开始。
该秒杀商品有多少件库存就向List中push多少次,这里存在两个问题:

  1. 因为时间调度不能在准确时间点开启活动,比如12点开始秒杀活动,当11点59分58秒的时候又一次任务调度,那么只有5s后他才会开始调用方法,在12点0分3秒的时候才会开启活动。并且对数据库有一定的压力,每5秒就去访问一次。
  2. 因为List只起到一个计数的作用,向List中注入数据的时候也是需要消耗时间的,这既浪费资源又效率不高
    电商项目实战经验_第3张图片
    解决方法:将List集合换为String类型,将查询出来的商品信息的库存直接set K V,并且String还有incr 和decr方法用来加减,效率会有一个明显的提高。
    电商项目实战经验_第4张图片
    因为之后需要一直写商品的key,太长了。所以写了一个RedisKeyUtils,通过传入商品编号来给商品设置Key。
    电商项目实战经验_第5张图片
    在Controller请求service时,会先从数据库中查询这个商品,如果商品的status为1,那么将向下进行秒杀业务逻辑。如果status为0,说明活动还未开始,如果为2,说明活动已经结束。这里算是一个缺陷,就是每次用户来秒杀商品的时候,都会去访问一次数据库,给数据库带来很大的压力。
    电商项目实战经验_第6张图片
    Service层逻辑:
    先判断该商品的value是否为0(在这个过程中需要把value强制转换成Integer),如果不为0就说明可以进行抢购。
    因为秒杀商品要求一个用户对一件商品只能购买一次,所以要借助set集合来进行去重。如果set中存在的用户,不允许在参加活动,如果set中不存在用户,那么可以参与秒杀。
    参与秒杀将用户id添加到set集合中,并将商品数量-1.
    电商项目实战经验_第7张图片
    任务调度判断是否超出秒杀时间
    如果超出秒杀时间,那么清空redis中的缓存数据,并将status设置为2,表示秒杀活动已经结束
    电商项目实战经验_第8张图片

利用令牌桶算法完成接口限流操作

电商项目实战经验_第9张图片
限流工具类RateLimiter
拿到令牌的请求可以做业务处理,但是没拿到令牌的请求有两种方式,第一种让请求一直等待(阻塞),直到请求拿到了令牌。第二种给出一个尝试时间,在规定的时间内拿到令牌做业务处理,没拿到就抛弃请求。另外,令牌桶算法可以设置初始令牌数,防止瞬间大批量请求。
还可以设置一个超时时间tryacquire():在规定的时间内没有拿到令牌的请求被抛弃。
在这里插入图片描述

Nginx负载均衡

电商项目实战经验_第10张图片
解决负载均衡后出现的session不共享问题

流量防刷

相当于令牌桶算法的升级版
电商项目实战经验_第11张图片
采用SpringMVC拦截器实现流量防刷
添加拦截器
首先获取用户的ip地址,将ip地址设置为key,每当用户请求拦截的页面,那么都会将key进行+1操作
判断如果用户的ip对应的value大于30小于100,说明用户请求过于频繁
判断如果用户的ip对应的value大于100,说明用户在使用使用脚本请求我们的接口,将用户ip拉黑
电商项目实战经验_第12张图片
创建ip黑名单
电商项目实战经验_第13张图片电商项目实战经验_第14张图片

注意:坑!
当用户第二次请求这个页面会发生错误:key的值不是一个整数,不能对其进行+1操作
解决办法
对redis进行序列化修改操作
电商项目实战经验_第15张图片
注册拦截器
电商项目实战经验_第16张图片
优化拉黑功能
当在一个机房内,通常大家所用的都是同一个ip地址,那么当有一个人刷了我们接口以后,其他人就会被伤及无辜,所以我们要对这个功能进行优化,对用户ip这个参数增加一些与电脑相关的特性。
例如:加入User-Agent属性,这个属性包含着当前浏览器所运行的环境

隐藏秒杀接口

加入黑客测试到了我们的接口请求次数限制,脚本设置一分钟之内迅速请求30次就等1分钟再次请求,使用过个机器人账号在短时间内直接请求30次对我们服务器也是一种压力,那么我们可以为了避免黑客直接请求我们的秒杀接口,将接口进行加盐处理。
电商项目实战经验_第17张图片

MQ削峰处理

当用户拿到抢购资格后会创建订单,但是订单创建的业务逻辑会比是否有抢购资格的逻辑复杂。假设抢购资格业务每秒可以处理100个请求,但是订单创建业务每秒只能处理20个请求,那么这对订单业务就是一种极大的压力,并且用户也会在前端等待订单创建的过程。
那么我们就可以使用消息队列来对消息进行一个削峰,将消息存入MQ中,订单业务监听MQ,以恒定的速度处理请求。
第一步:生成订单ID
将生成的订单id存入MQ中,等待订单业务消费
通过异步的方式将订单id传到前端,前端设置每1秒查询一次这个订单是否创建完毕,创建完毕返回订单
电商项目实战经验_第18张图片
第二步:消费消息
消费消息成功后回复(ack)消息队列。将成功创建的订单存入数据库,并从前端请求订单接口。
缺点:并没有解决用户需要等待订单创建的过程,并且查询订单是否创建完毕还要访问数据库。创建后的订单可以选择存入redis,我觉得可以使用hash类型进行解决,但是我还没有对这部分进行更改。

你可能感兴趣的:(redis,java)