Sentinel文档学习系列——1.Sentinel初体验

本系列文章通过学习Sentinel官方文档而后整理

Sentinel是分布式系统的流量卫兵,Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

首先需要理解Sentinel中的2个概念,资源 和 规则

资源 在Sentinel中是受保护的对象,资源可以是任何项目中的东西,可以是服务、方法(接口)、若干行代码
规则 是制定来规范如何保护资源的,Sentinel提供在任何时候都可以灵活地定义流量控制规则a

所以在官方文档中,定义的Sentinel进行资源保护的几个步骤:

  1. 定义资源
  2. 定义规则
  3. 检验规则是否生效

Sentinel适配大部分主流框架,Dubbo,Spring Cloud,gRPC等等,但是一切从简,让我们从最简单的maven环境体验Sentinel的本领

首先我们需要定义资源,至于如何定义资源,主要有以下2种方式

  1. Sentinel API,使用SphU.entry("自定义资源名")和entry.exit()包裹的代码,就是资源
try {
  // 资源名可使用任意有业务语义的字符串
  entry = SphU.entry("自定义资源名");
  // 被保护的逻辑
} catch (BlockException e1) {
  // 处理被流控的逻辑
} finally {
  if (entry != null) {
    entry.exit();
  }
}
  1. 注解,通过@SentinelResource注解声明该方法为资源
@SentinelResource("自定义资源名")
public void helloWorld() {
    // 被保护的逻辑
}

学习了俩种总的调用方法以后,让我们细化到代码上,来看看其他几种不通的代码实现方式:

  1. 不需要收到exit的try-with-resource
try (Entry entry = SphU.entry("resourceName")) {
  // 被保护的逻辑
} catch (BlockException ex) {
  // 处理被流控的逻辑
}
  1. 其实就是上面的API风格,不过这里拓展一个点,就是entry的额外参数,可以传入热点参数,不过注意,如果entry有额外参数,

需要在exit的时候也加上那些参数,否则可能会出现统计错误(热点参数问题以后再谈)

try {
  // 资源名可使用任意有业务语义的字符串
  entry = SphU.entry("自定义资源名");
  // 被保护的逻辑
} catch (BlockException e1) {
  // 处理被流控的逻辑
} finally {
  if (entry != null) {
    entry.exit();
  }
}

Sentinel文档学习系列——1.Sentinel初体验_第1张图片
3.可以使用SphO的布尔值来考虑限流逻辑,通过if-else

if (SphO.entry("自定义资源名")) {
    // 务必保证finally会被执行
    try {
      //被保护的逻辑
    } finally {
      SphO.exit();
    }
} else {
    // 处理被流控的逻辑
}

4.通过注解的方式,上面也已经提过了,不过这里添加blockHandlerfallback的说明,需要区别:

  • blockHandler会在原方法被限流/降级/系统保护的时候调用(异常: BlockException)
  • fallback会在所有异常的适合调用
@SentinelResource(value = "自定义资源名", blockHandler = "protect", fallback = "")
public void helloWorld(String id) {
    // 被保护的逻辑
}

public void protect(String id, BlockException ex) {
    //原方法被限流/降级/系统保护的适合调用
}

5.Sentinel还支持异步调用

try {
    AsyncEntry entry = SphU.asyncEntry(resourceName);
    // 异步调用
    doAsync(() -> {
        try {
            // 在此处处理异步调用的结果.
        } finally {
            entry.exit();
        }
    });
} catch (BlockException ex) {
    // 处理被流控的逻辑
}

在Sentinel的世界中,同步和异步的资源都是同级的,而不是嵌套关系,如果你想要在异步调用中嵌套调用同步资源,官方也给出了案例

  • 首先是一个同步资源的声明
public void handleResult(String result) {
    Entry entry = null;
    try {
        entry = SphU.entry("handleResultForAsync");
    } catch (BlockException ex) {
        // 处理被流控的逻辑
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }
}

public void someAsync() {
    try {
        AsyncEntry entry = SphU.asyncEntry(resourceName);

        // 异步执行
        doAsync(userId, result -> {
            // 在异步回调中进行上下文变换,通过 AsyncEntry 的 getAsyncContext 方法获取异步 Context,进行上下文切换
            ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
                try {
                    // 切换后即可嵌套正常的资源调用.
                    handleResult(result);
                } finally {
                    entry.exit();
                }
            });
        });
    } catch (BlockException ex) {
        // 处理被流控的逻辑
    }
}

接下来来到规则的部分

在Sentinel中的所有规则,都是存在于内存中,可随时查找以及修改的,并且修改后可以立即生效。

规则可以主要分为以下五大类:
  • 流量控制规则
  • 熔断降级规则
  • 系统保护规则
  • 来源访问控制规则
  • 热点参数规则

详细介绍放在后面的章节来介绍,来看一个简单的流量控制的代码

private void initFlowQpsRule() {
    List rules = new ArrayList<>();
    FlowRule rule = new FlowRule(resourceName);
    rule.setCount(20);  //设置QPS数值
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);  //设置限流类型,QPS或并发线程数模式
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

来跑一个例子把:

  1. 将依赖添加到pon.xml中

      com.alibaba.csp
      sentinel-core
      1.7.0
  1. 运行以下代码
public class RookieStartSingle {

    public static void main(String[] args) {
        initFlowRule();
        RookieStart start = new RookieStart();
        while (true) {
            try (Entry entry = SphU.entry("helloSentinel")) {
                //被保护的资源
                System.out.println("helloSentinel");
            } catch (BlockException e) {
                //限流后做的处理
                System.out.println("block!");
            }
        }

    }

    private static void initFlowRule() {
        List rules = new ArrayList<>();
        //制定规则
        FlowRule rule1 = new FlowRule();
        rule1.setResource("helloSentinel");
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setCount(100);
        rules.add(rule1);
        //规则加载
        FlowRuleManager.loadRules(rules);
    }
}

如若有错,烦请指出

你可能感兴趣的:(sentinel)