淘东电商项目(78) -秒杀系统(服务保护)

简介: 淘东电商项目(78) -秒杀系统(服务保护)

引言

本文代码已提交至Github(版本号:dd8742a8348b4c64a8ca794d544a3271e94365a9),有兴趣的同学可以下载来看看:https://github.com/ylw-github/taodong-shop

秒杀系统的代码在前面博客已经实现了,有兴趣的同学可以参阅下:

秒杀的逻辑代码完成了,剩下还有一个问题,就是关于服务的保护了,本文来讲解。

本文目录结构:

l____引言

l____ 1.服务保护

l________ 1.1 限流

l________ 1.2 降级、熔断、限流概念

l____ 2.代码

l________ 2.1 网关限流

l________ 2.2 服务保护

l____ 3.测试

l________ 3.1 网关限流测试

l________ 3.2 服务保护测试

1.服务保护

服务保护在《互联网并发与安全》栏目有讲解过,有兴趣的同学可以参阅下:

下面来简单的描述下。

1.1 限流

常见限流算法常用的限流算法有:令牌桶算法、漏桶算法

  • 令牌桶算法:在秒杀活动中,用户的请求速率是不固定的,这里我们假定为10r/s,令牌按照5个每秒的速率放入令牌桶,桶中最多存放20个令牌。仔细想想,是不是总有那么一部分请求被丢弃。
  • 漏桶算法:漏桶算法的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量

市面上常用实现限流框架:

  • Nginx+Lua、Guava、hystrix等

1.2 降级、熔断、限流概念

服务雪崩效应:服务雪崩效应产生与服务堆积在同一个线程池中,因为所有的请求都是同一个线程池进行处理,这时候如果在高并发情况下,所有的请求全部访问同一个接口,这时候可能会导致其他服务没有线程进行接受请求,这就是服务雪崩效应效应。

服务降级:在高并发情况下,防止用户一直等待,使用服务降级方式(直接返回一个友好的提示给客户端,调用fallBack方法)。

服务熔断:熔断机制目的为了保护服务,在高并发的情况下,如果请求达到一定极限(可以自己设置阔值)如果流量超出了设置阈值,让后直接拒绝访问,保护当前服务。使用服务降级方式返回一个友好提示,服务熔断和服务降级一起使用。

服务隔离:因为默认情况下,只有一个线程池会维护所有的服务接口,如果大量的请求访问同一个接口,达到tomcat 线程池默认极限,可能会导致其他服务无法访问。

解决服务雪崩效应:使用服务隔离机制(线程池方式和信号量),使用线程池方式实现隔离的原理: 相当于每个接口(服务)都有自己独立的线程池,因为每个线程池互不影响,这样的话就可以解决服务雪崩效应。

  • 线程池隔离:每个服务接口,都有自己独立的线程池,每个线程池互不影响。
  • 信号量隔离:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返回成功后计数器-1。

2.代码

2.1 网关限流

网关限流,淘东电商项目采用的是基于谷歌RateLimiter实现限流。Google的Guava工具包中就提供了一个限流工具类——RateLimiter,本文也是通过使用该工具类来实现限流功能,RateLimiter是基于“令牌桶算法”来实现限流的。之前的的网关是使用“责任链设计模式”来重新构造了,本文也使用责任链模式添加RateLimiter来实现限流。

①添加 guava maven依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
</dependency>

②添加限流Handler:

/**
 * description: 服务限流
 * create by: YangLinWei
 * create time: 2020/5/26 3:00 下午
 */
@Component
@Slf4j
public class CurrentLimitHandler extends BaseHandler implements GatewayHandler {
    private RateLimiter rateLimiter = RateLimiter.create(1);
    @Autowired
    private GenerateToken generateToken;
    @Override
    public Boolean service(RequestContext ctx, String ipAddres, HttpServletRequest request, HttpServletResponse response) {
        // 1.用户限流频率设置 每秒中限制1个请求
        boolean tryAcquire = rateLimiter.tryAcquire(0, TimeUnit.SECONDS);
        if (!tryAcquire) {
            resultError(ctx, "There are too many people snapping up goods now. Please wait a moment!");
            return Boolean.FALSE;
        }
        // 2.使用redis限制用户访问频率
        String seckillId = request.getParameter("seckillId");
        String seckillToken = generateToken.getListKeyToken(seckillId + "");
        if (StringUtils.isEmpty(seckillToken)) {
            log.info(">>>seckillId:{}, The second kill has sold out, please come again next time!", seckillId);
            resultError(ctx, "The second kill has sold out, please come again next time!");
            return Boolean.FALSE;
        }
        if (gatewayHandler != null) {
            gatewayHandler.service(ctx, ipAddres, request, response);
        }
        return Boolean.TRUE;
    }
}

③工厂定义网关过滤步骤:

public class FactoryHandler {
    public static GatewayHandler getHandler() {
        // 1.黑名单拦截
        GatewayHandler handler1 = (GatewayHandler) SpringContextUtil.getBean("blackListHandler");
        // 2.API接口参数接口验签
        GatewayHandler handler2 = (GatewayHandler) SpringContextUtil.getBean("verifySignHandler");
        handler1.setNextHandler(handler2);
        // 3.参数过滤
        GatewayHandler handler3 = (GatewayHandler) SpringContextUtil.getBean("filterParamHandler");
        handler1.setNextHandler(handler3);
        //4.服务限流
        GatewayHandler handler4 = (GatewayHandler) SpringContextUtil.getBean("currentLimitHandler");
        handler3.setNextHandler(handler4);
        //5.验证accessToken
        GatewayHandler handler5 = (GatewayHandler) SpringContextUtil.getBean("apiAuthorityHandler");
        handler4.setNextHandler(handler5);
        return handler1;
    }
}

2.2 服务保护

①添加Hystrix maven依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

②启动类开启Hystrix

③服务接口保护

@Override
@Transactional
@HystrixCommand(fallbackMethod = "spikeFallback")
public BaseResponse<JSONObject> spike(String phone, Long seckillId) {
  // 1.参数验证
  if (StringUtils.isEmpty(phone)) {
    return setResultError("手机号码不能为空!");
  }
  if (seckillId == null) {
    return setResultError("商品库存id不能为空!");
  }
  // 2.从redis从获取对应的秒杀token
  String seckillToken = generateToken.getListKeyToken(seckillId + "");
  if (StringUtils.isEmpty(seckillToken)) {
    log.info(">>>seckillId:{}, 亲,该秒杀已经售空,请下次再来!", seckillId);
    return setResultError("亲,该秒杀已经售空,请下次再来!");
  }
  // 3.获取到秒杀token之后,异步放入mq中实现修改商品的库存
  sendSeckillMsg(seckillId, phone);
  return setResultSuccess("正在排队中.......");
}
private BaseResponse<JSONObject> spikeFallback(String phone, Long seckillId) {
  return setResultError("服务器忙,请稍后重试!");
}

3.测试

3.1 网关限流测试

浏览器访问http://localhost/api-spike/spike?phone=13800000001&seckillId=100001,可以看到:

在1秒钟之内继续访问,可以看到限流如下:

3.2 服务保护测试

服务保护测试采用JMeter来测试,由于测试条件的不允许,本文不再演示。如果要看演示的效果,可以参考之前写的博客《微服务技术系列教程(22) - SpringCloud- 服务保护机制Hystrix》

目录
相关文章
|
XML 安全 前端开发
Spring Security—Spring MVC 整合
Spring Security—Spring MVC 整合
458 1
快手自动抢红包辅助插件,快手抢红包福袋脚本全自动,智能抢包软件按键版
这是一套快手自动抢红包插件源码,通过模拟点击实现自动化操作。例如准备100个快手账号配合此插件挂机抢红包
|
8月前
|
前端开发
使用 async/await 结合 try/catch 处理 Promise.reject()抛出的错误时,有什么需要注意的地方?
使用 async/await 结合 try/catch 处理 Promise.reject()抛出的错误时,有什么需要注意的地方?
338 57
|
存储 Linux
在Linux中,LVM是什么?
在Linux中,LVM是什么?
|
XML Java 数据库连接
如何搭建SSM框架、图书商城系统
这是一份详尽的《Spring + SpringMVC + Mybatis 整合指南》,作者耗时良久整理出约五万字的内容,现已经全部笔记公开。此文档详细地介绍了如何搭建与整合SSM框架,具体步骤包括创建Maven项目、添加web骨架、配置pom文件以及整合Spring、SpringMVC和Mybatis等。无论是对初学者还是有一定基础的开发者来说,都是很好的学习资源。此外,作者还提供了项目源码的GitHub链接,方便读者实践。虽然当前主流推荐学习SpringBoot,但了解SSM框架仍然是不可或缺的基础。
150 0
|
Cloud Native Go 开发工具
如何让CSDN学习成就个人能力六边形全是100分:解析个人能力雷达图的窍门
如何让CSDN学习成就个人能力六边形全是100分:解析个人能力雷达图的窍门
528 0
|
存储 运维 Kubernetes
k8s学习笔记之StorageClass+NFS
k8s学习笔记之StorageClass+NFS
Shiro用户鉴权框架 子线程获取不到用户信息问题解决
Shiro用户鉴权框架 子线程获取不到用户信息问题解决
仿美团饿了么程序,外卖人9.0外卖订餐源码(PC+微信)
仿美团饿了么程序,外卖人9.0商业版外卖订餐源码,PC+微信+WAP+短信宝,多城市多色版 非常不错的独立版外卖跑腿网站源码,喜欢的可以下载调试看看吧!!
270 0
|
XML 安全 前端开发
post为什么会发送两次请求详解
【6月更文挑战第5天】在Web开发中,开发者可能会遇到POST请求被发送了两次的情况,
351 0