A lightweight powerful flow control component enabling reliability and monitoring for microservices. (轻量级的流量控制、熔断降级 Java 库).中文文档html
雪崩效应又称cascading failure(级联故障),指基础服务故障致使上层服务故障而且故障像雪球同样越滚越大。java
<!--sentinel-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sentinel</artifactId>
</dependency>
复制代码
无
复制代码
无
复制代码
打开全部端点查看是否生效git
# actuator
management:
endpoints:
web:
exposure:
# 生产不能所有放开且需配置安全措施
include: '*'
复制代码
出现如下内容证实整合成功了github
下载咱们pom文件定义的相同版本的Sentinel。下载地址web
#启动
java -jar XXX.jar
复制代码
spring:
cloud:
sentinel:
transport:
# 指定sentinel控制台地址
dashboard: localhost:8080
复制代码
流控规则spring
直接apache
关联:关联资源达到阈值,限流本身json
链路:指定链路上的流量api
// 定义一个common服务
package com.virgo.user.service;
import com.virgo.entity.TblCar;
/**
* @author zhaozha
* @date 2019/10/15 下午4:27
*/
public interface CommonService {
TblCar common();
}
package com.virgo.user.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.virgo.entity.TblCar;
import org.springframework.stereotype.Service;
/**
* @author zhaozha
* @date 2019/10/15 下午4:28
*/
@Service
public class CommonServiceImpl implements CommonService {
@Override
@SentinelResource("common")
public TblCar common() {
return TblCar.builder().id(1L).build();
}
}
// controller层同时调用这个服务
@GetMapping("/test/a")
public String testA() {
commonServiceImpl.common();
return "testA";
}
@GetMapping("/test/b")
public String testB() {
commonServiceImpl.common();
return "testB";
}
复制代码
降级规则安全
热点规则
系统规则
受权规则
微服务注册/心跳到控制台,控制台经过api获取/推送消息
spring:
cloud:
sentinel:
transport:
控制台地址
dashboard:
和控制台通讯的ip
client-ip:
和控制通讯端口(默认8719,若是已经占用,+1直到找到)
port:
心跳毫秒
heartbeat-interval-ms:
复制代码
配置项 | 默认值 | 描述 |
---|---|---|
server.port | 8080 | 指定端口 |
csp.sentinel.dashboard.server | localhost:8080 | 指定地址 |
project.name | - | - |
sentinel.dashboard.auth.username[1.6] | sentinel | Dashboard登录帐号 |
sentinel.dashboard.auth.password[1.6] | sentinel | Dashboard登录密码 |
server.servlet.session.timeout[1.6] | 30分钟 | 登录session过时时间(7200:7200秒/60m:60分钟) |
@GetMapping("/test/sentinel/api")
public String testSentinelApi(@RequestParam(required = false) String a) {
String resourceName = "test-sentinel-api";
ContextUtil.enter(resourceName, "test");
Entry entry = null;
try {
entry = SphU.entry(resourceName);
if (StringUtils.isBlank(a)) {
throw new IllegalArgumentException("参数不可为空");
}
return a;
} catch (BlockException e) {
return "限流/降级了";
} catch (IllegalArgumentException e) {
Tracer.trace(e);
return "参数非法";
} finally {
if (entry != null) {
entry.exit();
}
ContextUtil.exit();
}
}
复制代码
经过@SentinelResource简化代码
package com.virgo.user.sentinel;
import com.alibaba.csp.sentinel.slots.block.BlockException;
/**
* @author zhaozha
* @date 2019/10/16 下午3:11
*/
public class ControllerBlockHandlerClass {
/**
* 处理限流/降级
*
* @param a
* @param e
* @return
*/
public static String block(String a, BlockException e) {
return "降级/限流了";
}
}
@GetMapping("/test/sentinel/api")
@SentinelResource(
value = "test-sentinel-api",
blockHandler = "block",
blockHandlerClass = com.virgo.user.sentinel.ControllerBlockHandlerClass.class
)
public String testSentinelApi(@RequestParam(required = false) String a) {
if (StringUtils.isBlank(a)) {
throw new IllegalArgumentException("参数不可为空");
}
return a;
}
复制代码
@Bean
@LoadBalanced
@SentinelRestTemplate
public RestTemplate restTemplate(){
return new RestTemplate();
}
复制代码
resttemplate:
sentinel:
enabled:
复制代码
feign:
#feign整合sentinel
sentinel
enable: true
复制代码
自定义返回报文
package com.virgo.user.feignclient;
import com.virgo.entity.TblCar;
import com.virgo.user.configuration.GlobalFeignConfiguration;
import com.virgo.user.feignclient.fallback.LockCenterFeignClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author zhaozha
* @date 2019/10/11 下午12:52
*/
@FeignClient(name = "lock-center", configuration = GlobalFeignConfiguration.class,fallback = LockCenterFeignClientFallback.class)
public interface LockCenterFeignClient {
@GetMapping("/lock/test/{id}")
TblCar findById(@PathVariable(value="id") Long id);
}
package com.virgo.user.feignclient.fallback;
import com.virgo.entity.TblCar;
import com.virgo.user.feignclient.LockCenterFeignClient;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/16 下午3:36
*/
@Component
public class LockCenterFeignClientFallback implements LockCenterFeignClient {
@Override
public TblCar findById(Long id) {
return TblCar.builder().level(1).build();
}
}
复制代码
package com.virgo.user.feignclient;
import com.virgo.entity.TblCar;
import com.virgo.user.configuration.GlobalFeignConfiguration;
import com.virgo.user.feignclient.fallbackFactory.LockCenterFeignClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @author zhaozha
* @date 2019/10/11 下午12:52
*/
@FeignClient(name = "lock-center", configuration = GlobalFeignConfiguration.class,fallbackFactory = LockCenterFeignClientFallbackFactory.class)
public interface LockCenterFeignClient {
@GetMapping("/lock/test/{id}")
TblCar findById(@PathVariable(value="id") Long id);
}
package com.virgo.user.feignclient.fallbackFactory;
import com.virgo.entity.TblCar;
import com.virgo.user.feignclient.LockCenterFeignClient;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author zhaozha
* @date 2019/10/16 下午4:02
*/
@Component
@Slf4j
public class LockCenterFeignClientFallbackFactory implements FallbackFactory<LockCenterFeignClient> {
@Override
public LockCenterFeignClient create(Throwable throwable) {
return new LockCenterFeignClient() {
@Override
public TblCar findById(Long id) {
log.info("限流/降级",throwable);
return TblCar.builder().level(1).build();
}
};
}
}
复制代码
使用方式 | 使用方式 | 使用方法 |
---|---|---|
编码方式 | API | try...catch...finally |
注解方式 | @SentinelResource | blockHandler/fallback |
RestTemplate | @SentinelRestTemplate | blockHandler/fallback |
Feign | feign.sentinel.enabled | fallback/fallbackFactory |
阿里云服务(AHAS)
package com.virgo.user.sentinel;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
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.databind.ObjectMapper;
import com.virgo.dto.CommonResult;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author zhaozha
* @date 2019/10/17 上午9:49
*/
@Component
public class VirgoUrlBlockHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
// 统一返回对象
CommonResult commonResult = null;
// 流控
if(e instanceof FlowException){
commonResult = CommonResult.builder().status(100).msg("流控异常").build();
}
// 降级
else if(e instanceof DegradeException){
commonResult = CommonResult.builder().status(101).msg("降级异常").build();
}
// 热点
else if(e instanceof ParamFlowException){
commonResult = CommonResult.builder().status(102).msg("热点异常").build();
}
// 系统
else if(e instanceof SystemBlockException){
commonResult = CommonResult.builder().status(102).msg("系统异常").build();
}
// 受权
else if (e instanceof AuthorityException){
commonResult = CommonResult.builder().status(102).msg("受权异常").build();
}
httpServletResponse.setStatus(500);
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
httpServletResponse.setContentType("application/json;charset=utf-8");
new ObjectMapper()
.writeValue(
httpServletResponse.getWriter(),
commonResult
);
}
}
复制代码
package com.virgo.user.sentinel;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @author zhaozha
* @date 2019/10/17 上午11:51
*/
@Component
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
// todo 改为header
String origin = httpServletRequest.getParameter("origin");
if (StringUtils.isBlank(origin)) {
throw new IllegalArgumentException("origin must be specified");
}
return origin;
}
}
复制代码
package com.virgo.user.sentinel;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @author zhaozha
* @date 2019/10/17 下午12:05
*/
@Component
public class VirgoUrlCleaner implements UrlCleaner {
@Override
public String clean(String originUrl) {
// todo 多参数
String[] split = originUrl.split("/");
return Arrays.stream(split)
.map(string -> {
if (NumberUtils.isNumber(string)) {
return "{number}";
}
return string;
})
.reduce((a, b) -> a + "/" + b)
.orElse("");
}
}
复制代码