微服务-服务容错(续)

1.降级规则

降级规则就是设置当满⾜什么条件的时候,对服务进⾏降级。 Sentinel 提供了三个衡量条件:

  • 慢调用比例:当资源的响应时间超过最⼤RT(以ms为单位,最⼤RT即最⼤响应时间)之后,资源进⼊准降 级状态。如果接下来1ms内持续进⼊5 个请求(最⼩请求数),他们的RT都持续超过这个阈值,那么在接下 的熔断时⻓(以s为单位)之内,就会对这个⽅法进⾏服务降级。
  • 异常⽐例:当资源的每秒异常总数占通过量的⽐值数超过阈值之后,资源进⼊降级状态,即在接下来的熔断 时⻓之内,对这个⽅法的调⽤都会⾃动地返回。异常⽐率的阈值范围是[0.0,1.0]。
  • 异常数:当资源近统计时⻓的异常数⽬超过阈值(异常数)之后会进⾏服务降级

1.1例子:

1.1.1慢调用比例

controller类中新建f1方法

java 复制代码
@GetMapping("/f1")
    @SneakyThrows
    public JsonResult f1() {
        Thread.sleep(15);
        return ResultTool.success("This is SentinelConsumerController`f1 method!");
    }

点击一秒内大于5次出现下图所示情况

1.1.2异常比例

在controller类中新建f2方法

java 复制代码
 @GetMapping("/f2")
    public JsonResult f2(@RequestParam("b") int b) {
        int a=9/b;
        return ResultTool.success("This is SentinelConsumerController`f1 method!");
    }

让b=0,即为错

10秒内5次请求错两次出现下图效果

1.1.3异常数

与异常比例相同,只有下述图片内容不同

2.热点规则

热点参数流控规则是⼀种更细粒度的流控规则,它允许将规则具体到参数上。

2.1例子

2.1.1在controller类中新建g方法

java 复制代码
@GetMapping("/g")
    @SentinelResource("messageG")
    public JsonResult g(String a,int b,char c) {
        return ResultTool.success("This is SentinelConsumerController`g method!");
    }

2.1.2新增热点规则

2.1.3高级选项

保存后最好再查看一下

如果是下图参数,限流100次

如果c不等于a

出现错误

3.授权规则

很多时候,我们需要根据调⽤来源来限制资源是否通过,这时候可以使⽤ Sentinel 的⿊⽩名单的功能,⿊⽩名单 根据资源的请求来源(origin)限制资源是否通过。

  • 若配置⽩名单则只有请求来源位于⽩名单内时才可通过。
  • 若配置⿊名单则请求来源位于⿊名单时不通过,其余的请求通过。

3.1例子

3.1.1新建parser包,在其中新建FirstRequestOriginParse类

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.parser;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
//自定义黑白名单
public class FirstRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        return request.getParameter("origin");
    }
}

3.2.2在controller类中新建h方法

java 复制代码
@GetMapping("/h")
    public JsonResult h(String origin) {
        return ResultTool.success("This is SentinelConsumerController`h method!");
    }

pc为白名单

pc,phone为黑名单

3.2.3header方式(使用APIPOST测试)

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.parser;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
//自定义黑白名单
public class FirstRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        return request.getHeader("origin");
    }
}

4.自定义异常返回

4.1整体

创建⼀个类实现BlockExceptionHandler 接⼝(整体)

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.handler;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
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.alibaba.fastjson.JSONArray;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;

@Slf4j
//@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        log.error("SentinelExceptionHandler handle exception", e);
        // BlockException 异常接⼝,包含Sentinel的五个异常
        // FlowException 限流异常
        // DegradeException 降级异常
        // ParamFlowException 参数限流异常
        // AuthorityException 授权异常
        // SystemBlockException 系统负载异常
        JsonResult result=null;
        if (e instanceof FlowException){
            result= ResultTool.fail("限流异常",401);
        }else if (e instanceof DegradeException){
            result=ResultTool.fail("降级异常",402);
        }else if (e instanceof ParamFlowException){
            result=ResultTool.fail("参数限流异常",403);
        }else if (e instanceof AuthorityException){
            result=ResultTool.fail("授权异常",404);
        }else if (e instanceof SystemBlockException){
            result=ResultTool.fail("系统负载异常",405);
        }else {
            result=ResultTool.fail("其他异常",406);
        }
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out=response.getWriter();
        out.print(JSONArray.toJSONString(result));
    }
}

依次进入Sentinel测试即可

4.2局部

新建MyBlockingAndFallbackHandler类

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;

public class MyBlockingAndFallbackHandler {
    public static JsonResult aBlockingMethod(BlockException e) {
        return ResultTool.fail("BlockException is"+e.getMessage(),401);
    }
    public static JsonResult bBlockingMethod(String name,Integer age,BlockException e) {
        return ResultTool.fail("Method b blockes for name"+name+" ,BlockException is"+e.getMessage(),402);
    }
    public static JsonResult cFallbackMethod(int a,Throwable e) {
        return ResultTool.fail("错了,"+e.getMessage(),403);
    }
}

新建SentinelConsumerBlockingController接口

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.handler.MyBlockingAndFallbackHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sentinel_consumer_blocking")
public class SentinelConsumerBlockingController {
    @SentinelResource(value = "aBlockingMessage", blockHandler = "aBlockingMethod",blockHandlerClass = MyBlockingAndFallbackHandler.class)
    @GetMapping("/a")
    public JsonResult a() {
        return ResultTool.success("This is SentinelConsumerBlockingController`a method!");
    }

    @SentinelResource(value = "bBlockingMessage", blockHandler = "bBlockingMethod", blockHandlerClass = MyBlockingAndFallbackHandler.class)
    @GetMapping("/b")
    public JsonResult b(@RequestParam String name, @RequestParam Integer age) {
        return ResultTool.success("This is method b with name: " + name + ", age: " + age);
    }


    @SentinelResource(value = "cBlockingMessage", blockHandler = "cBlockingMethod", fallback = "cFallbackMethod", fallbackClass = MyBlockingAndFallbackHandler.class)
    @GetMapping("/c")
    public JsonResult c(@RequestParam("a") int a) {
        int result = 9 / a;
        return ResultTool.success("cccc");
    }
}

进入Sentinel测试即可

5.Sentinel规则持久化

通过前⾯的讲解,我们已经知道,可以通过 Dashboard 来为每个 Sentinel 客户端设置各种各样的规则,但是这 ⾥有⼀个问题,就是这些规则默认是存放在内存中,极不稳定,所以需要将其持久化。 本地⽂件数据源会定时轮询⽂件的变更,读取规则。这样我们既可以在应⽤本地直接修改⽂件来更新规则,也可以 通过 Sentinel 控制台推送规则。以本地⽂件数据源为例,推送过程如下图所示:

5.1新建持久化类

file.FilePersistence

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.file;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;

@Component
public class FilePersistence implements InitFunc {

    @Value("${spring.application.name}")
    private String applicationName = null;

    @Override
    public void init() throws Exception {
        System.out.println(1111111);
//指定⽂件⽣成⽬录
        String applicationName = this.applicationName == null ? "cloud-sentinel-consumer" : this.applicationName;
        String ruleDir = System.getProperty("user.home") + "/sentinelRules/" +
                applicationName;
        System.out.println("path:"+ruleDir);
        String flowRulePath = ruleDir + "/flow-rule.json";
        String degradeRulePath = ruleDir + "/degrade-rule.json";
        String systemRulePath = ruleDir + "/system-rule.json";
        String authorityRulePath = ruleDir + "/authority-rule.json";
        String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
        this.mkdirIfNotExits(ruleDir);
        this.createFileIfNotExits(flowRulePath);
        this.createFileIfNotExits(degradeRulePath);
        this.createFileIfNotExits(systemRulePath);
        this.createFileIfNotExits(authorityRulePath);
        this.createFileIfNotExits(paramFlowRulePath);
// 流控规则
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new
                FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new
                FileWritableDataSource<>(
                flowRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
// 降级规则
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new
                FileRefreshableDataSource<>(
                degradeRulePath,
                degradeRuleListParser
        );
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new
                FileWritableDataSource<>(
                degradeRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
// 系统规则
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new
                FileRefreshableDataSource<>(
                systemRulePath,
                systemRuleListParser);
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new
                FileWritableDataSource<>(
                systemRulePath,
                this::encodeJson);
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
// 授权规则
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new
                FileRefreshableDataSource<>(
                authorityRulePath,
                authorityRuleListParser
        );
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                authorityRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
// 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new
                FileRefreshableDataSource<>(
                paramFlowRulePath,
                paramFlowRuleListParser
        );
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new
                FileWritableDataSource<>(paramFlowRulePath,
                this::encodeJson
        );
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }

    private Converter<String, List<FlowRule>> flowRuleListParser = source ->
            JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
            });
    private Converter<String, List<DegradeRule>> degradeRuleListParser = source
            -> JSON.parseObject(
            source,
            new TypeReference<List<DegradeRule>>() {
            });
    private Converter<String, List<SystemRule>> systemRuleListParser = source ->
            JSON.parseObject(
                    source,
                    new TypeReference<List<SystemRule>>() {
                    });
    private Converter<String, List<AuthorityRule>> authorityRuleListParser =
            source -> JSON.parseObject(
                    source,
                    new TypeReference<List<AuthorityRule>>() {
                    });
    private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser =
            source -> JSON.parseObject(
                    source,
                    new TypeReference<List<ParamFlowRule>>() {
                    });

    private void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    private void createFileIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    private <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }
}

5.2添加配置

在 resources 下创建配置⽬录 META-INF/services ,然后添加⽂件 com.alibaba.csp.sentinel.init.InitFunc 。(必须一致)

在⽂件中添加配置类的全路径

启动,在Sentinel(懒加载)中添加规则,进行测试

6.Feign 整合 Sentinel

6.1引入依赖

6.2配置文件(消费者)

在配置⽂件中开启 Feign 对 Sentinel 的⽀持

6.3修改SentinelProviderFeign

加入fallback="SentinelProviderFeignImpl.class"

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl.SentinelProviderFeignImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(value = "cloud-sentinel-provider", path = "sentinel_provider", fallback = SentinelProviderFeignImpl.class)
public interface SentinelProviderFeign {

    @GetMapping("/a")
    JsonResult a();

    @GetMapping("/b")
    JsonResult b();
}

6.4新建SentinelProviderFeignImpl类

java 复制代码
package com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.impl;

import com.jiazhong.mingxing.cloud.commons.util.JsonResult;
import com.jiazhong.mingxing.cloud.commons.util.ResultTool;
import com.jiazhong.mingxing.project.cloud.sentinel.provider.feign.SentinelProviderFeign;
import org.springframework.stereotype.Component;

@Component
public class SentinelProviderFeignImpl implements SentinelProviderFeign {
    @Override
    public JsonResult a() {
        return ResultTool.success("你要访问sentinel_provider的a()方法,但是a方法出现了问题,我是备选方案a");
    }

    @Override
    public JsonResult b() {
        return ResultTool.success("你要访问sentinel_provider的b()方法,但是b方法出现了问题,我是备选方案b");

    }
}

provider项目启动后,备选方案失效

相关推荐
m0_376137941 小时前
DevUI主题系统进阶:CSS-in-JS与暗黑模式无缝切换架构
javascript·css·架构·devui
不是笨小孩i1 小时前
多元算力融合实践:openEuler在中等配置硬件环境下的性能验证
云原生·serverless
好游科技1 小时前
开源IM即时通讯软件开发社交系统全解析:安全可控、功能全面的
安全·架构·交友·im即时通讯·社交软件·社交语音视频软件
星哥说事1 小时前
存储:PV / PVC / StorageClass 动态存储供给(K8s 存储核心篇)
云原生·容器·kubernetes
xiejava10181 小时前
企业级私有docker镜像仓库Harbor的搭建和使用
运维·docker·云原生·容器
Tony Bai1 小时前
Go 2025云原生与可观测年度报告:底层性能革新与生态固防
开发语言·后端·云原生·golang
神算大模型APi--天枢6461 小时前
聚合模型 API 算力平台:前端开发的强劲助力
大数据·人工智能·科技·架构·gpu算力
初九之潜龙勿用1 小时前
openEuler 24.03 LTS 云原生环境部署与企业实践
云原生
西格电力科技1 小时前
源网荷储如何重塑能源产业格局
大数据·运维·人工智能·架构·能源