随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
依赖引入
<!--使其主动对所有的url进行统计,把所有的controller接口识别成资源--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-web-servlet</artifactId> <version>1.8.5</version> </dependency>
定义过滤器
package com.example.sentinel.config; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; /** * 该过滤器将controller自动定义为Sentinel资源 */ @Configuration public class SentinelFilter { @Bean public FilterRegistrationBean sentinelFilterRegistration() { FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); registration.setFilter(new CommonFilter()); registration.addUrlPatterns("/*"); registration.setName("sentinelFilter"); registration.setOrder(1); return registration; } }
排除同类URL
package com.example.sentinel.config; import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; import java.util.regex.Pattern; /** * 一些接口采用了 @PathVariable 注解,每一个url都会被识别成资源,但是sentinel最多支持6000个,所以需要处理 * 例如:/name/{id}可能会有/name/1、/name/2、/name/3,如果不处理就是三个资源,但是其实这是一个资源 */ public class WebUrlCleaner implements UrlCleaner { /** * 正则匹配 */ private static String PATTERN_SENTINEL_TEST_NAME = "^/name/[0-9a-zA-Z]+$"; private static String SENTINEL_RESOURCE_SENTINEL_TEST_NAME = "/name/*"; private static Pattern pattern = Pattern.compile(PATTERN_SENTINEL_TEST_NAME); @Override public String clean(String originUrl) { if (pattern.matcher(originUrl).matches()) { return SENTINEL_RESOURCE_SENTINEL_TEST_NAME; } else { return originUrl; } } }
异常统一处理
其默认的异常提示不友好,也不符合项目中的统一返回定义,所以需要针对该情况做修改
package com.example.sentinel.config; import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import com.alibaba.csp.sentinel.slots.system.SystemBlockException; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; public class WebUrlBlockHandler implements UrlBlockHandler { @Override public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException { HashMap<Object, Object> result = new HashMap<>(2); String msg = null; Integer code = 0; if (e instanceof FlowException) { msg = "系统繁忙"; code = 1; } else if (e instanceof BlockException) { msg = "系统繁忙"; code = 2; } else if (e instanceof ParamFlowException) { msg = "系统繁忙"; code = 3; } else if (e instanceof SystemBlockException) { msg = "系统繁忙"; code = 4; } result.put("code", code); result.put("msg", msg); response.setStatus(200); response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.writeValue(response.getWriter(), result); } }
把以上定义配置给Sentinel
package com.example.sentinel.config; import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; import org.springframework.context.annotation.Configuration; @Configuration public class InitSRule { static { //设置自定义的Block异常处理 WebCallbackManager.setUrlBlockHandler(new WebUrlBlockHandler()); //设置url清洗 WebCallbackManager.setUrlCleaner(new WebUrlCleaner()); } }
定义一个普通Controller
@RequestMapping("/getHello5") public String getHello5() { return "hello,now is :" + DateUtil.now(); }
访问该接口,就会在Sentinel控制台看到该资源
END
Java小强
未曾清贫难成人,不经打击老天真。
自古英雄出炼狱,从来富贵入凡尘。
发表评论: