-
概述
任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们要根据系统的处理能力对流量进行控制。
流量控制的原理是监控应用的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性
-
Sentinel简介
sentinel是面向分布式服务框架的轻量级流量控制框架,主要以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度来维护系统的稳定性
-
Sentinel流量控制简介
Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示
流量控制有以下几个角度:
-
资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
-
运行指标,例如 QPS、线程池、系统负载等;
-
控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
-
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 }