电商系统中进行流量控制

  1. 概述

任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们要根据系统的处理能力对流量进行控制。

流量控制的原理是监控应用的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性

  1. Sentinel简介

sentinel是面向分布式服务框架的轻量级流量控制框架,主要以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度来维护系统的稳定性

  1. Sentinel流量控制简介

Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;

  • 运行指标,例如 QPS、线程池、系统负载等;

  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

  1. Sentinel流量控制功能的使用

接下来,以b2b2c电商系统Javashop为例,具体说明Sentinel流量控制功能的使用

 

1. pom.xml文件中引入依赖
 1    <dependency>
 2             <groupId>com.alibaba.csp</groupId>
 3             <artifactId>sentinel-transport-simple-http</artifactId>
 4             <version>1.8.0</version>
 5         </dependency>
 6         <dependency>
 7             <groupId>org.springframework.cloud</groupId>
 8             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 9             <version>0.2.0.RELEASE</version>
10         </dependency>
11         <dependency>
12             <groupId>com.alibaba.csp</groupId>
13             <artifactId>sentinel-spring-webmvc-adapter</artifactId>
14             <version>1.8.0</version>
15         </dependency>
2.application.yml加入sentinel配置
 1 spring:
 2   cloud:
 3     sentinel:
 4       transport:
 5           #sentinel控制台地址(可有可无,不影响程序运行)
 6         dashboard: localhost:8080
 7 sentinel:
 8   #true:限制所有资源  false:只限制resources下定义的资源
 9   limit-all: true
10   #限流阈值,每秒钟限制的请求数
11   count: 5
12   #要限流的资源(若限制所有资源,此项配置无效)
13   resources:
14     - 'GET:/regions/{id}/children'
15     - 'GET:/regions/depth/{depth}'
3.初始化限流规则
 1 @Component
 2 public class InitFlowRules implements ServletContextListener {
 3 
 4     @Autowired
 5     private RequestMappingHandlerMapping handlerMapping;
 6     @Autowired
 7     private SentinelConfig sentinelConfig;
 8 
 9     private final Logger logger = LoggerFactory.getLogger(this.getClass());
10 
11     @Override
12     public void contextInitialized(ServletContextEvent sce) {
13         List<String> resources = new ArrayList<>();
14 
15 
16         //添加所有资源的规则
17         if(sentinelConfig.isLimitAll()){
18             Set<RequestMappingInfo> rmSet = handlerMapping.getHandlerMethods().keySet();
19             for (RequestMappingInfo rm : rmSet) {
20                 try{
21                     String path = rm.getPatternsCondition().toString();
22                     String method = rm.getMethodsCondition().toString();
23                     path = path.replace("[", "").replace("]", "");
24                     method = method.replace("[", "").replace("]", "");
25                     String resource = method + ":" + path;
26                     resources.add(resource);
27                 }catch (Exception e){
28                     e.printStackTrace();
29                 }
30             }
31         }else {
32             resources = sentinelConfig.getResources();
33         }
34 
35         if(!StringUtil.isNotEmpty(resources)){
36             return;
37         }
38 
39         List<FlowRule> rules = new ArrayList<>();
40         Integer count = sentinelConfig.getCount();
41         for(String resource : resources){
42             FlowRule rule = new FlowRule();
43             rule.setResource(resource);
44             rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
45             rule.setCount(count);
46             rules.add(rule);
47             logger.info(resource);
48         }
49         FlowRuleManager.loadRules(rules);
50     }
51 
52     @Override
53     public void contextDestroyed(ServletContextEvent sce) {
54 
55     }
56 }
4.配置限流拦截器
 1 @Configuration
 2 public class SentinelWebMvcConfiguration implements WebMvcConfigurer {
 3 
 4     @Autowired
 5     private SentinelConfig sentinelConfig;
 6 
 7 
 8     @Override
 9     public void addInterceptors(InterceptorRegistry registry) {
10         SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
11         //指定 请求方法 POST  GET 等等
12         sentinelWebMvcConfig.setHttpMethodSpecify(true);
13         //默认使用统一Web上下文   如果希望支持链路关系的流控策略则应该设置为false
14         sentinelWebMvcConfig.setWebContextUnify(true);
15         // 统一的 BlockException 处理  FlowException(BlockException) 会被 JVM 的 UndeclaredThrowableException 包裹一层  某种原因并不能捕获到异常
16         sentinelWebMvcConfig.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
17         // 用来标识来源 可针对性的对特定客户端的请求进行流控   limitApp
18 //        sentinelWebMvcConfig.setOriginParser(request -> {
19 //            String remoteAddr = "default";
20 //            try {
21 //                remoteAddr = getIpAddress(request);
22 //            } catch (IOException e) {
23 //                e.printStackTrace();
24 //            }
25 //            return remoteAddr;
26 //        });
27  //       sentinelWebMvcConfig.setOriginParser(request -> request.getParameter("app"));
28 
29         //对原始的URL进行处理,比如去掉锚点之类的    /foo/bar?a=3#title  ->   /foo/bar?a=3
30 //        sentinelWebMvcConfig.setUrlCleaner( );
31         registry.addInterceptor(new SentinelWebInterceptor(sentinelWebMvcConfig)).addPathPatterns("/**");
32     }
33 
34 }
5.限流全局异常处理
 1 public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
 2 
 3     @Override
 4     public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
 5         httpServletResponse.setStatus(500);
 6         httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
 7         httpServletResponse.getWriter().print("{"code":"500","message":"请求被限制,请稍后重试"}");
 8         httpServletResponse.getWriter().flush();
 9     }
10 }
原文地址:https://www.cnblogs.com/javashop-docs/p/14272779.html