概述
目录
- 概述
- 一. 验证码
- 1.1 代码实现
- 二. 限流方案
- 2.1 限并发
- 2.2 令牌桶/漏桶
- 三. 限流力度
- 四. 限流范围
- 五. 代码实现
- 六. 防刷技术
- 6.1 防黄牛方案
- 七. 小结
概述
本章介绍了常见的黄牛入侵手段,以及如何使用对应的防刷手段防止黄牛入侵。同时业务的发展预估永远可能高于系统可承载的能力,因此介绍了使用多种限流技术保证系统的稳定。
本章学习目标:
- 掌握验证码生成与验证技术;
- 掌握限流原理与实现;
- 掌握防黄牛技术;
一. 验证码
- 包装秒杀令牌设置,需要验证码来错峰,分散用户的请求;
- 数学公式验证码生成器;
1.1 代码实现
首先我们需要一个生成二维码的程序,用awt来写。然后是在ordercontroller加上二维码的验证
OrderController.java
***
//生成秒杀令牌前,需要接收验证码
//生成验证码
@RequestMapping(value = "/generateverifycode",method = {RequestMethod.GET,RequestMethod.POST})
@ResponseBody
public void generateverifycode(HttpServletResponse response) throws BusinessException, IOException {
String token = httpServletRequest.getParameterMap().get("token")[0];
if(StringUtils.isEmpty(token)){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能生成验证码");
}
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if(userModel == null){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登陆,不能生成验证码");
}
Map<String,Object> map = CodeUtil.generateCodeAndPic();
redisTemplate.opsForValue().set("verify_code_"+userModel.getId(),map.get("code"));
redisTemplate.expire("verify_code_"+userModel.getId(),10,TimeUnit.MINUTES);
ImageIO.write((RenderedImage) map.get("codePic"), "jpeg", response.getOutputStream());
}
//生成秒杀令牌
@RequestMapping(value = "/generatetoken",method = {RequestMethod.POST},consumes={CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType generatetoken(@RequestParam(name="itemId")Integer itemId,
@RequestParam(name="promoId")Integer promoId,
@RequestParam(name="verifyCode")String verifyCode) throws BusinessException {
//通过verifycode验证验证码的有效性
String redisVerifyCode = (String) redisTemplate.opsForValue().get("verify_code_"+userModel.getId());
if(StringUtils.isEmpty(redisVerifyCode)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"请求非法");
}
if(!redisVerifyCode.equalsIgnoreCase(verifyCode)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"请求非法,验证码错误");
}
}
二. 限流方案
我们的原则:
- 流量远比你想象的要多
- 系统能运行或者总比挂了要好
- 宁愿让少数人能用,也不要让所有人不能用
2.1 限并发
限制并发量意思就是同一时间只有一定数量的线程去处理请求,实现也比较简单,维护一个全局计数器,当请求进入接口时,计数器-1,并且判断计数器是否>0,大于0则处理请求,小于0则拒绝等待。
但是一般衡量并发性,是用TPS或者QPS,而该方案由于限制了线程数,自然不能用TPS或者QPS衡量。
2.2 令牌桶/漏桶
- 令牌桶
客户端请求接口,必须先从令牌桶中获取令牌,令牌是由一个“定时器”定期填充的。在一个时间内,令牌的数量是有限的。令牌桶的大小为100,那么TPS就为100。
该方式可以处理突发流量
- 漏桶
客户端请求接口,会向漏桶里面“加水”。漏桶每秒漏出一定数量的“水”,也就是处理请求。只有当漏洞不满时,才能请求。刚开始时该桶是满的
该方式主要用来处理平滑流量
三. 限流力度
- 接口维度
- 总维度
接口维度就是限制某个接口的流量,而总维度是所有接口的流量。
四. 限流范围
- 集群限流:依赖Redis或其它中间件技术做统一计数器,往往会产生性能瓶颈
- 单机限流:负载均衡的前提下单机平均限流效果更好
五. 代码实现
google.guava.RateLimiter
就是令牌桶算法的一个实现类,OrderController
引入这个类,在init
方法里面,初始令牌数量为200。
@PostConstruct
public void init() {
//20个线程的线程池
executorService = Executors.newFixedThreadPool(20);
//200个令牌,即200TPS
orderCreateRateLimiter = RateLimiter.create(200);
}
请求createOrder
接口之前,会调用RateLimiter.tryAcquire
方法,看当前令牌是否足够,不够直接抛出异常。
if (!orderCreateRateLimiter.tryAcquire())
throw new BizException(EmBizError.RATELIMIT);
六. 防刷技术
排队、限流、令牌只能控制总流量,无法控制黄牛流量。
传统防刷技术
- 限制一个会话(Session、Token)一定时间内请求接口的次数。多会话接入绕开无效,比如黄牛可以开启多个会话。
- 限制一个IP一定时间内请求接口的次数。容易误伤,某个局域网的正常用户共享一个IP进行访问。而且IP可以被伪造。
黄牛为什么难防 - 模拟硬件设备,比如手机。一个看似正常的用户,可能是用模拟器模拟出来的。
- 设备牧场,一屋子手机刷接口。
- 人工作弊,这个最难防,请真人刷接口。
6.1 防黄牛方案
- 设备指纹方式:采集终端设备各项数据,启动应用时生成一个唯一设备指纹。根据对应设备的指纹参数,估计是可疑设备的概率。
- 凭证系统:根据设备指纹下发凭证,在关键业务链路上带上凭证并由凭证服务器验证。凭证服务器根据设备指纹参数和风控系统判定凭证的可疑程度。若凭证分数低于设定值,则开启验证。
七. 小结
这一节我们
- 通过引入验证码技术,在发送秒杀令牌之前,再做一层限流。
- 介绍了三种限流的方案,使用RateLimiter实现了令牌桶限流。
- 介绍了常见的防刷技术以及它们的缺点。介绍了黄牛为什么难防,应该怎样防。
最后
以上就是合适芹菜为你收集整理的【性能优化,打造亿级秒杀系统】- (八)防刷限流概述一. 验证码二. 限流方案三. 限流力度四. 限流范围五. 代码实现六. 防刷技术七. 小结的全部内容,希望文章能够帮你解决【性能优化,打造亿级秒杀系统】- (八)防刷限流概述一. 验证码二. 限流方案三. 限流力度四. 限流范围五. 代码实现六. 防刷技术七. 小结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复