每天多学一点点~
话不多说,这就开始吧…
不得不说,Hystrix再sentinel面前就是个弟弟~
sentinel git地址
默认账号密码是 sentinel
其实与这些第三方组件整合,无非就是三板斧
org.springframework.cloud
spring-cloud-dependencies
Greenwich.SR3
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.1.RELEASE
pom
import
com.alibaba.cloud
spring-cloud-alibaba-nacos-discovery
com.alibaba.csp
sentinel-core
1.7.0
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
org.springframework.boot
spring-boot-starter-actuator
spring:
datasource:
xxxxxx : 这里就不写了 db的配置
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:9999
#namespace: bc7613d2-2e22-4292-a748-48b78170f14c #指定namespace的id
application:
name: order-center
main:
allow-bean-definition-overriding: true
server:
port: 8080
management:
endpoints:
web:
exposure:
include: '*'
启动项目+nacos+sentinel dashboard 三个,随便访问一个项目接口,比如我这里的
http://localhost:8080/saveOrder
在 sentinel dashboard 中便会又显示(记住,首先要访问一次自己的端口,才会有显示)
我们给其加入 一个 流控规则 阈值为1
多访问几次接口 ,出现 Blocked by Sentinel (flow limiting) 说明被流控,成功
sentinel功能很强大,其他 关于 限流 降级 的配置 可以去git上自己去看看,这里就不演示了
sentinel git地址
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:9999
#是否开启@SentinelRestTemplate注解
resttemplate:
sentinel:
enabled: true
@Configuration
public class WebConfig {
@Bean
@LoadBalanced
@SentinelRestTemplate(
blockHandler = "handleException",blockHandlerClass = GlobalExceptionHandler.class,
fallback = "fallback",fallbackClass = GlobalExceptionHandler.class
)
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
GlobalExceptionHandler 是自己的全局异常处理类,这里简单的写一下
@Slf4j
public class GlobalExceptionHandler {
/**
* 限流后处理方法
*/
public static SentinelClientHttpResponse handleException(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductName("被限制流量拉");
productInfo.setProductNo("-1");
ObjectMapper objectMapper = new ObjectMapper();
try {
return new SentinelClientHttpResponse(objectMapper.writeValueAsString(productInfo));
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
/**
* 熔断后处理的方法
*/
public static SentinelClientHttpResponse fallback(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductName("被降级拉");
productInfo.setProductNo("-1");
ObjectMapper objectMapper = new ObjectMapper();
try {
return new SentinelClientHttpResponse(objectMapper.writeValueAsString(productInfo));
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
}
com.alibaba.csp
sentinel-core
1.7.0
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.boot
spring-boot-starter-actuator
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:9999
feign:
httpclient:
enabled: true # #让feign底层使用HttpClient去调用
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 为每个url请求设置最大连接数
client:
config:
dafult:
connectTimeout: 5000
readTime: 5000
product-center: # 要调用服务的名称
loggerLevel: FULL # 日志级别
sentinel:
enabled: true # 打开 Sentinel 对 Feign 的支持 这样@FeignClient的fallback 才会生效
//@FeignClient(name = "product-center",fallback = ProductCenterFeignApiWithSentinelFallback.class)
@FeignClient(name = "product-center",fallbackFactory = ProductCenterFeignApiWithSentielFallbackFactory.class)
public interface ProductCenterFeignApiWithSentinel {
/**
* 声明式接口,远程调用http://product-center/selectProductInfoById/{productNo}
* @param productNo
* @return
*/
@RequestMapping("/selectProductInfoById/{productNo}")
ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
}
FallbackFactory 能区别异常
@Component
@Slf4j
public class ProductCenterFeignApiWithSentielFallbackFactory implements FallbackFactory {
@Override
public ProductCenterFeignApiWithSentinel create(Throwable throwable) {
return new ProductCenterFeignApiWithSentinel(){
@Override
public ProductInfo selectProductInfoById(String productNo) {
log.error("原因:{}",throwable);
ProductInfo productInfo = new ProductInfo();
productInfo.setProductName("默认商品");
return productInfo;
}
};
}
}
Fallback 不能区别异常
@Component
public class ProductCenterFeignApiWithSentinelFallback implements ProductCenterFeignApiWithSentinel {
@Override
public ProductInfo selectProductInfoById(String productNo) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductName("默认商品");
return productInfo;
}
}
到此整合结束,但是 ,sentinel不支持持久化 ,即 你重启sentinel dashboard 或者 项目工程,你配置在sentinel中的流控降级等等规则全部 没了,这也是阿里比较坑的地方,为何,因为阿里云上有AHAS。。。
那么 下篇,来分享下 sentinel 持久化的 三种方式
sentinel默认情况下,无论你是限流还是降级,触发了都会返回
这样返回实在太不友好了,所以要加入自己的配置
@Component
public class QiuqiuUrlBlockHandler implements UrlBlockHandler {
public static final Logger log = LoggerFactory.getLogger(QiuqiuUrlBlockHandler.class);
/**
* 接口中加了feign,则 在 控制台中会既会显示接口 也会也是 feign的调用接口
* 看你 限流哪个 ,限流feign 就走feign的fallback
* 限流原来接口,则走下面的逻辑
* @return
*/
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
if(ex instanceof FlowException) {
log.warn("触发了流控");
warrperResponse(response, ErrorEnum.FLOW_RULE_ERR);
}else if(ex instanceof ParamFlowException) {
log.warn("触发了参数流控");
warrperResponse(response,ErrorEnum.HOT_PARAM_FLOW_RULE_ERR);
}else if(ex instanceof AuthorityException) {
log.warn("触发了授权规则");
warrperResponse(response,ErrorEnum.AUTH_RULE_ERR);
}else if(ex instanceof SystemBlockException) {
log.warn("触发了系统规则");
warrperResponse(response,ErrorEnum.SYS_RULE_ERR);
}else{
log.warn("触发了降级规则");
warrperResponse(response,ErrorEnum.DEGRADE_RULE_ERR);
}
}
private void warrperResponse(HttpServletResponse httpServletResponse, ErrorEnum errorEnum) throws IOException {
httpServletResponse.setStatus(500);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
httpServletResponse.setContentType("application/json;charset=utf-8");
ObjectMapper objectMapper = new ObjectMapper();
String errMsg =objectMapper.writeValueAsString(new ErrorResult(errorEnum));
httpServletResponse.getWriter().write(errMsg);
}
}
根据异常类型,自定义返回值返给前台
。
注意:若接口中加了feign,则 在 控制台中会既会显示接口 ,也会显示 feign的调用接口
看你限流哪个 ,若限流feign 就走feign的fallback。 若限流原来接口,则走UrlBlockHandler 逻辑。
ribbon同理。
世上无难事,只怕有心人,每天积累一点点,fighting!!!