Skip to content

6.11.0(JUL 11, 2021)

Compare
Choose a tag to compare
@HaojunRen HaojunRen released this 11 Jul 03:29
· 577 commits to 6.x.x since this release

贡献列表

  • 感谢@pegasus的贡献
  • 感谢@zifenhan的贡献
  • 感谢@ayang的贡献
  • 感谢@星河的贡献
  • 感谢@jimodebeiju123的贡献
  • 感谢@rottenmu的测试
  • 感谢@春雷的测试
  • 感谢@blank的测试
  • 感谢@弄潮儿的测试
  • 感谢@明天better的测试
  • 感谢@陌路的测试

发布日志

6.11.0版,一个经过全面严格优化和严格测试的版本,架构科学性、代码规范性和高可用以及性能方面上更上一层楼,除此之外,暴露了更加丰富的端点(Endpoint)接口,供第三方云原生系统(例如,DevOps平台)做对接。不过,对于非核心的模块优化和重构,带来一些使用上的不兼容性,向广大用户致以歉意,我们相信您可以在几分钟内解决不兼容性问题。Please enjoy!

发布策略

提醒:版本号右边, 表示>=该版本号, 表示<=该版本号

版本 状态 SC SB SCA
7.0.0 (商业版) 202x.x.x 2.5.x
2.4.1 ↑
202x.x
6.11.0 H.SR5 ↑
H
G
F
2.3.x
2.2.x
2.1.x
2.0.x
2.2.x
2.2.x
2.1.x
2.0.x
5.6.0 G 2.1.x 2.1.x
4.15.0 F 2.0.x 2.0.x
3.27.0 E 1.5.x 1.5.x
2.0.x D 1.x.x 1.5.x
1.0.x C 1.x.x 1.5.x

表示维护中 | 表示不维护,但可用,强烈建议升级 | 表示不维护,不可用,已废弃

  • 7.x.x版本(适用于202x.x.x)将继续维护
  • 6.x.x版本(同时适用于Finchley、Greenwich和Hoxton)将继续维护
  • 5.x.x版本(适用于Greenwich)已废弃
  • 4.x.x版本(适用于Finchley)已废弃
  • 3.x.x版本(适用于Edgware)不维护,但可用,强烈建议升级
  • 2.x.x版本(适用于Dalston)已废弃
  • 1.x.x版本(适用于Camden)已废弃

版本变更

  • 默认集成Spring Boot版本为2.3.12.RELEASE(可降级
  • 默认集成Spring Cloud版本为Hoxton.SR12(可降级),Hoxton.SR12为Spring Cloud官方发布的最后一个版本
  • 默认集成Spring Cloud Alibaba版本为2.2.6.RELEASE(可降级
  • 默认集成Nacos 1.4.x以上版本。如果使用1.4.x以下版本,那么
    • 跟业务服务相关的Plugin模块不受影响
    • 跟业务服务不相关的Console模块受影响,新增的Rest接口/config/remote/update/{group}/{serviceId}/{formatType}无法使用,必须使用不带{formatType}参数的老接口
    • Nacos 1.4.x以上版本推送参数新增配置文件类型(包括 xml | json | yaml | properties | html | text),可以让配置在Nacos界面上有效区别出不同的配置类型并高亮,从而提高易用性
  • 默认集成Caffeine版本为2.9.2
  • 默认集成SkyWalking APM Toolkit版本为8.6.0
  • 默认集成OpenTelemetry版本为1.3.0
  • 升级JEtcd版本为0.5.7,解决在Hoxton高版本抛Netty Grpc版本不兼容的错误

功能迭代

增强蓝绿灰度发布

① 蓝绿发布支持内置兜底路由

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-release>
        <conditions type="blue-green">
            <!-- 蓝路由,条件expression驱动 -->	
            <condition id="blue-condition" expression="#H['a'] == '1'" version-id="blue-route"/>
            <!-- 绿路由,条件expression驱动 -->
            <condition id="green-condition" expression="#H['a'] == '1' and #H['b'] == '2'" version-id="green-route"/>
            <!-- 兜底路由,无expression驱动 -->
            <condition id="basic-condition" version-id="basic-route"/>
        </conditions>

        <routes>
            <route id="blue-route" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>	
            <route id="green-route" type="version">{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</route>
            <route id="basic-route" type="version">{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</route>
        </routes>
    </strategy-release>
</rule>

② 灰度发布支持内置兜底路由

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-release>
        <conditions type="gray">
            <!-- 灰度路由1,条件expression驱动 -->
            <condition id="gray-condition1" expression="#H['a'] == '1'" version-id="gray-route=10;stable-route=90"/>
            <!-- 灰度路由2,条件expression驱动 -->
            <condition id="gray-condition2" expression="#H['a'] == '1' and #H['b'] == '2'" version-id="gray-route=85;stable-route=15"/>
            <!-- 兜底路由,无expression驱动 -->
            <condition id="basic-condition" version-id="gray-route=0;stable-route=100"/>
        </conditions>

        <routes>
            <route id="gray-route" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>
            <route id="stable-route" type="version">{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</route>
        </routes>
    </strategy-release>
</rule>

③ 蓝绿灰度混合发布

基于上述增强,支持更简单更强大的蓝绿灰度混合发布功能

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-release>
        <conditions type="blue-green">
            <condition id="condition-0" expression="#H['a'] == '0'" version-id="route-0"/>
            <condition id="condition-1" expression="#H['a'] == '1'" version-id="route-1"/>
            <condition id="basic-condition" version-id="basic-route"/> <!-- 可以删除掉蓝绿发布的兜底策略 -->
        </conditions>

        <conditions type="gray">
            <condition id="condition-0" expression="#H['a'] == '2'" version-id="route-0=10;route-1=90"/>
            <condition id="condition-1" expression="#H['a'] == '3'" version-id="route-0=85;route-1=15"/>
            <condition id="basic-condition" version-id="route-0=0;route-1=100"/>
        </conditions>

        <routes>
            <route id="route-0" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>
            <route id="route-1" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>
            <route id="basic-route" type="version">{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</route>
        </routes>
    </strategy-release>
</rule>

规则解读

原则:蓝绿规则优先于灰度规则

if (a == 0) {
    执行蓝绿发布blue-green的route-0下的路由
} else if (a == 1) {
    执行蓝绿发布blue-green的route-1下的路由
} else {
    执行蓝绿发布blue-green的basic-route下的兜底路由
}

提醒:当蓝绿发布存在兜底策略(basic-condition),灰度发布永远不会被执行

如果删除掉蓝绿发布的兜底策略,那么执行逻辑则变为

if (a == 0) {
    执行蓝绿发布route-0下的路由
} else if (a == 1) {
    执行蓝绿发布route-1下的路由
} else if (a == 2) {
    执行灰度发布route-0=10;route-1=90下的流量百分比分配路由
} else if (a == 3) {
    执行灰度发布route-0=85;route-1=15下的流量百分比分配路由	
} else {
    执行灰度发布route-0=0;route-1=100下的兜底路由
    由于赋予了route-0=0那么流量会全部打到route-1相当于变种的蓝绿发布
}

蓝绿灰度混合发布一些应用场景和示例,可参考

https://github.com/Nepxion/Discovery/wiki -> 如何执行高级蓝绿灰度混合发布

网关动态路由

网关动态路由功能,主要包括

  • 路由动态添加
  • 路由动态修改
  • 路由动态删除
  • 路由动态批量更新
  • 路由查询
  • 路由动态变更后,通过事件总线方式发出事件通知

上述操作,可以通过

  • 网关暴露Rest Endpoint接口实施
  • 控制台暴露Rest Endpoint接口,对同一个网关下若干个实例批量实施
  • 网关订阅配置中心(包括Nacos、Apollo、Consul、Etcd、Redis、Zookeeper)批量实施
Spring-Cloud-Gateway网关动态路由

提醒:Spring Cloud Gateway网关在自动路由模式下,动态路由不能工作

支持Spring Cloud Gateway网关官方断言器和过滤器,也支持用户自定义断言器和过滤器

① Spring Cloud Gateway网关动态路由配置

  • 精简配置
[
    {
        "id": "route0", 
        "uri": "lb://discovery-guide-service-a", 
        "predicates": [
            "Path=/discovery-guide-service-a/**,/x/**,/y/**"
        ], 
        "filters": [
            "StripPrefix=1"
        ]
    }
]
  • 完整配置
[
    {
        "id": "route0", 
        "uri": "lb://discovery-guide-service-a", 
        "predicates": [
            "Path=/discovery-guide-service-a/**,/x/**,/y/**"
        ], 
        "filters": [
            "StripPrefix=1"
        ], 
        "order": 0,
        "metadata": {}
    }
]

② Spring Cloud Gateway网关自定义动态路由配置

自定义方式描述网关内置断言器和过滤器

提醒:自定义方式描述网关内置断言器和过滤器的Key必须遵循如下规则

  • 对于没有显式args定义的配置,类似Path、StripPrefix这种配置,args名称必须是_genkey_序号格式。例如,"_genkey_0": "/discovery-guide-service-a/**"
  • 对于显式args定义的配置,类似Header、Cookie、Query这种配置,args名称遵照Spring Cloud Gateway内置格式,请查看相关文档或者源码。例如,Header的KV格式为header -> regexp,Cookie的KV格式为name->regexp,Query的KV格式为param->regexp
[
    {
        "id": "route0", 
        "uri": "lb://discovery-guide-service-a",
        "userPredicates": [
            {
                "name": "Path",
                "args": {
                    "_genkey_0": "/discovery-guide-service-a/**",
                    "_genkey_1": "/x/**",
                    "_genkey_2": "/y/**"
                }
            },
          {
                "name": "Header",
                "args": {
                    "header": "a",
                    "regexp": "1"
                }
            },
            {
                "name": "Header",
                "args": {
                    "header": "b",
                    "regexp": "2"
                }
            },
            {
                "name": "Cookie",
                "args": {
                    "name": "c",
                    "regexp": "3"
                }
            },
            {
                "name": "Cookie",
                "args": {
                    "name": "d",
                    "regexp": "4"
                }
            },
            {
                "name": "Query",
                "args": {
                    "param": "e",
                    "regexp": "5"
                }
            },
            {
                "name": "Query",
                "args": {
                    "param": "f",
                    "regexp": "6"
                }
            }
        ],
        "userFilters": [
            {
                "name": "StripPrefix",
                "args": {
                    "_genkey_0": "1"
                }
            }
        ]
    }
]

在DiscoveryPlatform界面上,格式为

Path={"_genkey_0":"/discovery-guide-service-a/**", "_genkey_1":"/x/**", "_genkey_2":"/y/**"}
StripPrefix={"_genkey_0":"1"}

Header={"header":"a","regexp":"1"}
Header={"header":"b","regexp":"2"}
Cookie={"name":"c","regexp":"3"}
Cookie={"name":"d","regexp":"4"}
Query={"param":"e","regexp":"5"}
Query={"param":"f","regexp":"6"}

自定义方式描述用户扩展的断言器和过滤器

提醒:自定义方式描述用户扩展的断言器和过滤器的Key必须遵循如下规则

  • List结构,args名称必须是list的变量名.序号格式。例如,"whiteList.0": "* swagger-ui.html"
  • Map<String, String>结构,args名称必须是map的变量名.map的key格式。例如,"userMap.name": "jason"
[
    {
        "id": "route0", 
        "uri": "lb://discovery-guide-service-a", 
        "predicates": [
            "Path=/discovery-guide-service-a/**,/x/**,/y/**"
        ], 
        "filters": [
            "StripPrefix=1"
        ], 
        "userPredicates": [],
        "userFilters": [
            {
                "name": "Authentication",
                "args": {
                    "secretKey": "abc",
                    "whiteList.0": "* swagger-ui.html",
                    "whiteList.1": "* /swagger-resources/**",
                    "whiteList.2": "* /doc.html",
                    "userMap.name": "jason",
                    "userMap.age": "20",
                    "authInfoCarryStrategy": "AuthWriteToHeader"
                }
            }
        ]
    }
]

在DiscoveryPlatform界面上,格式为

Authentication={"secretKey":"abc", "whiteList.0":"* swagger-ui.html", "whiteList.1":"* /swagger-resources/**", "whiteList.2":"* /doc.html", "userMap.name":"jason", "userMap.age":"20", "authInfoCarryStrategy":"AuthWriteToHeader"}

③ Spring Cloud Gateway网关的Rest Endpoint接口

操作 路径 参数 方式
增加网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/add 单个动态路由配置 POST
修改网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/modify 单个动态路由配置 POST
删除网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/delete/{routeId} DELETE
更新全部网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/update-all 多个动态路由配置 POST
根据路由Id查看网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/view/{routeId} GET
查看全部网关路由 http://[网关IP:PORT]/spring-cloud-gateway-route/view-all GET

④ 控制台的Rest Endpoint接口

操作 路径 参数 方式
增加网关路由 http://[控制台IP:PORT]/route/add/spring-cloud-gateway/{serviceId} 单个动态路由配置 POST
修改网关路由 http://[控制台IP:PORT]/route/modify/spring-cloud-gateway/{serviceId} 单个动态路由配置 POST
删除网关路由 http://[控制台IP:PORT]/route/delete/spring-cloud-gateway/{serviceId}/{routeId} DELETE
更新全部网关路由 http://[控制台IP:PORT]/route/update-all/spring-cloud-gateway/{serviceId} 多个动态路由配置 GET
查看全部网关路由 http://[控制台IP:PORT]/route/view-all/spring-cloud-gateway/{serviceId} GET

⑤ Spring Cloud Gateway网关订阅配置中心

网关订阅配置中心的使用方式,如下

  • Key为
    • Nacos、Redis、Zookeeper配置中心,Group为{group},DataId为{网关serviceId}-dynamic-route
    • Apollo、Consul、Etcd配置中心,Key的格式为{group}-{网关serviceId}-dynamic-route
    • {group}为注册中心元数据group值
  • Value参考“① Spring Cloud Gateway网关动态路由配置”

支持如下开关开启该动能,默认是关闭的

# 开启和关闭网关订阅配置中心的动态路由策略。缺失则默认为false
spring.application.strategy.gateway.dynamic.route.enabled=true

配置中心配置的网关动态路由推送到网关后,网关会自动根据已经存在的路由表进行判断后实施增删改操作,而不是全部清空后再全部插入,这样有助于提高性能和安全性。网关控制台上会打印出如下日志

--- Gateway Dynamic Routes Update Information ----
Total count=3
Added count=1
Modified count=1
Deleted count=1
--------------------------------------------------

⑥ Spring Cloud Gateway网关事件总线通知的订阅

@EventBus
public class MySubscriber {
    @Subscribe
    public void onGatewayStrategyRouteAdded(GatewayStrategyRouteAddedEvent gatewayStrategyRouteAddedEvent) {
        System.out.println("增加网关路由=" + gatewayStrategyRouteAddedEvent.getGatewayStrategyRouteEntity());
    }

    @Subscribe
    public void onGatewayStrategyRouteModified(GatewayStrategyRouteModifiedEvent gatewayStrategyRouteModifiedEvent) {
        System.out.println("修改网关路由=" + gatewayStrategyRouteModifiedEvent.getGatewayStrategyRouteEntity());
    }

    @Subscribe
    public void onGatewayStrategyRouteDeleted(GatewayStrategyRouteDeletedEvent gatewayStrategyRouteDeletedEvent) {
        System.out.println("删除网关路由=" + gatewayStrategyRouteDeletedEvent.getRouteId());
    }

    @Subscribe
    public void onGatewayStrategyRouteUpdatedAll(GatewayStrategyRouteUpdatedAllEvent gatewayStrategyRouteUpdatedAllEvent) {
        System.out.println("更新全部网关路由=" + gatewayStrategyRouteUpdatedAllEvent.getGatewayStrategyRouteEntityList());
    }
}
Zuul网关动态路由

提醒:Zuul网关在自动路由模式下,动态路由可以工作

① Zuul网关动态路由配置

  • 精简配置
[
    {
        "id": "route0",
        "serviceId": "discovery-guide-service-a",
        "path": "/discovery-guide-service-a/**"
    },
    {
        "id": "route1",
        "serviceId": "discovery-guide-service-a",
        "path": "/x/**"
    },
    {
        "id": "route2",
        "serviceId": "discovery-guide-service-a",
        "path": "/y/**"
    }
]

如果希望一个服务只映射一个动态路由路径,则不需要id,可以简化为

[
    {
        "serviceId": "discovery-guide-service-a",
        "path": "/x/**"
    }
]
  • 完整配置
[
    {
        "id": "route0",
        "serviceId": "discovery-guide-service-a",
        "path": "/discovery-guide-service-a/**",
        "url": null,
        "stripPrefix": true,
        "retryable": null,
        "sensitiveHeaders": [],
        "customSensitiveHeaders": false
    },
    {
        "id": "route1",
        "serviceId": "discovery-guide-service-a",
        "path": "/x/**",
        "url": null,
        "stripPrefix": true,
        "retryable": null,
        "sensitiveHeaders": [],
        "customSensitiveHeaders": false
    },
    {
        "id": "route2",
        "serviceId": "discovery-guide-service-a",
        "path": "/y/**",
        "url": null,
        "stripPrefix": true,
        "retryable": null,
        "sensitiveHeaders": [],
        "customSensitiveHeaders": false
    }
]

② Zuul网关的Rest Endpoint接口

操作 路径 参数 方式
增加网关路由 http://[网关IP:PORT]/zuul-route/add 单个动态路由配置 POST
修改网关路由 http://[网关IP:PORT]/zuul-route/modify 单个动态路由配置 POST
删除网关路由 http://[网关IP:PORT]/zuul-route/delete/{routeId} DELETE
更新全部网关路由 http://[网关IP:PORT]/zuul-route/update-all 多个动态路由配置 POST
根据路由Id查看网关路由 http://[网关IP:PORT]/zuul-route/view/{routeId} GET
查看全部网关路由 http://[网关IP:PORT]/zuul-route/view-all GET

③ 控制台的Rest Endpoint接口

操作 路径 参数 方式
增加网关路由 http://[控制台IP:PORT]/route/add/zuul/{serviceId} 单个动态路由配置 POST
修改网关路由 http://[控制台IP:PORT]/route/modify/zuul/{serviceId} 单个动态路由配置 POST
删除网关路由 http://[控制台IP:PORT]/route/delete/zuul/{serviceId}/{routeId} DELETE
更新全部网关路由 http://[控制台IP:PORT]/route/zuul/update-all/{serviceId} 多个动态路由配置 GET
查看全部网关路由 http://[控制台IP:PORT]/route/zuul/view-all/{serviceId} GET

④ Zuul网关订阅配置中心

网关订阅配置中心的使用方式,如下

  • Key为
    • Nacos、Redis、Zookeeper配置中心,Group为{group},DataId为{网关serviceId}-dynamic-route
    • Apollo、Consul、Etcd配置中心,Key的格式为{group}-{网关serviceId}-dynamic-route
    • {group}为注册中心元数据group值
  • Value参考“① Zuul网关动态路由配置”

支持如下开关开启该动能,默认是关闭的

# 开启和关闭网关订阅配置中心的动态路由策略。缺失则默认为false
spring.application.strategy.zuul.dynamic.route.enabled=true

配置中心配置的网关动态路由推送到网关后,网关会自动根据已经存在的路由表进行判断后实施增删改操作,而不是全部清空后再全部插入,这样有助于提高性能和安全性。网关控制台上会打印出如下日志

----- Zuul Dynamic Routes Update Information -----
Total count=3
Added count=1
Modified count=1
Deleted count=1
--------------------------------------------------

⑤ Zuul网关事件总线通知的订阅

@EventBus
public class MySubscriber {
    @Subscribe
    public void onZuulStrategyRouteAdded(ZuulStrategyRouteAddedEvent zuulStrategyRouteAddedEvent) {
        System.out.println("增加网关路由=" + zuulStrategyRouteAddedEvent.getZuulStrategyRouteEntity());
    }

    @Subscribe
    public void onZuulStrategyRouteModified(ZuulStrategyRouteModifiedEvent zuulStrategyRouteModifiedEvent) {
        System.out.println("修改网关路由=" + zuulStrategyRouteModifiedEvent.getZuulStrategyRouteEntity());
    }

    @Subscribe
    public void onZuulStrategyRouteDeleted(ZuulStrategyRouteDeletedEvent zuulStrategyRouteDeletedEvent) {
        System.out.println("删除网关路由=" + zuulStrategyRouteDeletedEvent.getRouteId());
    }

    @Subscribe
    public void onZuulStrategyRouteUpdatedAll(ZuulStrategyRouteUpdatedAllEvent zuulStrategyRouteUpdatedAllEvent) {
        System.out.println("更新全部网关路由=" + zuulStrategyRouteUpdatedAllEvent.getZuulStrategyRouteEntityList());
    }
}

统一配置订阅执行器

统一配置订阅执行器,基于Nacos、Apollo、Consul、Etcd、Redis、Zookeeper六种配置中心,通过封装适配成同样的写法,通过切换继承类,可切换配置中心,无须修改其它代码

Spring Cloud配置动态刷新机制固化在一个比较单一的场景(例如,通过@value方式)里,无法满足更灵活更高级的订阅场景,例如,Spring Cloud Gateway和Zuul网关通过改变配置中心的路由信息无法动态刷新路由路径

本框架提供更简单灵活的实现方式,以Nacos为例子,使用者先确定订阅的Group和DataId,在Nacos界面填入这两个参数对应的配置内容,然后通过回调方法处理业务逻辑。具体使用方式,如下

// 把继承类(extends)换成如下任何一个,即可切换配置中心,代码无需任何变动
// 1. NacosProcessor
// 2. ApolloProcessor
// 3. ConsulProcessor
// 4. EtcdProcessor
// 5. ZookeeperProcessor
// 6. RedisProcessor
// Group和DataId自行决定,需要注意
// 1. 对于Nacos、Redis、Zookeeper配置中心,Group和DataId需要和界面相对应
// 2. 对于Apollo、Consul、Etcd配置中心,Key的格式为Group-DataId
// 可以同时支持多个配置中心的订阅,需要同时创建多个不同的Processor,同时@Bean方式进入到Spring容器
public class MyConfigProcessor extends NacosProcessor {
    @Override
    public void beforeInitialization() {
        System.out.println("订阅器初始化之前,可以做一些工作");
    }

    @Override
    public void afterInitialization() {
        System.out.println("订阅器初始化之后,可以做一些工作");
    }

    @Override
    public String getGroup() {
        return "b";
    }

    @Override
    public String getDataId() {
        return "a";
    }

    @Override
    public String getDescription() {
        // description为日志打印显示而设置,作用是帮助使用者在日志上定位订阅器是否在执行
        return "My subscription";
    }

    @Override
    public void callbackConfig(String config) {
        // config为配置中心对应键值的内容变更,使用者可以根据此变更对业务模块做回调处理
        System.out.println("监听配置改变:config=" + config);
    }
}

统一配置订阅执行器可以单独运行在Spring Boot应用上,它是一个通用的解决方案

  • 如果使用者希望脱离Nepxion Discovery以及Spring Cloud框架,使用者只需要引入如下依赖之一即可
  • 如果使用者正在使用Nepxion Discovery框架,则跟随它的内置引入即可,不需要额外引入如下依赖之一
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-nacos</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-apollo</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-redis</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-zookeeper</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-consul</artifactId>
    <version>${discovery.version}</version>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-common-etcd</artifactId>
    <version>${discovery.version}</version>
</dependency>

具体用法和配置,请参考6.x.x指南示例配置版,分支为6.x.x-config

StrategyAlarmEvent新增告警类型

AlarmEvent更名为StrategyAlarmEvent,移动到strategy模块下

StrategyAlarmEvent新增告警类型,并把contextMap改为alarmMap,如下

public class StrategyAlarmEvent implements Serializable {
    private static final long serialVersionUID = 5966845230262521754L;

    private String alarmType;
    private Map<String, String> alarmMap;

    public StrategyAlarmEvent(String alarmType, Map<String, String> alarmMap) {
        this.alarmType = alarmType;
        this.alarmMap = alarmMap;
    }

    public String getAlarmType() {
        return alarmType;
    }

    public Map<String, String> getAlarmMap() {
        return alarmMap;
    }
}

使用端的用法变更,如下

@EventBus
public class MySubscriber {
    @Subscribe
    public void onAlarm(StrategyAlarmEvent strategyAlarmEvent) {
        // 在本告警中告警类型为StrategyConstant.STRATEGY_CONTEXT_ALARM的静态变量值,表示蓝绿灰度上下文告警
        String alarmType = strategyAlarmEvent.getAlarmType();

        // 通过事件总线把告警数据alarmMap存储到ElasticSearch、MessageQueue、数据库等
        Map<String, String> alarmMap = strategyAlarmEvent.getAlarmMap();
    }
}

Nacos配置自动鉴别配置类型

支持Nacos Client推送规则配置的时候,把配置类型(包括 xml | json | yaml | properties | html | text)推送到Nacos配置中心

元数据新增Http协议类型

Http协议类型包括http和https,通过注册元数据到注册中心,支持http和https两种方式的全链路侦测,路由,通过控制台对服务批量轮询操作

默认为http协议,当服务开启https暴露框架内部接口的时候,通过如下配置开启

spring.application.protocol=https

服务侧增加路由策略过滤器执行顺序的配置

服务侧支持路由策略过滤器执行顺序

# 路由策略过滤器的执行顺序(Order)。缺失则默认为0
spring.application.strategy.service.route.filter.order=0

重构优化

重构优化蓝绿灰度配置格式

配置节点

<strategy-customization>

变更为

<strategy-release>

但依旧兼容识别<strategy-customization>配置节点

重构优化服务下线场景下全链路蓝绿灰度发布

① 全局唯一ID格式从UUID变更为

年月日(8位)-小时分钟秒(6位)-毫秒(3位)-随机数(4位)-随机数(3位)-随机数(3位)

前半部分精确到毫秒的设计,基本能保证ID的全局唯一,后半部分三重随机数,完全能保证ID的全局唯一。全局唯一失效的前提是,两个服务实例必须是毫秒级的同时启动,同时三次随机碰撞下来,得到完全三个相同的随机数后

② 配置方式和蓝绿灰度方式一致

全局唯一ID屏蔽变更

下面规则

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <!-- 单个ID形式。如果多个用“;”分隔,不允许出现空格 -->
        <id value="e92edde5-0153-4ec8-9cbb-b4d3f415aa33;af043384-c8a5-451e-88f4-457914e8e3bc"/>

        <!-- 多个ID节点形式 -->
        <!-- <id value="e92edde5-0153-4ec8-9cbb-b4d3f415aa33"/>
        <id value="af043384-c8a5-451e-88f4-457914e8e3bc"/> -->
    </strategy-blacklist>
</rule>

变更为

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <id>20210601-222214-909-1146-372-698;20210601-222214-988-3281-569-232</id>
        <!-- <id>{"discovery-guide-service-a":"20210601-222214-909-1146-372-698"}</id> -->
    </strategy-blacklist>
</rule>

IP地址和端口屏蔽变更

下面规则

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <!-- 单个Address形式。如果多个用“;”分隔,不允许出现空格 -->
        <address value="192.168.43.101:1201;192.168.*.102;1301"/>

        <!-- 多个Address节点形式 -->
        <!-- <address value="192.168.43.101:1201"/>
        <address value="192.168.*.102"/>
        <address value="1301"/> -->
    </strategy-blacklist>
</rule>

变更为

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <address>192.168.43.101:1201;192.168.*.102;1301</address>
        <!-- <address>{"discovery-guide-service-a":"3001"}</address> -->
    </strategy-blacklist>
</rule>

Header传递的内容增加对Json格式的支持

n-d-id-blacklist={"discovery-guide-service-a":"20210601-222214-909-1146-372-698", "discovery-guide-service-b":"20210601-222623-277-4978-633-279"}
n-d-address-blacklist={"discovery-guide-service-a":"3001", "discovery-guide-service-b":"3001"}

小贴士

利用通配符方式实现对指定日期上线的服务实例做屏蔽,示例内容如下,表示2021年6月1日(也可以精确到小时或者分钟)上线的a服务实例和b服务实例都会被屏蔽。该场景的使用意义是,在服务下线之前,使用者担心流量有损,同时使用者知道上一次服务发布的日期,只要该屏蔽策略一生效,负载均衡将实时过滤掉指定日期的服务实例。那么,使用者对这些服务实例无论是优雅停机,还是暴力下线,都不会造成任何流量有损,例如

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <id>{"discovery-guide-service-a":"20210601*", "discovery-guide-service-b":"20210601*"}</id>
    </strategy-blacklist>
</rule>

重构优化内置Header配置

为考虑到对接DiscoveryPlatform,数据结构尽量用Json来统一描述

下面配置

<headers>
    <header key="a" value="1"/>
    <header key="b" value="2"/>
</headers>

变更为

<header>{"a":"1", "b":"2"}</header>

重构优化Sentinel模块

① Sentinel扩展配置中心

上个版本只支持Nacos和Apollo,本版本支持Consul、Etcd、Zookeeper、Redis,除了支持配置中心外,也支持读取本地配置文件,当配置中心和本地配置文件同时存在时,以配置中心为优先

  • 依赖变更

下面三个依赖

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel</artifactId>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-local</artifactId>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-apollo</artifactId>
</dependency>

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-nacos</artifactId>
</dependency>

变更合并为如下一个依赖,囊括了六个配置中心

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-datasource</artifactId>
</dependency>
  • 配置变更

下面配置变更

spring.application.strategy.sentinel.enabled=true

变更为

spring.application.strategy.sentinel.datasource.enabled=true
  • 增强功能

支持本地规则文件读取,包括从classpath:xxx.json或者file:xxx.json两种方式读取

当配置中心存在对应规则时候,则忽略本地规则文件的规则;当配置中心不存在对应规则时候,则启动本地规则文件的规则

② Sentinel子模块重构

discovery-plugin-strategy-starter-service-sentinel模块主要实现Sentinel Limiter高级限流熔断,且不仅仅适用于微服务端,故用service-sentinel的后缀来命名并不准确,故依赖名变更为discovery-plugin-strategy-starter-sentinel-limiter

下面依赖

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

变更为

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-limiter</artifactId>
</dependency>

下面配置变更(去掉service字段)

spring.application.strategy.service.sentinel.limit.app.enabled=true
spring.application.strategy.service.sentinel.request.origin.key=n-d-service-id

变更为

spring.application.strategy.sentinel.limit.app.enabled=true
spring.application.strategy.sentinel.request.origin.key=n-d-service-id

下面类名变更(去掉Service字段,加上Strategy字段)

ServiceSentinelRequestOriginAdapter
DefaultServiceSentinelRequestOriginAdapter

类变更为

SentinelStrategyRequestOriginAdapter
DefaultSentinelStrategyRequestOriginAdapter

重构优化其它模块

① 重构优化Common模块

  • 抽象出中间件基本枚举类型,包括ConfigType,DiscoveryType,GatewayType,LoadBalancerType,ProtectorType,SentinelRuleType,TracingType等
  • 抽象出ExceptionUtil,对于Endpoint统一异常封装
  • 增加DiscoveryClientDelegate,为Plugin和Console模块提供代理接口
  • DiscoveryResponseErrorHandler和RestUtil,方法名getCause更名为getError,做了统一规范
  • JsonUtil增加Json字符串美化输出JsonUtil.toPrettyJson
  • PropertiesUtil增加方法
  • FileContextUtil从discovery-plugin-framework-starter模块移动到common模块,并重命名为FileUtil
  • BeanRegisterUtil从discovery-plugin-framework-starter模块移动到common模块
  • Dom4J通用类从discovery-plugin-framework-starter-parser模块移动到common模块
  • 抽象出DiscoveryThreadPoolFactory,对Nacos和Consul配置模块的线程池做了统一封装
  • 增加future通用模块,支持对WebFlux实现阻塞式获取数据
  • 修改RelationalType枚举类型,&&改为and,||改为or,规避&&的转义
  • 增加若干个枚举变量
  • 修改和优化内置变量名

② 重构优化Framework模块

  • 去掉RibbonProccessor
  • 某些HashMap的变量改成LinkedHashMap

③ 重构优化Framework Parser

  • PluginConfigParser和PluginConfigDeparser Bean的创建方式归属到Framework Parser模块

④ 重构优化配置订阅模块

  • 优化所有通用配置自动装配spring.factories
  • 增加所有配置订阅模块通过DisposableBean关闭订阅
  • 增加所有配置订阅模块additional-spring-configuration-metadata.json
  • 重构优化Redis配置订阅模块
  • 重构优化Zookeeper配置订阅模块,TreeCache方式改为NodeCache,Sleep Time默认值从6秒改为3秒
  • 规范化配置模块类对象的命名

⑤ 重构优化Admin Endpoint模块

  • 抽象出Resource层,封装Endpoint逻辑,Endpoint调用Resource,第三方可以通过调用Resource层,进行Endpoint扩展和自定义
  • 统一返回值为ResponseEntity,统一异常处理
  • Endpoint初始化次序做了优化
  • Endpoint如果返回值是Boolean类型,则返回值用true/false代替原来的ok/no,做了统一规范
  • 优化Swagger描述和返回值,部分接口为提升友好性加入默认值
  • 增加ServiceEndpoint
    • 增加获取注册中心类型,配置中心类型的接口
    • 增加根据网关类型列表获取网关服务名列表的接口
    • 增加根据服务类型列表获取服务名列表的接口
    • 增加根据服务名获取服务组名的接口
    • DiscoveryClientDecorator暴露出getDelegate方法,为ServiceEndpoint提供注册中心类型的获取逻辑
    • 其它更多接口
    • 返回值进行排序
  • 增加GatewayStrategyRouteEndpoint和ZuulStrategyRouteEndpoint接口
    • 增加增加网关路由的接口
    • 增加修改网关路由的接口
    • 增加删除网关路由的接口
    • 增加更新全部网关路由的接口
    • 增加根据路由Id查看网关路由的接口
    • 增加查看全部网关路由的接口

⑥ 重构优化Console Endpoint

  • 分解ConsoleEndpoint为AuthenticationEndpoint,ConfigEndpoint,RouteEndpoint,SentinelEndpoint,ServiceEndpoint,StrategyEndpoint,VersionEndpoint
  • 抽象出Resource层,封装Endpoint逻辑,Endpoint调用Resource,第三方可以通过调用Resource层,进行Endpoint扩展和自定义
  • 统一返回值为ResponseEntity,统一异常处理
  • 批量轮询调用返回对象ResultEntity加了serviceId、host和port三个字段
  • Endpoint初始化次序做了优化
  • Endpoint如果返回值是Boolean类型,则返回值用true/false代替原来的ok/no,做了统一规范
  • 优化Swagger描述和返回值,部分接口为提升友好性加入默认值
  • 增加AuthenticationEndpoint
    • 修改登录校验接口,对接DiscoveryPlatform,引入Access Web Token机制
  • 增加ConfigEndpoint
    • 增加更新规则配置到远程配置中心的接口,把配置类型(包括 xml | json | yaml | properties | html | text)推送到配置中心(只支持Nacos配置中心,其它配置中心不适用)
    • 增加批量查看规则配置的接口
    • 增加规则配置字符串转对象(parse)和对象转字符串(deparse)的接口
  • 增加RouteEndpoint
    • 增加批量增加网关路由的接口
    • 增加批量修改网关路由的接口
    • 增加批量删除网关路由的接口
    • 增加批量更新全部网关路由的接口
    • 增加批量查看全部网关路由的接口
  • 增加SentinelEndpoint
    • 增加批量查看哨兵规则列表的接口
  • 增加ServiceEndpoint
    • 增加获取注册中心类型,配置中心类型的接口
    • 增加根据网关类型获取网关服务名列表的接口
    • 增加根据服务名获取服务组名的接口
    • 其它更多接口
  • 增加StrategyEndpoint
  • 增加VersionEndpoint
    • 增加批量查看版本的接口

⑦ 重构优化Strategy Service

  • 优化ServiceStrategyRequestDecorator,去除不必要的getRequestURL和getRequestURI的代理,采用父类代理

⑧ 重构优化Strategy Gateway

  • 增加Spring Cloud Gateway中SkyWalking的相关开关
# 开启和关闭从SkyWalking apm-agent-core里反射获取TraceId并复制。由于SkyWalking对WebFlux上下文Threadlocal处理机制不恰当,导致产生的TraceId在全链路中并不一致,打开这个开关可以保证全链路TraceId都是一致的。缺失则默认为true
spring.application.strategy.gateway.skywalking.traceid.enabled=true

⑨ 重构优化Swagger模块

  • 自定义Swagger接口利用内置的SwaggerConfiguration来初始化,这样使用者可以不需要定义自己的SwaggerConfiguration。通过如下配置实现
swagger.service.scan.group=your-scan-group
swagger.service.scan.packages=your-scan-packages
  • 自定义内置的基准Docket组名。通过如下配置实现
swagger.service.base.group=your-base-group
  • Swagger界面显示的组名变更为Nepxion Discovery
  • Swagger界面显示的版本号表达为Nepxion Discovery版本号
  • 新增DiscoverySwaggerConstant用来定义静态变量
  • 自定义覆盖内置的Swagger配置。通过如下配置实现
# 启动和关闭Swagger。缺失则默认为true
swagger.service.enabled=true
# Swagger基准Docket组名
swagger.service.base.group=Nepxion Discovery
# Swagger自定义Docket组名
swagger.service.scan.group=Admin Center Restful APIs
# Swagger自定义扫描目录
swagger.service.scan.packages=your-scan-packages
# Swagger描述
swagger.service.description=your-description
# Swagger版本
swagger.service.version=6.11.0
# Swagger License名称
swagger.service.license.name=Apache License 2.0
# Swagger License链接
swagger.service.license.url=http://www.apache.org/licenses/LICENSE-2.0
# Swagger联系人名称
swagger.service.contact.name=Nepxion
# Swagger联系人网址
swagger.service.contact.url=https://github.com/Nepxion/Discovery
# Swagger联系人邮件
[email protected]
# Swagger服务条件网址
swagger.service.termsOfService.url=http://www.nepxion.com
  • 自定义基于Access Token Header的Swagger授权,包括全局授权和接口级授权。使用者通过如下方式进行扩展支持,可以选择其中一种,也可以两种并存。当两种并存的时候,全局授权优先于接口级授权
@Configuration
@ConditionalOnProperty(value = DiscoverySwaggerConstant.SWAGGER_SERVICE_ENABLED, matchIfMissing = true)
public class SwaggerAutoConfiguration {
    // Access Token Header全局授权
    @Bean
    public List<SecurityScheme> swaggerSecuritySchemes() {
        return Collections.singletonList(new ApiKey(DiscoveryConstant.N_D_ACCESS_TOKEN, DiscoveryConstant.N_D_ACCESS_TOKEN, "header"));
    }

    @Bean
    public List<SecurityContext> swaggerSecurityContexts() {
        return Collections.singletonList(
                SecurityContext
                        .builder()
                        .securityReferences(Collections.singletonList(new SecurityReference(DiscoveryConstant.N_D_ACCESS_TOKEN, scopes())))
                        .forPaths(PathSelectors.any())
                        .build());
    }

    private AuthorizationScope[] scopes() {
        return new AuthorizationScope[] { new AuthorizationScope("global", "accessAnything") };
    }

    // Access Token Header接口级授权
    @Bean
    public List<Parameter> swaggerHeaderParameters() {
        return Collections.singletonList(
                new ParameterBuilder()
                        .name(DiscoveryConstant.N_D_ACCESS_TOKEN)
                        .description("Access Token。格式:" + DiscoveryConstant.BEARER + "空格${access-token}。当全局授权(Authorize)后,此处不必填写")
                        .modelRef(new ModelRef("string"))
                        .parameterType("header")
                        .defaultValue(DiscoveryConstant.BEARER + " ${access-token}")
                        .required(false)
                        .build());
    }
}

把SwaggerAutoConfiguration加入到src/main/resources/META-INF/spring.factories进行自动装配

⑩ 其它优化

  • 优化日志打印

  • 优化去除了一些无效依赖的引入

  • 优化去除了一些过时方法的引用

  • 优化指南示例的配置,增加Apollo Demo环境的配置

  • 优化指南示例的测试用例

缺陷修复

① 修复在只引入注册中心依赖后(不引入其它三个依赖)无法启动的缺陷

② 修复Zookeeper重复订阅的缺陷

③ 修复Zookeeper服务发现时候,无法获取元数据的缺陷

④ 修复配置中心上,在删除配置后,响应事件回调值不是null的缺陷

⑤ 修复批量轮询调用,处理异常通过DiscoveryResponseErrorHandler返回异常信息的多线程缺陷,通过DiscoveryResponseContext中ThreadLocal予以修复

⑥ 修复Spring Boot 1.5版本重复触发反订阅事件的缺陷

⑦ 修复Spring Cloud Gateway和WebClient重复设置Header的缺陷

⑧ 修复外置Parameter、Cookie传递和内置Header并存时候,前两者失效的缺陷,取值顺序调整为外置Parameter > 外置Cookie > 外置Header > 内置Header

⑨ 修复全局灰度条件和局部灰度条件并存时候,取值顺序调整为局部灰度条件 > 全局灰度条件

⑩ 修复服务侧在无法获取到内置Header的缺陷

⑪ 更改内置Header的Map类型为LinkedCaseInsensitiveMap,大小写不敏感

⑫ 修复修复极端情况下SkyWalkingGatewayStrategyFilter引起的服务调用失败。感谢@jimodebeiju123贡献的PR

相关发布

DiscoveryAgent发布

DiscoveryAgent发布1.1.0版

重构优化

  • 优化Agent和Example的Pom结构
  • 优化Agent异常抛出

缺陷修复

  • 修复在线程没有切换的情况下,也会进入插件执行的缺陷
  • 修复agent.config文件重复打包的缺陷

感谢@zifenhan贡献的PR

DiscoveryDesktop发布

DiscoveryDesktop发布发布1.1.0版

功能迭代

  • 对接DiscoveryPlatform,支持Shiro和JWT的登录以及鉴权

相关下载

DiscoveryAgent下载

访问https://github.com/Nepxion/DiscoveryAgent/releases获取最新版本

DiscoveryDesktop下载

访问https://github.com/Nepxion/DiscoveryUI/releases获取最新版本