本文共 10508 字,大约阅读时间需要 35 分钟。
熔断:当满足某个特定条件的时候,触发熔断,在熔断的时间内,接收到的请求将不会得到处理,而是快速失败响应给客户端.
sentinel提供了熔断功能,且熔断策略有三种:RT、异常比例和异常数量.熔断策略 | 含义 |
---|---|
RT | 平均响应时间超出阈值且在时间窗口内通过的请求数量>=5,两个条件同时满足后触发降级,窗口期过后关闭断路器 |
异常比例(秒级统计比例) | qps>=5且异常比例(秒级统计)超过阈值时,触发断路器;时间窗口结束后,关闭断路器 |
异常数 | 异常数超过阈值时,触发断路器;时间窗口结束后,关闭断路器 |
降级规则tab提供的就是熔断功能,只是sentinel文字描述个人觉得不是非常准确,只能说sentinel为自己的熔断功能也提供了降级功能,主功能在熔断.
package com.ccm.server.user.controller;import com.ccm.common.exception.result.ResultSet;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @Description sentinel熔断测试控制层 * @Author ccm * @CreateTime 2020/07/29 10:17 */@RestController@RequestMapping(value = "sentinelFusingTest")@Api(tags = "sentinel熔断测试控制层")public class SentinelFusingTestController { @ApiOperation(value = "rt熔断策略") @GetMapping(value = "test01") public ResultSet test01() throws InterruptedException { Thread.sleep(300L); return ResultSet.success("笑脸"); }}
配置的含义:在10秒钟内,如果请求数量大于5且请求的平均响应时间超过200毫秒,微服务在这个10秒钟的时间窗口开启断路器.10秒钟内,所有的请求不会访问到资源,会快速失败返回给客户端.断路器10秒之后自动关闭,允许客户端访问该资源.
10秒钟之内,发起20个请求.
填写url. 发起请求,查看结果树,可以看到20个请求中,5个请求成功,15个请求失败,并返回了Blocked by Sentinel (flow limiting).package com.ccm.server.user.controller;import com.ccm.common.exception.result.ResultSet;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @Description sentinel熔断测试控制层 * @Author ccm * @CreateTime 2020/07/29 10:17 */@RestController@RequestMapping(value = "sentinelFusingTest")@Api(tags = "sentinel熔断测试控制层")public class SentinelFusingTestController { @ApiOperation(value = "rt熔断策略") @GetMapping(value = "test01") public ResultSet test01() throws InterruptedException { Thread.sleep(300L); return ResultSet.success("笑脸"); } @ApiOperation(value = "异常比例熔断策略") @GetMapping(value = "test02") public ResultSet test02() { int i = 1/0; return ResultSet.success("笑脸"); }}
/*package com.ccm.common.handler;import com.ccm.common.exception.CcmMallException;import com.ccm.common.exception.CustomerException;import com.ccm.common.exception.ServerException;import com.ccm.common.exception.result.CodeEnum;import com.ccm.common.exception.result.ResultSet;import lombok.extern.slf4j.Slf4j;import org.apache.catalina.servlet4preview.http.HttpServletRequest;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.web.HttpMediaTypeNotAcceptableException;import org.springframework.web.HttpMediaTypeNotSupportedException;import org.springframework.web.HttpRequestMethodNotSupportedException;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.MissingPathVariableException;import org.springframework.web.bind.MissingServletRequestParameterException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;import org.springframework.web.servlet.NoHandlerFoundException;import javax.annotation.PostConstruct;import javax.validation.ConstraintViolationException;*//** * @Description 全局异常处理器 * @Author ccm * @CreateTime 2020/7/15 10:13 *//*@Slf4j@RestControllerAdvicepublic class GlobalExceptionHandler { *//** * 服务名 *//* @Value("${spring.application.name}") private String serverName; *//** * 错误信息前缀 *//* private String errorMessagePrefix; @PostConstruct public void init() { this.errorMessagePrefix = new StringBuffer().append("(") .append(this.serverName) .append("服务") .append("->") .append(") ").toString(); } *//** * @Description 处理系统内部异常(未知异常,入空指针,索引越界) * @Author ccm * @CreateTime 2020/7/15 10:13 * @Params [e, request] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = {Exception.class}) public ResultSet handlerException(Exception e, HttpServletRequest request) { log.error("请求路径uri={},系统内部出现异常:{}", request.getRequestURI(),e); ResultSet resultSet = ResultSet.error(CodeEnum.SYSTEM_INNER_ERROR,errorMessagePrefix+e.toString(),"服务器繁忙,请稍后再试"); return resultSet; } *//** * @Description 非法请求异常(SpringAOP) * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [exception] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = { HttpMediaTypeNotAcceptableException.class, HttpMediaTypeNotSupportedException.class, HttpRequestMethodNotSupportedException.class, MissingServletRequestParameterException.class, NoHandlerFoundException.class, MissingPathVariableException.class, HttpMessageNotReadableException.class }) public ResultSet handlerSpringAOPException(Exception exception) { ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix+exception.getMessage(),exception.getMessage()); return resultSet; } *//** * @Description 非法请求异常(@DateTimeFormat注解抛出异常) * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [e] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = MethodArgumentTypeMismatchException.class) public ResultSet handlerSpringAOPException(MethodArgumentTypeMismatchException e) { ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix+e.getMessage(),e.getMessage()); return resultSet; } *//** * @Description 非法请求(处理spring validation参数校验抛出异常1) * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [methodArgumentNotValidException] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = {MethodArgumentNotValidException.class}) public ResultSet handlerMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) { //获取异常字段及对应的异常信息 StringBuffer stringBuffer = new StringBuffer(); methodArgumentNotValidException.getBindingResult().getFieldErrors().stream() .map(t -> t.getField()+"=>"+t.getDefaultMessage()+" ") .forEach(e -> stringBuffer.append(e)); String errorMessage = stringBuffer.toString(); ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST, errorMessagePrefix+errorMessage,errorMessage); return resultSet; } *//** * @Description 非法请求异常(处理spring validation参数校验抛出异常2) * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [constraintViolationException] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = {ConstraintViolationException.class}) public ResultSet handlerConstraintViolationException(ConstraintViolationException constraintViolationException) { String errorMessage = constraintViolationException.getLocalizedMessage(); ResultSet resultSet = ResultSet.error(CodeEnum.ILLEGAL_REQUEST,errorMessagePrefix+errorMessage,errorMessage); return resultSet; } *//** * @Description 处理自定义异常-CustomException * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [e] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = {CustomerException.class}) public ResultSet handlerCustomException(CustomerException e) { String errorMessage = e.getErrorMessage(); ResultSet resultSet = ResultSet.error(e.getCodeEnum(), errorMessagePrefix+errorMessage,errorMessage); return resultSet; } *//** * @Description 处理自定义异常-ServerException * @Author ccm * @CreateTime 2020/7/15 10:14 * @Params [e] * @Return com.ccm.common.exception.result.ResultSet *//* @ExceptionHandler(value = {ServerException.class}) public ResultSet handlerServerException(ServerException e) { String errorMessage = e.getErrorMessage(); ResultSet resultSet = ResultSet.error(e.getCodeEnum(), errorMessagePrefix+errorMessage,errorMessage); return resultSet; }}*/
配置解读:以10秒钟为一个时间窗口期,qps(每秒的并发量)>=5且请求的异常比例大于50%(秒级统计比例)时,会触发断路器开启,时间窗口期结束,断路器关闭.
一秒钟内发起10个请求(保证qps>=5,且这秒级统计的异常比例会是100%,保证触发断路器).
填写url.
发起请求,查看结果树,可以看到从第6个请求开始,触发了断路器.
package com.ccm.server.user.controller;import com.ccm.common.exception.result.ResultSet;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @Description sentinel熔断测试控制层 * @Author ccm * @CreateTime 2020/07/29 10:17 */@RestController@RequestMapping(value = "sentinelFusingTest")@Api(tags = "sentinel熔断测试控制层")public class SentinelFusingTestController { @ApiOperation(value = "rt熔断策略") @GetMapping(value = "test01") public ResultSet test01() throws InterruptedException { Thread.sleep(300L); return ResultSet.success("笑脸"); } @ApiOperation(value = "异常比例熔断策略") @GetMapping(value = "test02") public ResultSet test02() { int i = 1/0; return ResultSet.success("笑脸"); } @ApiOperation(value = "异常数熔断策略") @GetMapping(value = "test03") public ResultSet test03() { int i = 1/0; return ResultSet.success("笑脸"); }}
配置含义:在10秒钟的时间窗口内,如果异常数超过5个,断路器会开启.10秒钟以后断路器关闭,恢复正常,进入下一个10秒时间窗口.
10秒钟发出6个请求.
配置url 发起请求,查看结果树,发现第6个请求开始,断路器被打开了. 至此,完事!源码地址:
您的点赞、收藏、转发和关注是我持续创作的动力!
转载地址:http://pktli.baihongyu.com/