如何基于 Nacos 和 Sentinel ,实现灰度路由和流量防御一体化

Nepxion Discovery框架在实现灰度发布和路由功能前提下,结合Nacos和Sentinel,对流量再实施一层防御措施,更能达到企业级的流量安全控制的目的。它的功能包括:spring

  • 封装远程配置中心和本地规则文件的读取逻辑,即优先读取远程配置,若是不存在或者规则错误,则读取本地规则文件。动态实现远程配置中心对于规则的热刷新
  • 封装NacosDataSource和ApolloDataSource,支持Nacos和Apollo两个远程配置中心,零代码实现Sentinel功能。更多的远程配置中心,请参照Sentinel官方的DataSource并自行集成
  • 支持原生的流控规则、降级规则、受权规则、系统规则、热点参数流控规则
  • 支持扩展LimitApp的机制,经过动态的Http Header方式实现组合式防御机制,包括基于服务名、基于灰度组、基于灰度版本、基于灰度区域、基于机器地址和端口等防御机制,支持自定义任意的业务参数组合实现该功能,例如,根据传入的微服务灰度版本号+用户名,组合在一块儿进行熔断
  • 支持微服务侧Actuator、Swagger和Rest三种方式的规则写入
  • 支持控制台侧基于微服务名的Actuator、Swagger和Rest三种方式的批量规则写入
  • 支持开关关闭上述功能spring.application.strategy.sentinel.enabled=true,默认是关闭的

[Nacos] 阿里巴巴中间件部门开发的新一代集服务注册发现中心和配置中心为一体的中间件。它是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施,支持几乎全部主流类型的“服务”的发现、配置和管理,更敏捷和容易地构建、交付和管理微服务平台数组

[Sentinel] 阿里巴巴中间件部门开发的新一代以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性的分布式系统的流量防卫兵。它承接了阿里巴巴近10年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量能够承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等安全

环境搭建及依赖引入

服务端在Discovery框架原有依赖的基础上,再引入以下依赖bash

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-service-sentinel</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-sentinel-starter-nacos</artifactId>
    <!-- <artifactId>discovery-plugin-strategy-sentinel-starter-apollo</artifactId> -->
    <version>${discovery.version}</version>
</dependency>复制代码

原生Sentinel注解

参照下面代码,为接口方法增长@SentinelResource注解,value为sentinel-resource,blockHandler和fallback是防御其做用后须要执行的方法架构

@RestController
@ConditionalOnProperty(name = DiscoveryConstant.SPRING_APPLICATION_NAME, havingValue = "discovery-guide-service-b")
public class BFeignImpl extends AbstractFeignImpl implements BFeign {
    private static final Logger LOG = LoggerFactory.getLogger(BFeignImpl.class);

    @Override
    @SentinelResource(value = "sentinel-resource", blockHandler = "handleBlock", fallback = "handleFallback")
    public String invoke(@PathVariable(value = "value") String value) {
        value = doInvoke(value);

        LOG.info("调用路径:{}", value);

        return value;
    }

    public String handleBlock(String value, BlockException e) {
        return value + "-> B server sentinel block, cause=" + e.getClass().getName() + ", rule=" + e.getRule() + ", limitApp=" + e.getRuleLimitApp();
    }

    public String handleFallback(String value) {
        return value + "-> B server sentinel fallback";
    }
}复制代码

原生Sentinel规则

Sentinel在配置中心订阅的Key格式,以下:app

1. Nacos的Key格式:Group为元数据中配置的[组名],Data Id为[服务名]-[规则类型]
2. Apollo的Key格式:[组名]-[服务名]-[规则类型]复制代码

Sentinel规则的用法,请参照Sentinel官方文档负载均衡

流控规则

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-flow,规则内容以下:框架

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "refResource": null,
        "controlBehavior": 0,
        "warmUpPeriodSec": 10,
        "maxQueueingTimeMs": 500,
        "clusterMode": false,
        "clusterConfig": null
    }
]复制代码

如图所示
分布式


降级规则

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-degrade,规则内容以下:ide

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "count": 2,
        "timeWindow": 10,
        "grade": 0,
        "passCount": 0
    }
]复制代码

如图所示


受权规则

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "discovery-guide-service-a",
        "strategy": 0
    }
]复制代码

如图所示


系统规则

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-system,规则内容以下:

[
    {
        "resource": null,
        "limitApp": null,
        "highestSystemLoad": -1.0,
        "highestCpuUsage": -1.0,
        "qps": 200.0,
        "avgRt": -1,
        "maxThread": -1
    }
]复制代码

如图所示


热点参数流控规则

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-param-flow,规则内容以下:

[
    {
        "resource": "sentinel-resource",
        "limitApp": "default",
        "grade": 1,
        "paramIdx": 0,
        "count": 1,
        "controlBehavior": 0,
        "maxQueueingTimeMs": 0,
        "burstCount": 0,
        "durationInSec": 1,
        "paramFlowItemList": [],
        "clusterMode": false
    }
]复制代码

如图所示


基于灰度路由和Sentinel-LimitApp扩展的防御机制

该方式对于上面5种规则都有效,这里以受权规则展开阐述

受权规则中,limitApp,若是有多个,能够经过“,”分隔。"strategy": 0 表示白名单,"strategy": 1 表示黑名单

基于服务名的防御机制

修改配置项Sentinel Request Origin Key为服务名的Header名称,修改受权规则中limitApp为对应的服务名,可实现基于服务名的防御机制

配置项,该配置项默认为n-d-service-id,能够不配置

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-id复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示全部discovery-guide-service-a服务容许访问discovery-guide-service-b服务

[
    {
        "resource": "sentinel-resource",
        "limitApp": "discovery-guide-service-a",
        "strategy": 0
    }
]复制代码

基于灰度组的防御机制

修改配置项Sentinel Request Origin Key为灰度组的Header名称,修改受权规则中limitApp为对应的组名,可实现基于组名的防御机制

配置项

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-group复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示隶属my-group组的全部服务都容许访问服务discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "my-group",
        "strategy": 0
    }
]复制代码

基于灰度版本的防御机制

修改配置项Sentinel Request Origin Key为灰度版本的Header名称,修改受权规则中limitApp为对应的版本,可实现基于版本的防御机制

配置项

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-version复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示版本为1.0的全部服务都容许访问服务discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0",
        "strategy": 0
    }
]复制代码

基于灰度区域的防御机制

修改配置项Sentinel Request Origin Key为灰度区域的Header名称,修改受权规则中limitApp为对应的区域,可实现基于区域的防御机制

配置项

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-region复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示区域为dev的全部服务都容许访问服务discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "dev",
        "strategy": 0
    }
]复制代码

基于机器地址和端口的防御机制

修改配置项Sentinel Request Origin Key为灰度区域的Header名称,修改受权规则中limitApp为对应的区域值,可实现基于机器地址和端口的防御机制

配置项

spring.application.strategy.service.sentinel.request.origin.key=n-d-service-address复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示地址和端口为192.168.0.88:8081和192.168.0.88:8082的服务都容许访问服务discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "192.168.0.88:8081,192.168.0.88:8082",
        "strategy": 0
    }
]复制代码

自定义业务参数的组合式防御机制

经过适配类实现自定义业务参数的组合式防御机制

// 版本号+用户名,实现组合式熔断
public class MyServiceSentinelRequestOriginAdapter extends DefaultServiceSentinelRequestOriginAdapter {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String version = request.getHeader(DiscoveryConstant.N_D_SERVICE_VERSION);
        String user = request.getHeader("user");

        return version + "&" + user;
    }
}复制代码

在配置类里@Bean方式进行适配类建立

@Bean
public ServiceSentinelRequestOriginAdapter ServiceSentinelRequestOriginAdapter() {
    return new MyServiceSentinelRequestOriginAdapter();
}复制代码

增长服务discovery-guide-service-b的规则,Group为discovery-guide-group,Data Id为discovery-guide-service-b-sentinel-authority,规则内容以下,表示版本为1.0且传入的Http Header的user=zhangsan,同时知足这两个条件下的全部服务都容许访问服务discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0&zhangsan",
        "strategy": 0
    }
]复制代码

运行效果

  • 当传递的Http Header中user=zhangsan,当全链路调用中,API网关负载均衡discovery-guide-service-a服务到1.0版本后再去调用discovery-guide-service-b服务,最终调用成功

如图所示


  • 当传递的Http Header中user=lisi,不知足条件,最终调用在discovery-guide-service-b服务端被拒绝掉

如图所示


  • 当传递的Http Header中user=zhangsan,知足条件之一,当全链路调用中,API网关负载均衡discovery-guide-service-a服务到1.1版本后再去调用discovery-guide-service-b服务,不知足version=1.0的条件,最终调用在discovery-guide-service-b服务端被拒绝掉

如图所示


基于Swagger的Sentinel规则推送

分为基于单个服务实例和基于服务名对应的多个服务实例的Sentinel规则推送

基于单个服务实例的Sentinel规则推送

直接访问该服务实例的Swagger主页便可

如图所示


基于服务名对应的多个服务实例的Sentinel规则推送

须要开启discovery-console服务,并访问其Swagger主页便可

如图所示


原文连接

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索