Awesome Open Source
Awesome Open Source

Discovery

Total visits Total lines License Maven Central Javadocs Build Status Codacy Badge Stars Stars

Spring Boot Spring Cloud Spring Cloud Alibaba Nepxion Discovery

Discovery PPT Discovery WIKI Discovery Platform WIKI Polaris WIKI

           

[Star]

  • Nepxion
  • 2020
  • 2020NacosSpring Cloud Alibaba
  • 2021
  • 2021
  • 2021Gitee
  • Nacos Group MemberSpring Cloud Alibaba Member
  • Spring Cloud AlibabaNacosSentinelOpenTracing Committer & Contributor

Discovery

Spring Cloud
Discovery 1.x.x ~ 6.x.x Camden ~ Hoxton
DiscoveryX 7.x.x 202x

Polaris

PolarisDiscovery

  • Nepxion Discovery
  • DCNDSUSET
  • PaaS
Discovery Spring Cloud
Polaris 1.x.x 6.x.x Finchley ~ Hoxton
Polaris 2.x.x 7.x.x 202x

1394997

Discovery

Polaris

DiscoveryPolaris

DiscoveryPolaris

DiscoveryPolaris

Polaris

Discovery

Discovery

Discovery

Discovery

Discovery

  • 201712
  • 201803
  • 201806GitHub
  • 201806v1.0.0Camden
  • 201806v2.0.0Dalston
  • 201807v3.0.0Edgware
  • 201807v4.0.0Finchley
  • 201904v5.0.0Greenwich
  • 202004v6.0.0Hoxton
  • 202104v7.0.0202x

DiscoverySpring Cloud & Spring Cloud AlibabaDiscoveryRibbon & Spring Cloud LoadBalancerFeign & RestTemplate & WebClientSpring Cloud Gateway & Zuul

  • Spring Cloud Alibaba
  • NacosEurekaConsulZookeeper
  • NacosApolloRedisZookeeperConsulEtcd
  • SentinelHystrixResilience4J
  • OpenTracingOpenTelemetryJaegerSkyWalkingZipkin
  • Prometheus MicrometerSpring Boot Admin
  • Java AgentThreadLocal
  • Spring Spel
  • Spring Matcher
  • Spring Cloud GatewayZuul
  • Spring Cloud EdgwareFinchleyGreenwichHoxton202xSpring Cloud
  • Java8Java16SDK

    • IP
    • IP
    • | | |
    • HeaderParameterCookieRPC Method
    • HeaderJob
    • ID
    • IP
    • Agent
    • Hystrix
    • DataSource
    • Queue
    • SwaggerRest
    • Sentinel
    • Sentinel
    • Sentinel
    • Sentinel
    • Sentinel
    • Sentinel
    • SentinelIP
    • SentinelHeaderParameterCookie
    • Sentinel
    • Sentinel
  • API

    • Git
  • DockerKubernetes

  • pom.xml

  • Metadata5

      • metadata.group
      • metadata.versionGit
      • metadata.region
      • metadata.env
      • metadata.zone
  • HeaderParameterCookieJsonHeader

>= <=

Spring Cloud Spring Boot Spring Cloud Alibaba
7.0.0
master 202x.x.x 2.5.x
2.4.1 ``
202x.x
6.12.1 6.x.x Hoxton.SR5 ``
Hoxton
Greenwich
Finchley
2.3.x.RELEASE
2.2.x.RELEASE
2.1.x.RELEASE
2.0.x.RELEASE
2.2.x.RELEASE
2.2.x.RELEASE
2.1.x.RELEASE
2.0.x.RELEASE
5.6.0 5.x.x Greenwich 2.1.x.RELEASE 2.1.x.RELEASE
4.15.0 4.x.x Finchley 2.0.x.RELEASE 2.0.x.RELEASE
3.28.1 3.x.x Edgware 1.5.x.RELEASE 1.5.x.RELEASE
2.0.x 2.x.x Dalston 1.x.x.RELEASE 1.5.x.RELEASE
1.0.x 1.x.x Camden 1.x.x.RELEASE 1.5.x.RELEASE

| |

  • 7.x.x202x.x.x
  • 6.x.xFinchleyGreenwichHoxton
  • 5.x.xGreenwich
  • 4.x.xFinchley
  • 3.x.xEdgware
  • 2.x.xDalston
  • 1.x.xCamden
Guava
Caffeine
Dom4J
Swagger
Swagger
Apollo
Zookeeper Curator
Consul
JEtcd
Nacos
Eureka
Redis
Sentinel
Hystrix
OpenTelemetry
OpenTracing
OpenTracing%20Sping%20Cloud
OpenTracing%20Jaeger
OpenTracing%20Concurrent
SkyWalking
Spring Boot
Spring Alibaba Spring
Spring Cloud
Spring Cloud Alibaba
Spring Boot

Github Issues

Nepxion Discovery10000

Nepxion Discovery202122600

Discovery

Polaris

DiscoveryAgent

DiscoveryDesktop

Discovery

Polaris

Gitee Wiki

Github Wiki

Discovery

discovery-commons
   discovery-common
   discovery-common-apollo Apollo
   discovery-common-nacos Nacos
   discovery-common-redis Redis
   discovery-common-zookeeper Zookeeper
   discovery-common-consul Consul
   discovery-common-etcd Etcd
discovery-plugin-framework
   discovery-plugin-framework-starter Starter
   discovery-plugin-framework-starter-parser Starter
discovery-plugin-register-center
   discovery-plugin-register-center-starter Starter
   discovery-plugin-register-center-starter-eureka Eureka Starter
   discovery-plugin-register-center-starter-consul Consul Starter
   discovery-plugin-register-center-starter-zookeeper Zookeeper Starter
   discovery-plugin-register-center-starter-nacos Nacos Starter
discovery-plugin-config-center
   discovery-plugin-config-center-starter Starter
   discovery-plugin-config-center-starter-apollo Apollo Starter
   discovery-plugin-config-center-starter-nacos Nacos Starter
   discovery-plugin-config-center-starter-redis Redis Starter
   discovery-plugin-config-center-starter-zookeeper Zookeeper Starter
   discovery-plugin-config-center-starter-consul Consul Starter
   discovery-plugin-config-center-starter-etcd Etcd Starter
discovery-plugin-admin-center
   discovery-plugin-admin-center-starter Starter
discovery-plugin-strategy
   discovery-plugin-strategy-starter Starter
   discovery-plugin-strategy-starter-service Starter
   discovery-plugin-strategy-starter-zuul ZuulStarter
   discovery-plugin-strategy-starter-gateway Spring Cloud GatewayStarter
   discovery-plugin-strategy-starter-hystrix HystrixStarter
   discovery-plugin-strategy-starter-opentelemetry OpenTelemetryStarter
   discovery-plugin-strategy-starter-opentracing OpenTracingStarter
   discovery-plugin-strategy-starter-skywalking SkyWalkingStarter
   discovery-plugin-strategy-starter-sentinel-datasource SentinelStarter
   discovery-plugin-strategy-starter-sentinel-limiter Sentinel LimiterStarter
   discovery-plugin-strategy-starter-sentinel-monitor SentinelStarter
   discovery-plugin-strategy-starter-sentinel-opentelemetry Sentinel OpenTelemetryStarter
   discovery-plugin-strategy-starter-sentinel-opentracing Sentinel OpenTracingStarter
   discovery-plugin-strategy-starter-sentinel-skywalking Sentinel SkyWalkingStarter
   discovery-plugin-strategy-starter-sentinel-micrometer Sentinel MicrometerStarter
discovery-plugin-test
   discovery-plugin-test-starter-automation Starter
discovery-console
   discovery-console-starter starter
   discovery-console-starter-apollo Apollo Starter
   discovery-console-starter-nacos Nacos Starter
   discovery-console-starter-redis Redis Starter
   discovery-console-starter-zookeeper Zookeeper Starter
   discovery-console-starter-consul Consul Starter
   discovery-console-starter-etcd Etcd Starter
discovery-springcloud-examples
   discovery-springcloud-example-admin Spring Boot Admin
   discovery-springcloud-example-console
   discovery-springcloud-example-eureka Eureka
   discovery-springcloud-example-service
   discovery-springcloud-example-zuul Zuul
   discovery-springcloud-example-gateway Spring Cloud Gateway

DiscoveryPlatform

discovery-platform-server
   discovery-platform-starter-server Starter
   discovery-platform-starter-server-mysql MySQLStarter
   discovery-platform-starter-server-h2 H2Starter
   discovery-platform-starter-server-ldap LdapStarter
   discovery-platform-starter-server-ui
discovery-platform-client
   discovery-platform-starter-client Starter
discovery-platform-common
   discovery-platform-starter-common-dingding Starter
   discovery-platform-starter-common-mail Starter
discovery-platform-application

DiscoveryAgent

discovery-agent-starter Agent Starter
discovery-agent-starter-plugin-strategy Agent Plugin Starter
discovery-agent-starter-plugin-mdc MDCAgent Plugin Starter
discovery-agent-example

DiscoveryUI

desktop Nepxion Discovery
web Nepxion Discovery Web

DiscoveryContrib

discovery-contrib-plugin-starter Contrib Plugin Starter
discovery-contrib-plugin-starter-rocketmq RocketMQContrib Plugin Starter
discovery-contrib-plugin-starter-shardingsphere ShardingSphereContrib Plugin Starter
discovery-contrib-example

Discovery Total lines
DiscoveryPlatform Total lines
DiscoveryGuide Total lines
DiscoveryAgent Total lines
DiscoveryUI Total lines
DiscoveryContrib Total lines

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-register-center-starter-nacos</artifactId>
    <artifactId>discovery-plugin-register-center-starter-eureka</artifactId>
    <artifactId>discovery-plugin-register-center-starter-consul</artifactId>
    <artifactId>discovery-plugin-register-center-starter-zookeeper</artifactId>
    <version>${discovery.version}</version>
</dependency>
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-config-center-starter-apollo</artifactId>
    <artifactId>discovery-plugin-config-center-starter-nacos</artifactId>
    <artifactId>discovery-plugin-config-center-starter-redis</artifactId>
    <artifactId>discovery-plugin-config-center-starter-zookeeper</artifactId>
    <artifactId>discovery-plugin-config-center-starter-consul</artifactId>
    <artifactId>discovery-plugin-config-center-starter-etcd</artifactId>
    <version>${discovery.version}</version>
</dependency>
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>discovery-plugin-admin-center-starter</artifactId>
    <version>${discovery.version}</version>
</dependency>

ZuulSpring Cloud Gateway

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-service</artifactId>
    <artifactId>discovery-plugin-strategy-starter-zuul</artifactId>
    <artifactId>discovery-plugin-strategy-starter-gateway</artifactId>
    <version>${discovery.version}</version>
</dependency>
  • Sentinel
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-datasource</artifactId>
    <version>${discovery.version}</version>
</dependency>
  • SentinelSentinel LimiterServlet
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-limiter</artifactId>
    <version>${discovery.version}</version>
</dependency>
  • HystrixHystrix
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-hystrix</artifactId>
    <version>${discovery.version}</version>
</dependency>
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-console-starter-apollo</artifactId>
    <artifactId>discovery-console-starter-nacos</artifactId>
    <artifactId>discovery-console-starter-redis</artifactId>
    <artifactId>discovery-console-starter-zookeeper</artifactId>
    <version>${discovery.version}</version>
</dependency>

ZuulSpring Cloud Gateway

F

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-opentelemetry</artifactId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-opentracing</artifactId>
    <artifactId>discovery-plugin-strategy-starter-sentinel-skywalking</artifactId>
    <version>${discovery.version}</version>
</dependency>
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-test-starter</artifactId>
    <version>${discovery.version}</version>
</dependency>

Agent

-javaagent:/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar -Dthread.scan.packages=com.abc;com.xyz

Nacos

Git clone https://github.com/Nepxion/DiscoveryGuide.git6.x.x-simple

IDE

Nacos

Nacos

  • Windowsbinstartup.cmd
  • Linuxbinstartup.sh

  • IDE
DiscoveryGuideServiceA1.java A1 3001 1.0 dev env1 zone1
DiscoveryGuideServiceA2.java A2 3002 1.1 qa common zone2
DiscoveryGuideServiceB1.java B1 4001 1.0 qa env1 zone1
DiscoveryGuideServiceB2.java B2 4002 1.1 dev common zone2
DiscoveryGuideGateway.java Gateway 5001 1.0
DiscoveryGuideZuul.java Zuul 5002 1.0

API -> A -> B

Postman

gateway 
-> [ID=discovery-guide-service-a][T=service][P=Nacos][H=192.168.0.107:3001][V=1.0][R=dev][E=env1][Z=zone1][G=discovery-guide-group][TID=48682.7508.15870951148324081][SID=49570.77.15870951148480000] 
-> [ID=discovery-guide-service-b][T=service][P=Nacos][H=192.168.0.107:4001][V=1.0][R=qa][E=env1][Z=zone2][G=discovery-guide-group][TID=48682.7508.15870951148324081][SID=49571.85.15870951189970000]
zuul 
-> [ID=discovery-guide-service-a][T=service][P=Nacos][H=192.168.0.107:3001][V=1.0][R=dev][E=env1][Z=zone1][G=discovery-guide-group][TID=48682.7508.15870951148324081][SID=49570.77.15870951148480000] 
-> [ID=discovery-guide-service-b][T=service][P=Nacos][H=192.168.0.107:4001][V=1.0][R=qa][E=env1][Z=zone2][G=discovery-guide-group][TID=48682.7508.15870951148324081][SID=49571.85.15870951189970000]
  • PostmanDiscoveryAgent

Spring Cloud 202x

Spring Cloud 202xSpring Cloud LoadBalancerWebFluxDiscoveryAgent

-javaagent:C:/opt/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar

URL
/invoke/
/invoke-async/ @Async
/invoke-thread/
/invoke-threadpool/

Blue-Green Deployment

/

Gray Release Canary Release

5%95%

Rolling Release

Header | Parameter | Cookie | | JsonHeadern-d-HeaderHeader

->A->B->C->DBCBCBC

n-d-nNepxiondDiscovery

Spring Cloud GatewayGroupdiscovery-guide-groupData Iddiscovery-guide-gatewaySpring Cloud Gateway1.0

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version>1.0</version>
    </strategy>
</rule>

Spring Cloud Gateway1.0a1.1b

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

1.01.1ab

<version>1.0;1.1</version>
<version>{"discovery-guide-service-a":"1.0;1.1", "discovery-guide-service-b":"1.0;1.1"}</version>

Spring AntPathMatcherSpring Matcher*?

* - 
1.* - 1
"discovery-guide-service-b":"1.*;1.2.?"

discovery-guide-service-b11.21

Header

n-d-version=1.0
n-d-version={"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}

ZuulGroupdiscovery-guide-groupData Iddiscovery-guide-zuulZuuldev

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <region>dev</region>
    </strategy>
</rule>

Zuuldevaqab

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <region>{"discovery-guide-service-a":"dev", "discovery-guide-service-b":"qa"}</region>
    </strategy>
</rule>
<region>dev</region>
<region>{"discovery-guide-service-a":"dev", "discovery-guide-service-b":"dev"}</region>

devqaab

<region>dev;qa</region>
<region>{"discovery-guide-service-a":"dev;qa", "discovery-guide-service-b":"dev;aq"}</region>

Spring AntPathMatcherSpring Matcher*?

* - 
d* - d
"discovery-guide-service-b":"d*;q?"

discovery-guide-service-bdq1

Header

n-d-region=dev
n-d-region={"discovery-guide-service-a":"dev", "discovery-guide-service-b":"dev"}

IP

ZuulIPGroupdiscovery-guide-groupData Iddiscovery-guide-zuulZuulIPIP

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <!-- <address>127.0.0.1:3001</address> -->
        <!-- <address>127.0.0.1</address> -->
        <address>3001</address>
    </strategy>
</rule>

IPZuul3001a4001b

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <address>{"discovery-guide-service-a":"3001", "discovery-guide-service-b":"4001"}</address>
    </strategy>
</rule>
<address>3001</address>
<address>{"discovery-guide-service-a":"3001", "discovery-guide-service-b":"3001"}</address>

30014001ab

<address>3001;4001</address>
<address>{"discovery-guide-service-a":"3001;4001", "discovery-guide-service-b":"3001;4001"}</address>

Spring AntPathMatcherSpring Matcher*?

* - 
3* - 3
"discovery-guide-service-b":"3*;400?"

discovery-guide-service-b34001

Header

n-d-address=3001
n-d-address={"discovery-guide-service-a":"3001", "discovery-guide-service-b":"3001"}

IP

HeaderParameterCookieHeader

HeaderParameterCookieuserHeaderParameterCookie

HeaderParameterCookieuserParameter > Cookie > Header > Header

HeaderParameterCookieuserageaddressHeaderParameterCookieuserHeaderageParameteraddressCookie

Spring Spel=!=><&&||matches

Spring Spelmatches

  • ``
[a-zA-Z0-9._%+-][email protected][a-zA-Z0-9.-]+.[a-zA-Z]{2,4}
  • 2
[a-z]{3}2

Spring Spel

abca1b2c3

#H['a'] == '1' && #H['b'] <= '2' && #H['c'] != '3'

#H['a'] == '1' and #H['b'] <= '2' and #H['c'] != '3'

#H['a']Spring Spela

HHHttpHttpHeaderParameterCookie

Spring Spel

  • nullfalse#H['a'] > '2'aanullnull > 2false
  • nulltrue#H['a'] != '2'aanullnull != 2true

Spring Spel

+
-
*
/ div
% mod
== eq equal
!= ne not equal
> gt greater than
>= ge greater than equal
< lt less than
<= le less than equal
&& and
|| or
! not
matches #H['a'] matches '[a-z]{3}2'
contains #H['a'].contains('123')
between #H['a'] between {1, 2}
instanceof #H['a'] instanceof 'T(String)'

Spring SpelXML

& &amp;
< &lt;
" &quot;
> &gt;
' &apos;

XML

#H['a'] == '1' &amp;&amp; #H['b'] &lt;= '2' &amp;&amp; #H['c'] != '3'

Spring Cloud GatewayGroupdiscovery-guide-groupData Iddiscovery-guide-gateway

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

    <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>

a HeaderParameterCookie expression="#H['a'] == '1'"

Header/Parameter/Cookiesa=1b=2

<condition>id="blue-condition" expression="#H['a'] == '1' and #H['b'] == '2'" version-id="green-route" <route> id="green-route" type="version"

{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}

Header/Parameter/Cookiesa=1

<condition>id="green-condition" expression="#H['a'] == '1'" version-id="blue-route" <route> id="blue-route" type="version"

{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}

Header/Parameter/Cookies

  • <condition>id="basic-condition"
{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}
  • <strategy>
{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}

  • Spring Cloud Ribbon

Header/Parameter/CookiesHeaderHeader/Parameter/Cookies

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

HeaderJobHeaderHeaderHeaderHeader

Spring Cloud GatewayFinchley

  • | |
  • |

5

  • version
  • region
  • address IP
  • version-weight
  • region-weight

Spring Spel

Spring Matcher

  • version-id``region-id
  • type="version"``type="region"
  • routeJson

IP

  • version-id``address-id
  • type="version"``type="address"
  • routeJsonIP

| JsonHeadern-d-HeaderHeader

->A->B->C->DBCBCBC

Spring Cloud GatewayGroupdiscovery-guide-groupData Iddiscovery-guide-gatewaySpring Cloud Gateway1.090%1.110%

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version-weight>1.0=90;1.1=10</version-weight>
    </strategy>
</rule>

Spring Cloud Gatewaya1.090%1.110%b1.080%1.120%

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version-weight>{"discovery-guide-service-a":"1.0=90;1.1=10", "discovery-guide-service-b":"1.0=80;1.1=20"}</version-weight>
    </strategy>
</rule>
<version-weight>1.0=90;1.1=10</version-weight>
<version-weight>{"discovery-guide-service-a":"1.0=90;1.1=10", "discovery-guide-service-b":"1.0=90;1.1=10"}</version-weight>

Header

n-d-version-weight=1.0=90;1.1=10
n-d-version-weight={"discovery-guide-service-a":"1.0=90;1.1=10", "discovery-guide-service-b":"1.0=90;1.1=10"}

ZuulGroupdiscovery-guide-groupData Iddiscovery-guide-zuulZuuldev85%qa15%

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <region-weight>dev=85;qa=15</region-weight>
    </strategy>
</rule>

Zuuladev85%qa15%bdev75%qa25%

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <region-weight>{"discovery-guide-service-a":"dev=85;qa=15", "discovery-guide-service-b":"dev=75;qa=25"}</region-weight>
    </strategy>
</rule>
<region-weight>dev=85;qa=15</region-weight>
<region-weight>{"discovery-guide-service-a":"dev=85;qa=15", "discovery-guide-service-b":"dev=85;qa=15"}</region-weight>

Header

n-d-region-weight=dev=85;qa=15
n-d-region-weight={"discovery-guide-service-a":"dev=85;qa=15", "discovery-guide-service-b":"dev=85;qa=15"}

ZuulGroupdiscovery-guide-groupData Iddiscovery-guide-zuul

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <!--  -->
    <!-- 100%0% -->
    <!-- <strategy>
        <version>{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</version>
    </strategy> -->

    <strategy-release>
        <conditions type="gray">
            <!-- 1expression -->
            <!-- <condition id="gray-condition-1" expression="#H['a'] == '1'" version-id="gray-route=10;stable-route=90"/> -->
            <!-- 2expression -->
            <!-- <condition id="gray-condition-2" 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>

  • a1.090%a1.0b1.0
  • a1.110%a1.1b1.1

gray-route10%stable-route90%

3

  • version
  • region
  • address IP

  • version-id``region-id
  • type="version"``type="region"
  • routeJson

IP

  • version-id``address-id
  • type="version"``type="address"
  • routeJsonIP

-> ->

->

HeaderHeaderHeader

# HeaderHeaderHeadertruetrue
spring.application.strategy.gateway.header.priority=false
# HeaderHeaderHeadertrue
spring.application.strategy.gateway.original.header.ignored=true

# HeaderHeaderHeadertruetrue
spring.application.strategy.zuul.header.priority=false
# HeaderHeaderHeadertrue
spring.application.strategy.zuul.original.header.ignored=true

->

HeaderHeaderHeader

# HeaderHeaderHeadertruetrue
# spring.application.strategy.service.header.priority=true

->

header.priority

aHeaderParameterCookie

  • a1a1.1b1.1
  • aab 1.15%ab 1.095%
<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-release>
        <conditions type="blue-green"> 
            <condition id="blue-condition" expression="#H['a'] == '1'" version-id="route-2"/>
        </conditions>

        <conditions type="gray">
            <condition id="gray-condition" version-id="route-1=95;route-2=5"/>
        </conditions>

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

0%

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-release>
        <conditions type="gray">
            <condition id="gray-condition-1" expression="#H['a'] == '1'" version-id="route-1=0;route-2=100"/>
            <condition id="gray-condition-2" version-id="route-1=95;route-2=5"/>
        </conditions>

        <routes>
            <route id="route-1" type="version">{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</route>
            <route id="route-2" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>
        </routes>
    </strategy-release>
</rule>
<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version>{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}</version>
    </strategy>
    <strategy-release>
        <conditions type="blue-green">
            <condition id="condition-0" expression="#H['a'] == '1'" version-id="route-0"/>
            <condition id="condition-1" expression="#H['a'] == '2'" version-id="route-1"/>
            <condition id="basic-condition" version-id="route-0"/>
        </conditions>
        <conditions type="gray">
            <condition id="condition-0" expression="#H['a'] == '3'" version-id="route-0=10;route-1=90"/>
            <condition id="condition-1" expression="#H['a'] == '4'" version-id="route-0=40;route-1=60"/>
            <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.0", "discovery-guide-service-b":"1.0"}</route>
            <route id="route-1" type="version">{"discovery-guide-service-a":"1.1", "discovery-guide-service-b":"1.1"}</route>
        </routes>
    </strategy-release>
</rule>
if (a == 1) {
    blue-greenroute-0
} else if (a == 2) {
    blue-greenroute-1
} else {
    blue-greenroute-0
}

basic-condition

if (a == 1) {
    route-0
} else if (a == 2) {
    route-1
} else if (a == 3) {
    route-0=10;route-1=90
} else if (a == 4) {
    route-0=40;route-1=60
} else {
    route-0=0;route-1=100
    route-0=0route-1
}
if (a == 1) {
    route-0
} else if (a == 2) {
    route-1
} else if (a == 3) {
    route-0=10;route-1=90
} else if (a == 4) {
    route-0=40;route-1=60
} else {
    <strategy>
}

ABB

header.priority

AB

header.priority

  • Header
n-d-version=1.0
n-d-version={"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}
  • Header
n-d-version-weight=1.0=90;1.1=10
n-d-version-weight={"discovery-guide-service-a":"1.0=90;1.1=10", "discovery-guide-service-b":"1.0=90;1.1=10"}
  • Header
n-d-region=qa
n-d-region={"discovery-guide-service-a":"qa", "discovery-guide-service-b":"qa"}
  • Header
n-d-region-weight=dev=99;qa=1
n-d-region-weight={"discovery-guide-service-a":"dev=99;qa=1", "discovery-guide-service-b":"dev=99;qa=1"}
  • IPHeader
n-d-address=3001;4002
n-d-address={"discovery-guide-service-a":"127.0.0.1:3001", "discovery-guide-service-b":"127.0.0.1:4002"}
n-d-address={"discovery-guide-service-a":"127.0.0.1", "discovery-guide-service-b":"127.0.0.1"}
n-d-address={"discovery-guide-service-a":"3001", "discovery-guide-service-b":"4002"}
n-d-env=env1
  • IDHeader
n-d-id-blacklist=20210601-222214-909-1146-372-698;20210601-222623-277-4978-633-279
n-d-id-blacklist={"discovery-guide-service-a":"20210601-222214-909-1146-372-698", "discovery-guide-service-b":"20210601-222623-277-4978-633-279"}
  • IPHeader
n-d-address-blacklist=3001;4002
n-d-address-blacklist={"discovery-guide-service-a":"127.0.0.1:3001", "discovery-guide-service-b":"127.0.0.1:4002"}
n-d-address-blacklist={"discovery-guide-service-a":"127.0.0.1", "discovery-guide-service-b":"127.0.0.1"}
n-d-address-blacklist={"discovery-guide-service-a":"3001", "discovery-guide-service-b":"4002"}

Header

Http

Headern-d-Header

# RESTtrue
spring.application.strategy.rest.intercept.enabled=true
# HeaderDebugfalse
spring.application.strategy.rest.intercept.debug.enabled=true
# RESTFeignRestTemplateWebClientHeaderHeadertrace-id, span-id;
spring.application.strategy.context.request.headers=trace-id;span-id
# RESTFeignRestTemplateWebClientHeaderHeadermobile;
spring.application.strategy.business.request.headers=user;mobile;location

Parameter

Http

http://localhost:5001/discovery-guide-service-a/invoke/gateway?a=1

http://localhost:5001/discovery-guide-service-a/invoke/gateway?a=2

Cookie Http

hosts

127.0.0.1 common.nepxion.com
127.0.0.1 env1.nepxion.com
127.0.0.1 env2.nepxion.com
  • env1.nepxion.comenv1

  • common.nepxion.comcommon

RPC-Method

RPC

HeaderHeaderHeader

Groupdiscovery-guide-groupData Iddiscovery-guide-groupa1.0b1.1

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

# HeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.gateway.core.header.transmission.enabled=true
spring.application.strategy.zuul.core.header.transmission.enabled=true
spring.application.strategy.feign.core.header.transmission.enabled=true
spring.application.strategy.rest.template.core.header.transmission.enabled=true
spring.application.strategy.web.client.core.header.transmission.enabled=true

ZuulSpring Cloud GatewayDefaultGatewayStrategyRouteFilter[email protected]Bean

public String getRouteVersion();

public String getRouteRegion();

public String getRouteEnvironment();

public String getRouteAddress();

public String getRouteVersionWeight();

public String getRouteRegionWeight();

public String getRouteIdBlacklist();

public String getRouteAddressBlacklist();

GatewayStrategyRouteFilter

// A/B TestingA/B
// Header
public class MyGatewayStrategyRouteFilter extends DefaultGatewayStrategyRouteFilter {
    private static final Logger LOG = LoggerFactory.getLogger(MyGatewayStrategyRouteFilter.class);

    private static final String DEFAULT_A_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.0\", \"discovery-guide-service-b\":\"1.1\"}";
    private static final String DEFAULT_B_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.1\", \"discovery-guide-service-b\":\"1.0\"}";
    private static final String DEFAULT_A_ROUTE_REGION = "{\"discovery-guide-service-a\":\"dev\", \"discovery-guide-service-b\":\"qa\"}";
    private static final String DEFAULT_B_ROUTE_REGION = "{\"discovery-guide-service-a\":\"qa\", \"discovery-guide-service-b\":\"dev\"}";
    private static final String DEFAULT_A_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3001\", \"discovery-guide-service-b\":\"4002\"}";
    private static final String DEFAULT_B_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3002\", \"discovery-guide-service-b\":\"4001\"}";

    @Value("${a.route.version:" + DEFAULT_A_ROUTE_VERSION + "}")
    private String aRouteVersion;

    @Value("${b.route.version:" + DEFAULT_B_ROUTE_VERSION + "}")
    private String bRouteVersion;

    @Value("${a.route.region:" + DEFAULT_A_ROUTE_REGION + "}")
    private String aRouteRegion;

    @Value("${b.route.region:" + DEFAULT_B_ROUTE_REGION + "}")
    private String bRouteRegion;

    @Value("${a.route.address:" + DEFAULT_A_ROUTE_ADDRESS + "}")
    private String aRouteAddress;

    @Value("${b.route.address:" + DEFAULT_B_ROUTE_ADDRESS + "}")
    private String bRouteAddress;

    // Header
    @Override
    public String getRouteVersion() {
        String user = strategyContextHolder.getHeader("user");

        LOG.info("Header, Header user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteVersion);

            return aRouteVersion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteVersion);

            return bRouteVersion;
        }

        return super.getRouteVersion();
    }

    // Parameter
    @Override
    public String getRouteRegion() {
        String user = strategyContextHolder.getParameter("user");

        LOG.info("Parameter, Parameter user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteRegion);

            return aRouteRegion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteRegion);

            return bRouteRegion;
        }

        return super.getRouteRegion();
    }

    // CookieIP
    @Override
    public String getRouteAddress() {
        String user = strategyContextHolder.getCookie("user");

        LOG.info("CookieIP, Cookie user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("IP={}", aRouteAddress);

            return aRouteAddress;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("IP={}", bRouteAddress);

            return bRouteAddress;
        }

        return super.getRouteAddress();
    }

    @Autowired
    private GatewayStrategyContextHolder gatewayStrategyContextHolder;

    // 
    @Override
    public String getRouteEnvironment() {
        String host = gatewayStrategyContextHolder.getURI().getHost();
        if (host.contains("nepxion.com")) {
            LOG.info(", URL={}", host);

            String environment = host.substring(0, host.indexOf("."));

            LOG.info("={}", environment);

            return environment;
        }

        return super.getRouteEnvironment();
    }

    // 
    /*@Override
    public String getRouteVersion() {
        LOG.info("");

        List<Pair<String, Integer>> weightList = new ArrayList<Pair<String, Integer>>();
        weightList.add(new ImmutablePair<String, Integer>(aRouteVersion, 30));
        weightList.add(new ImmutablePair<String, Integer>(bRouteVersion, 70));
        MapWeightRandom<String, Integer> weightRandom = new MapWeightRandom<String, Integer>(weightList);

        return weightRandom.random();
    }*/
}

@Bean

@Bean
public GatewayStrategyRouteFilter gatewayStrategyRouteFilter() {
    return new MyGatewayStrategyRouteFilter();
}

ZuulStrategyRouteFilter

// A/B TestingA/B
// Header
public class MyZuulStrategyRouteFilter extends DefaultZuulStrategyRouteFilter {
    private static final Logger LOG = LoggerFactory.getLogger(MyZuulStrategyRouteFilter.class);

    private static final String DEFAULT_A_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.0\", \"discovery-guide-service-b\":\"1.1\"}";
    private static final String DEFAULT_B_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.1\", \"discovery-guide-service-b\":\"1.0\"}";
    private static final String DEFAULT_A_ROUTE_REGION = "{\"discovery-guide-service-a\":\"dev\", \"discovery-guide-service-b\":\"qa\"}";
    private static final String DEFAULT_B_ROUTE_REGION = "{\"discovery-guide-service-a\":\"qa\", \"discovery-guide-service-b\":\"dev\"}";
    private static final String DEFAULT_A_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3001\", \"discovery-guide-service-b\":\"4002\"}";
    private static final String DEFAULT_B_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3002\", \"discovery-guide-service-b\":\"4001\"}";

    @Value("${a.route.version:" + DEFAULT_A_ROUTE_VERSION + "}")
    private String aRouteVersion;

    @Value("${b.route.version:" + DEFAULT_B_ROUTE_VERSION + "}")
    private String bRouteVersion;

    @Value("${a.route.region:" + DEFAULT_A_ROUTE_REGION + "}")
    private String aRouteRegion;

    @Value("${b.route.region:" + DEFAULT_B_ROUTE_REGION + "}")
    private String bRouteRegion;

    @Value("${a.route.address:" + DEFAULT_A_ROUTE_ADDRESS + "}")
    private String aRouteAddress;

    @Value("${b.route.address:" + DEFAULT_B_ROUTE_ADDRESS + "}")
    private String bRouteAddress;

    // Header
    @Override
    public String getRouteVersion() {
        String user = strategyContextHolder.getHeader("user");

        LOG.info("Header, Header user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteVersion);

            return aRouteVersion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteVersion);

            return bRouteVersion;
        }

        return super.getRouteVersion();
    }

    // Parameter
    @Override
    public String getRouteRegion() {
        String user = strategyContextHolder.getParameter("user");

        LOG.info("Parameter, Parameter user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteRegion);

            return aRouteRegion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteRegion);

            return bRouteRegion;
        }

        return super.getRouteRegion();
    }

    // CookieIP
    @Override
    public String getRouteAddress() {
        String user = strategyContextHolder.getCookie("user");

        LOG.info("CookieIP, Cookie user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("IP={}", aRouteAddress);

            return aRouteAddress;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("IP={}", bRouteAddress);

            return bRouteAddress;
        }

        return super.getRouteEnvironment();
    }

    @Autowired
    private ZuulStrategyContextHolder zuulStrategyContextHolder;

    // 
    @Override
    public String getRouteEnvironment() {
        String requestURL = zuulStrategyContextHolder.getRequestURL();
        if (requestURL.contains("nepxion.com")) {
            LOG.info(", URL={}", requestURL);

            String host = requestURL.substring("http://".length(), requestURL.length());
            String environment = host.substring(0, host.indexOf("."));

            LOG.info("={}", environment);

            return environment;
        }

        return super.getRouteEnvironment();
    }

    // 
    /*@Override
    public String getRouteVersion() {
        LOG.info("");

        List<Pair<String, Integer>> weightList = new ArrayList<Pair<String, Integer>>();
        weightList.add(new ImmutablePair<String, Integer>(aRouteVersion, 30));
        weightList.add(new ImmutablePair<String, Integer>(bRouteVersion, 70));
        MapWeightRandom<String, Integer> weightRandom = new MapWeightRandom<String, Integer>(weightList);

        return weightRandom.random();
    }*/
}

@Bean

@Bean
public ZuulStrategyRouteFilter zuulStrategyRouteFilter() {
    return new MyZuulStrategyRouteFilter();
}

ServiceStrategyRouteFilter

// A/B TestingA/B
// Header
public class MyServiceStrategyRouteFilter extends DefaultServiceStrategyRouteFilter {
    private static final Logger LOG = LoggerFactory.getLogger(MyServiceStrategyRouteFilter.class);

    private static final String DEFAULT_A_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.0\", \"discovery-guide-service-b\":\"1.1\"}";
    private static final String DEFAULT_B_ROUTE_VERSION = "{\"discovery-guide-service-a\":\"1.1\", \"discovery-guide-service-b\":\"1.0\"}";
    private static final String DEFAULT_A_ROUTE_REGION = "{\"discovery-guide-service-a\":\"dev\", \"discovery-guide-service-b\":\"qa\"}";
    private static final String DEFAULT_B_ROUTE_REGION = "{\"discovery-guide-service-a\":\"qa\", \"discovery-guide-service-b\":\"dev\"}";
    private static final String DEFAULT_A_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3001\", \"discovery-guide-service-b\":\"4002\"}";
    private static final String DEFAULT_B_ROUTE_ADDRESS = "{\"discovery-guide-service-a\":\"3002\", \"discovery-guide-service-b\":\"4001\"}";

    @Value("${a.route.version:" + DEFAULT_A_ROUTE_VERSION + "}")
    private String aRouteVersion;

    @Value("${b.route.version:" + DEFAULT_B_ROUTE_VERSION + "}")
    private String bRouteVersion;

    @Value("${a.route.region:" + DEFAULT_A_ROUTE_REGION + "}")
    private String aRouteRegion;

    @Value("${b.route.region:" + DEFAULT_B_ROUTE_REGION + "}")
    private String bRouteRegion;

    @Value("${a.route.address:" + DEFAULT_A_ROUTE_ADDRESS + "}")
    private String aRouteAddress;

    @Value("${b.route.address:" + DEFAULT_B_ROUTE_ADDRESS + "}")
    private String bRouteAddress;

    // Header
    @Override
    public String getRouteVersion() {
        String user = strategyContextHolder.getHeader("user");

        LOG.info("Header, Header user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteVersion);

            return aRouteVersion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteVersion);

            return bRouteVersion;
        }

        return super.getRouteVersion();
    }

    // Parameter
    @Override
    public String getRouteRegion() {
        String user = strategyContextHolder.getParameter("user");

        LOG.info("Parameter, Parameter user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("={}", aRouteRegion);

            return aRouteRegion;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("={}", bRouteRegion);

            return bRouteRegion;
        }

        return super.getRouteRegion();
    }

    // CookieIP
    @Override
    public String getRouteAddress() {
        String user = strategyContextHolder.getCookie("user");

        LOG.info("CookieIP, Cookie user={}", user);

        if (StringUtils.equals(user, "zhangsan")) {
            LOG.info("IP={}", aRouteAddress);

            return aRouteAddress;
        } else if (StringUtils.equals(user, "lisi")) {
            LOG.info("IP={}", bRouteAddress);

            return bRouteAddress;
        }

        return super.getRouteEnvironment();
    }

    @Autowired
    private ServiceStrategyContextHolder serviceStrategyContextHolder;

    // 
    @Override
    public String getRouteEnvironment() {
        String requestURL = serviceStrategyContextHolder.getRequestURL();
        if (requestURL.contains("nepxion.com")) {
            LOG.info(", URL={}", requestURL);

            String host = requestURL.substring("http://".length(), requestURL.length());
            String environment = host.substring(0, host.indexOf("."));

            LOG.info("={}", environment);

            return environment;
        }

        return super.getRouteEnvironment();
    }

    // 
    /*@Override
    public String getRouteVersion() {
        LOG.info("");

        List<Pair<String, Integer>> weightList = new ArrayList<Pair<String, Integer>>();
        weightList.add(new ImmutablePair<String, Integer>(aRouteVersion, 30));
        weightList.add(new ImmutablePair<String, Integer>(bRouteVersion, 70));
        MapWeightRandom<String, Integer> weightRandom = new MapWeightRandom<String, Integer>(weightList);

        return weightRandom.random();
    }*/
}

@Bean

@Bean
public ServiceStrategyRouteFilter serviceStrategyRouteFilter() {
    return new MyServiceStrategyRouteFilter();
}

Spring Cloud 202x

Spring Cloud 202xRibbonapply(Server server)com.netflix.loadbalancer.Serverorg.springframework.cloud.client.ServiceInstance

ZuulSpring Cloud [email protected]

// ++IP+
public class MyDiscoveryEnabledStrategy extends DefaultDiscoveryEnabledStrategy {
    private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledStrategy.class);

    // RESTHeadermobile
    @Override
    public boolean apply(Server server) {
        String mobile = strategyContextHolder.getHeader("mobile");
        String serviceId = pluginAdapter.getServerServiceId(server);
        String version = pluginAdapter.getServerVersion(server);
        String region = pluginAdapter.getServerRegion(server);
        String environment = pluginAdapter.getServerEnvironment(server);
        String address = server.getHost() + ":" + server.getPort();

        LOG.info("mobile={}, serviceId={}, version={}, region={}, env={}, address={}", mobile, serviceId, version, region, environment, address);

        if (StringUtils.isNotEmpty(mobile)) {
            // 1381.0
            if (mobile.startsWith("138") && StringUtils.equals(version, "1.0")) {
                return true;
                // 1332.0
            } else if (mobile.startsWith("133") && StringUtils.equals(version, "1.1")) {
                return true;
            } else {
                // 
                return false;
            }
        }

        return true;
    }
}

@Bean

@Bean
public DiscoveryEnabledStrategy discoveryEnabledStrategy() {
    return new MyDiscoveryEnabledStrategy();
}

RestRpc

// ++IP+
public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
    private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledStrategy.class);

    @Autowired
    private PluginAdapter pluginAdapter;

    @Autowired
    private ServiceStrategyContextHolder serviceStrategyContextHolder;

    @Override
    public boolean apply(Server server) {
        boolean enabled = applyFromHeader(server);
        if (!enabled) {
            return false;
        }

        return applyFromMethod(server);
    }

    // RESTHeadermobile
    private boolean applyFromHeader(Server server) {
        String mobile = serviceStrategyContextHolder.getHeader("mobile");
        String serviceId = pluginAdapter.getServerServiceId(server);
        String version = pluginAdapter.getServerVersion(server);
        String region = pluginAdapter.getServerRegion(server);
        String environment = pluginAdapter.getServerEnvironment(server);
        String address = server.getHost() + ":" + server.getPort();

        LOG.info("mobile={}, serviceId={}, version={}, region={}, env={}, address={}", mobile, serviceId, version, region, environment, address);

        if (StringUtils.isNotEmpty(mobile)) {
            // 1381.0
            if (mobile.startsWith("138") && StringUtils.equals(version, "1.0")) {
                return true;
                // 1332.0
            } else if (mobile.startsWith("133") && StringUtils.equals(version, "1.1")) {
                return true;
            } else {
                // 
                return false;
            }
        }

        return true;
    }

    // RPC
    // discovery-guide-service-a
    @SuppressWarnings("unchecked")
    private boolean applyFromMethod(Server server) {
        Map<String, Object> attributes = serviceStrategyContextHolder.getRpcAttributes();
        String serviceId = pluginAdapter.getServerServiceId(server);
        String version = pluginAdapter.getServerVersion(server);
        String region = pluginAdapter.getServerRegion(server);
        String environment = pluginAdapter.getServerEnvironment(server);
        String address = server.getHost() + ":" + server.getPort();

        LOG.info("attributes={}, serviceId={}, version={}, region={}, env={}, address={}", attributes, serviceId, version, region, environment, address);

        if (attributes.containsKey(DiscoveryConstant.PARAMETER_MAP)) {
            Map<String, Object> parameterMap = (Map<String, Object>) attributes.get(DiscoveryConstant.PARAMETER_MAP);
            String value = parameterMap.get("value").toString();
            if (StringUtils.isNotEmpty(value)) {
                // devdev
                if (value.contains("dev") && StringUtils.equals(region, "dev")) {
                    return true;
                    // qaqa
                } else if (value.contains("qa") && StringUtils.equals(region, "qa")) {
                    return true;
                } else {
                    // 
                    return true;
                }
            }
        }

        return true;
    }
}
# RPCfalse
spring.application.strategy.rpc.intercept.enabled=true

Open API

Nacos

spring.cloud.nacos.discovery.metadata.version=stable
spring.cloud.nacos.discovery.metadata.version=gray
<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version>gray</version>
    </strategy>
</rule>

ab

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

Header

n-d-version=gray
n-d-version={"discovery-guide-service-a":"gray", "discovery-guide-service-b":"stable"}

grayOpen APIstable

  • Nacos Open API
curl -X PUT 'http://ip:port/nacos/v1/ns/instance?serviceName={appId}&ip={ip}&port={port}&metadata={"version", "stable"}'

Nacos Open APIhttps://nacos.io/zh-cn/docs/open-api.html

  • Eureka Open API
curl -X PUT 'http://ip:port/eureka/apps/{appId}/{instanceId}/metadata?version=stable'
  • Consul Open API

  • Zookeeper Open API

Open API

Discovery Platform WIKI

admin/adminnepxion/nepxionbootstrap.propertiesAuthenticationResource

  • | | |

  • a==1
  • a==1&&b==2

a=1:falsea=1;b=2:true

  • discovery-guide-service-a=1.1=1.0=1.0
  • discovery-guide-service-b=1.1=1.0=1.0

Header

Nacos

Nacosrule.xml

95%5%

HeaderParameterCookie2

  • Headera=1

  • Parameterb=2

  • discovery-guide-service-a

  • discovery-guide-service-b

  • a==1&&b==2->a1.0->b1.0

n-d-versionHeader

  • discovery-guide-zuul

  • ->a1.1->b1.195%
  • ->a1.0->b1.05%

a

a

discovery-plugin-admin-center-starterLoadBalanced RestTemplateIP

Rest Endpoint

http://[IP:PORT]/[A]/inspector/inspect {"serviceIdList":["B", "C", ...]} POST
http://[AIP:PORT]/inspector/inspect {"serviceIdList":["B", "C", ...]} POST

# false
spring.application.strategy.version.failover.enabled=true

Header

# false
spring.application.strategy.version.prefer.enabled=true

Ribbon

DevOpsOpen API

ID

IDspring.application.uuidID

ID

8-6-3-4-3-3

IDID

Spring Cloud GatewayIDGroupdiscovery-guide-groupData Iddiscovery-guide-gatewaySpring Cloud GatewayID

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <id>20210601-222214-909-1146-372-698</id>
    </strategy-blacklist>
</rule>

IDSpring Cloud GatewayID20210601-222214-909-1146-372-698aID20210601-222623-277-4978-633-279b

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <id>{"discovery-guide-service-a":"20210601-222214-909-1146-372-698", "discovery-guide-service-b":"20210601-222623-277-4978-633-279"}</id>
    </strategy>
</rule>

ID20210601-222214-909-1146-372-69820210601-222623-277-4978-633-279

<id>20210601-222214-909-1146-372-698;20210601-222623-277-4978-633-279</id>

Spring AntPathMatcherSpring Matcher*?

20210601* - 20210601
20210601-222214-909-1146-372-69? - 20210601-222214-909-1146-372-69ID
"discovery-guide-service-b":"20210601*;20210601-222214-909-1146-372-69?"

discovery-guide-service-b2021060120210601-222214-909-1146-372-69ID1

HeaderIP

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

202161ab

<?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>

IP

IPIP+

ZuulIPGroupdiscovery-guide-groupData Iddiscovery-guide-zuulZuulIPIP

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy-blacklist>
        <!-- <address>127.0.0.1:3001</address> -->
        <!-- <address>127.0.0.1</address> -->
        <address>3001</address>
    </strategy-blacklist>
</rule>

IPZuul3001a4001b

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <address>{"discovery-guide-service-a":"3001", "discovery-guide-service-b":"4001"}</address>
    </strategy>
</rule>

30014001

<address>3001;4001</address>
<address>3001</address>
<address>{"discovery-guide-service-a":"3001", "discovery-guide-service-b":"3001"}</address>

Spring AntPathMatcherSpring Matcher*?

* - 
3* - 3
"discovery-guide-service-b":"3*;400?"

discovery-guide-service-b34001

HeaderIP

n-d-address-blacklist=3001
n-d-address-blacklist={"discovery-guide-service-a":"3001", "discovery-guide-service-b":"3001"}

Discovery

DiscoveryAgentDiscoveryDiscoveryAgent

  • Spring Cloud Gateway
  • Zuul
  • Feign
  • RestTemplate
  • WebClient

DiscoveryAgent

DiscoveryAgentDiscoveryDubbo

ThreadLocalThreadLocalThreadLocalDiscoveryAgentJava Agent

Java8ThreadLocal

  • WebFlux Reactor
  • @Async
  • Hystrix Thread Pool Isolation
  • Runnable
  • Callable
  • Single Thread
  • Thread Pool
  • SLF4J MDC

DiscoveryAgent

DiscoveryAgent

discovery-agent-starter-${discovery.version}.jarAgentJVM

agent.config

agent.config

# Base thread scan packages
agent.plugin.thread.scan.packages=reactor.core.publisher;org.springframework.aop.interceptor;com.netflix.hystrix
  • WebFlux Reactorreactor.core.publisher
  • @Asyncorg.springframework.aop.interceptor
  • Hystrixcom.netflix.hystrix

plugin/discovery-agent-starter-plugin-strategy-${discovery.version}.jarNepxion Discovery

plugin/discovery-agent-starter-plugin-mdc-${discovery.version}.jarSLF4J MDC

plugin

DiscoveryAgent

  • -javaagent
-javaagent:C:/opt/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar -Dthread.scan.packages=com.nepxion.discovery.guide.service.feign
  • C:/opt/discovery-agentAgent
  • -Dthread.scan.packagesRunnable/Callable/Thread/ThreadPool

    • ;
    • ;""-Dthread.scan.packages="com.abc;com.xyz"
    • Runnable/Callable/Thread/ThreadPoolthread.scan.packages-javaagent:C:/opt/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar
  • -Dthread.gateway.enabledSpring Cloud GatewayHeader
  • -Dthread.zuul.enabledZuulHeader
  • -Dthread.service.enabledHeader
  • -Dthread.mdc.enabledSLF4J MDC
  • -Dthread.request.decorator.enabledRequestRequestDestoryHeader

DiscoveryAgent

  • ThreadLocal
  • pluginThreadLocalplugin

SDK

  • ThreadLocal
public class MyContext {
    private static final ThreadLocal<MyContext> THREAD_LOCAL = new ThreadLocal<MyContext>() {
        @Override
        protected MyContext initialValue() {
            return new MyContext();
        }
    };

    public static MyContext getCurrentContext() {
        return THREAD_LOCAL.get();
    }

    public static void clearCurrentContext() {
        THREAD_LOCAL.remove();
    }

    private Map<String, String> attributes = new HashMap<>();

    public Map<String, String> getAttributes() {
        return attributes;
    }

    public void setAttributes(Map<String, String> attributes) {
        this.attributes = attributes;
    }
}

Agent

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-agent-starter</artifactId>
    <version>${discovery.agent.version}</version>
    <scope>provided</scope>
</dependency>
  • ThreadLocalHookAbstractThreadLocalHook
public class MyContextHook extends AbstractThreadLocalHook {
    @Override
    public Object create() {
        // ThreadLocal
        return MyContext.getCurrentContext().getAttributes();
    }

    @Override
    public void before(Object object) {
        // createThreadLocal
        if (object instanceof Map) {
            MyContext.getCurrentContext().setAttributes((Map<String, String>) object);
        }
    }

    @Override
    public void after() {
        // 
        MyContext.clearCurrentContext();
    }
}
  • PluginAbstractPlugin
public class MyContextPlugin extends AbstractPlugin {
    private Boolean threadMyPluginEnabled = Boolean.valueOf(System.getProperty("thread.myplugin.enabled", "false"));

    @Override
    protected String getMatcherClassName() {
        // ThreadLocal
        return "com.nepxion.discovery.example.sdk.MyContext";
    }

    @Override
    protected String getHookClassName() {
        // ThreadLocalHook
        return MyContextHook.class.getName();
    }

    @Override
    protected boolean isEnabled() {
        // -Dthread.myplugin.enabled=true/falsePlugintrue
        return threadMyPluginEnabled;
    }
}
  • SPIsrc/main/resources/META-INF/servicesSPI
com.nepxion.discovery.agent.plugin.Plugin

Plugin

com.nepxion.discovery.example.agent.MyContextPlugin
  • Mavendiscovery-agent/plugin

-javaagent:C:/opt/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar -Dthread.scan.packages=com.nepxion.discovery.example.application -Dthread.myplugin.enabled=true

Application

  • MyApplicationThreadLocalMapDiscoveryAgentMap
@SpringBootApplication
@RestController
public class MyApplication {
    private static final Logger LOG = LoggerFactory.getLogger(MyApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);

        invoke();
    }

    public static void invoke() {
        RestTemplate restTemplate = new RestTemplate();

        for (int i = 1; i <= 10; i++) {
            restTemplate.getForEntity("http://localhost:8080/index/" + i, String.class).getBody();
        }
    }

    @GetMapping("/index/{value}")
    public String index(@PathVariable(value = "value") String value) throws InterruptedException {
        Map<String, String> attributes = new HashMap<String, String>();
        attributes.put(value, "MyContext");

        MyContext.getCurrentContext().setAttributes(attributes);

        LOG.info("ThreadLocal{}", MyContext.getCurrentContext().getAttributes());

        new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("ThreadLocal{}", MyContext.getCurrentContext().getAttributes());

                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                LOG.info("Sleep 5ThreadLocal{} ", MyContext.getCurrentContext().getAttributes());
            }
        }).start();

        return "";
    }
}
2020-11-09 00:08:14.330  INFO 16588 --- [nio-8080-exec-1] c.n.d.example.application.MyApplication  : ThreadLocal{1=MyContext}
2020-11-09 00:08:14.381  INFO 16588 --- [       Thread-4] c.n.d.example.application.MyApplication  : ThreadLocal{1=MyContext}
2020-11-09 00:08:14.402  INFO 16588 --- [nio-8080-exec-2] c.n.d.example.application.MyApplication  : ThreadLocal{2=MyContext}
2020-11-09 00:08:14.403  INFO 16588 --- [       Thread-5] c.n.d.example.application.MyApplication  : ThreadLocal{2=MyContext}
2020-11-09 00:08:14.405  INFO 16588 --- [nio-8080-exec-3] c.n.d.example.application.MyApplication  : ThreadLocal{3=MyContext}
2020-11-09 00:08:14.406  INFO 16588 --- [       Thread-6] c.n.d.example.application.MyApplication  : ThreadLocal{3=MyContext}
2020-11-09 00:08:14.414  INFO 16588 --- [nio-8080-exec-4] c.n.d.example.application.MyApplication  : ThreadLocal{4=MyContext}
2020-11-09 00:08:14.414  INFO 16588 --- [       Thread-7] c.n.d.example.application.MyApplication  : ThreadLocal{4=MyContext}
2020-11-09 00:08:14.417  INFO 16588 --- [nio-8080-exec-5] c.n.d.example.application.MyApplication  : ThreadLocal{5=MyContext}
2020-11-09 00:08:14.418  INFO 16588 --- [       Thread-8] c.n.d.example.application.MyApplication  : ThreadLocal{5=MyContext}
2020-11-09 00:08:14.421  INFO 16588 --- [nio-8080-exec-6] c.n.d.example.application.MyApplication  : ThreadLocal{6=MyContext}
2020-11-09 00:08:14.422  INFO 16588 --- [       Thread-9] c.n.d.example.application.MyApplication  : ThreadLocal{6=MyContext}
2020-11-09 00:08:14.424  INFO 16588 --- [nio-8080-exec-7] c.n.d.example.application.MyApplication  : ThreadLocal{7=MyContext}
2020-11-09 00:08:14.425  INFO 16588 --- [      Thread-10] c.n.d.example.application.MyApplication  : ThreadLocal{7=MyContext}
2020-11-09 00:08:14.427  INFO 16588 --- [nio-8080-exec-8] c.n.d.example.application.MyApplication  : ThreadLocal{8=MyContext}
2020-11-09 00:08:14.428  INFO 16588 --- [      Thread-11] c.n.d.example.application.MyApplication  : ThreadLocal{8=MyContext}
2020-11-09 00:08:14.430  INFO 16588 --- [nio-8080-exec-9] c.n.d.example.application.MyApplication  : ThreadLocal{9=MyContext}
2020-11-09 00:08:14.431  INFO 16588 --- [      Thread-12] c.n.d.example.application.MyApplication  : ThreadLocal{9=MyContext}
2020-11-09 00:08:14.433  INFO 16588 --- [io-8080-exec-10] c.n.d.example.application.MyApplication  : ThreadLocal{10=MyContext}
2020-11-09 00:08:14.434  INFO 16588 --- [      Thread-13] c.n.d.example.application.MyApplication  : ThreadLocal{10=MyContext}
2020-11-09 00:08:19.382  INFO 16588 --- [       Thread-4] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{1=MyContext} 
2020-11-09 00:08:19.404  INFO 16588 --- [       Thread-5] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{2=MyContext} 
2020-11-09 00:08:19.406  INFO 16588 --- [       Thread-6] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{3=MyContext} 
2020-11-09 00:08:19.416  INFO 16588 --- [       Thread-7] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{4=MyContext} 
2020-11-09 00:08:19.418  INFO 16588 --- [       Thread-8] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{5=MyContext} 
2020-11-09 00:08:19.422  INFO 16588 --- [       Thread-9] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{6=MyContext} 
2020-11-09 00:08:19.425  INFO 16588 --- [      Thread-10] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{7=MyContext} 
2020-11-09 00:08:19.428  INFO 16588 --- [      Thread-11] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{8=MyContext} 
2020-11-09 00:08:19.432  INFO 16588 --- [      Thread-12] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{9=MyContext} 
2020-11-09 00:08:19.434  INFO 16588 --- [      Thread-13] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{10=MyContext} 

AgentThreadLocal

2020-11-09 00:01:40.133  INFO 16692 --- [nio-8080-exec-1] c.n.d.example.application.MyApplication  : ThreadLocal{1=MyContext}
2020-11-09 00:01:40.135  INFO 16692 --- [       Thread-8] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.158  INFO 16692 --- [nio-8080-exec-2] c.n.d.example.application.MyApplication  : ThreadLocal{2=MyContext}
2020-11-09 00:01:40.159  INFO 16692 --- [       Thread-9] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.162  INFO 16692 --- [nio-8080-exec-3] c.n.d.example.application.MyApplication  : ThreadLocal{3=MyContext}
2020-11-09 00:01:40.163  INFO 16692 --- [      Thread-10] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.170  INFO 16692 --- [nio-8080-exec-5] c.n.d.example.application.MyApplication  : ThreadLocal{4=MyContext}
2020-11-09 00:01:40.170  INFO 16692 --- [      Thread-11] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.173  INFO 16692 --- [nio-8080-exec-4] c.n.d.example.application.MyApplication  : ThreadLocal{5=MyContext}
2020-11-09 00:01:40.174  INFO 16692 --- [      Thread-12] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.176  INFO 16692 --- [nio-8080-exec-6] c.n.d.example.application.MyApplication  : ThreadLocal{6=MyContext}
2020-11-09 00:01:40.177  INFO 16692 --- [      Thread-13] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.179  INFO 16692 --- [nio-8080-exec-8] c.n.d.example.application.MyApplication  : ThreadLocal{7=MyContext}
2020-11-09 00:01:40.180  INFO 16692 --- [      Thread-14] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.182  INFO 16692 --- [nio-8080-exec-7] c.n.d.example.application.MyApplication  : ThreadLocal{8=MyContext}
2020-11-09 00:01:40.182  INFO 16692 --- [      Thread-15] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.185  INFO 16692 --- [nio-8080-exec-9] c.n.d.example.application.MyApplication  : ThreadLocal{9=MyContext}
2020-11-09 00:01:40.186  INFO 16692 --- [      Thread-16] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:40.188  INFO 16692 --- [io-8080-exec-10] c.n.d.example.application.MyApplication  : ThreadLocal{10=MyContext}
2020-11-09 00:01:40.189  INFO 16692 --- [      Thread-17] c.n.d.example.application.MyApplication  : ThreadLocal{}
2020-11-09 00:01:45.136  INFO 16692 --- [       Thread-8] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.160  INFO 16692 --- [       Thread-9] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.163  INFO 16692 --- [      Thread-10] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.171  INFO 16692 --- [      Thread-11] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.174  INFO 16692 --- [      Thread-12] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.177  INFO 16692 --- [      Thread-13] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.181  INFO 16692 --- [      Thread-14] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.183  INFO 16692 --- [      Thread-15] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.187  INFO 16692 --- [      Thread-16] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 
2020-11-09 00:01:45.190  INFO 16692 --- [      Thread-17] c.n.d.example.application.MyApplication  : Sleep 5ThreadLocal{} 

https://github.com/Nepxion/DiscoveryAgent/tree/master/discovery-agent-exampleThreadLocal

Hystrix

HeaderSpanHystrixHeader

Pom

<!-- Hystrix -->
<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-hystrix</artifactId>
    <version>${discovery.version}</version>
</dependency>
# Hystrixspring.application.strategy.hystrix.threadlocal.supportedtruediscovery-plugin-strategy-starter-hystrixThreadLocalfalse
spring.application.strategy.hystrix.threadlocal.supported=true

DiscoveryAgent

DataSource

Queue

Groupdiscovery-guide-groupData Iddiscovery-guide-group

a1.0db1a1.1db2

bdevqueue1bqaqueue2

cenv1db1cenv2db2

dzone1queue1dzone2queue2

cIP192.168.43.101:1201db1cIP192.168.43.102:1201db2

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <parameter>
        <service service-name="discovery-guide-service-a" tag-key="version" tag-value="1.0" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-guide-service-a" tag-key="version" tag-value="1.1" key="ShardingSphere" value="db2"/>
        <service service-name="discovery-guide-service-b" tag-key="region" tag-value="dev" key="RocketMQ" value="queue1"/>
        <service service-name="discovery-guide-service-b" tag-key="region" tag-value="qa" key="RocketMQ" value="queue2"/>
        <service service-name="discovery-guide-service-c" tag-key="env" tag-value="env1" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-guide-service-c" tag-key="env" tag-value="env2" key="ShardingSphere" value="db2"/>
        <service service-name="discovery-guide-service-d" tag-key="zone" tag-value="zone1" key="RocketMQ" value="queue1"/>
        <service service-name="discovery-guide-service-d" tag-key="zone" tag-value="zone2" key="RocketMQ" value="queue2"/>
        <service service-name="discovery-guide-service-e" tag-key="address" tag-value="192.168.43.101:1201" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-guide-service-e" tag-key="address" tag-value="192.168.43.102:1201" key="ShardingSphere" value="db2"/>
    </parameter>
</rule>
@EventBus
public class MySubscriber {
    @Autowired
    private PluginAdapter pluginAdapter;

    @Subscribe
    public void onParameterChanged(ParameterChangedEvent parameterChangedEvent) {
        ParameterEntity parameterEntity = parameterChangedEvent.getParameterEntity();
        String serviceId = pluginAdapter.getServiceId();
        List<ParameterServiceEntity> parameterServiceEntityList = null;
        if (parameterEntity != null) {
            Map<String, List<ParameterServiceEntity>> parameterServiceMap = parameterEntity.getParameterServiceMap();
            parameterServiceEntityList = parameterServiceMap.get(serviceId);
        }
        // parameterServiceEntityList
    }
}
# true
spring.application.parameter.event.onstart.enabled=true

https://awesomeopensource.com/project/Nepxion/DiscoveryContrib

  • Rest Endpoint

  • Rest Endpoint

  • NacosApolloConsulEtcdRedisZookeeper

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

  • argsPathStripPrefixargs_genkey_"_genkey_0": "/discovery-guide-service-a/**"
  • argsHeaderCookieQueryargsSpring Cloud GatewayHeaderKVheader -> regexpCookieKVname->regexpQueryKVparam->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

  • Listargslist."whiteList.0": "* swagger-ui.html"
  • Map<String, String>argsmap.mapkey"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-GatewayRest-Endpoint

Spring Cloud GatewayRest 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
    • NacosRedisZookeeperGroup{group}DataId{serviceId}-dynamic-route
    • ApolloConsulEtcdKey{group}-{serviceId}-dynamic-route
    • {group}group
  • ValueSpring-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
    }
]

ZuulRest-Endpoint

ZuulRest 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
    • NacosRedisZookeeperGroup{group}DataId{serviceId}-dynamic-route
    • ApolloConsulEtcdKey{group}-{serviceId}-dynamic-route
    • {group}group
  • ValueZuul

# 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());
    }
}

NacosApolloConsulEtcdRedisZookeeper

Spring [email protected] Cloud GatewayZuul

NacosGroupDataIdNacos

// extends
// 1. NacosProcessor
// 2. ApolloProcessor
// 3. ConsulProcessor
// 4. EtcdProcessor
// 5. ZookeeperProcessor
// 6. RedisProcessor
// GroupDataId
// 1. NacosRedisZookeeperGroupDataId
// 2. ApolloConsulEtcdKeyGroup-DataId
// [email protected]
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 DiscoverySpring 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.x6.x.x-config

  • application.propertiesapplication.yamlspring.application.name
  • XMLJson
  • NacosApolloRedisKey

XMLJsondiscovery-plugin-frameworkdiscovery-plugin-config-centerdiscovery-plugin-admin-center

XMLJsondiscovery-springcloud-example-servicerule.json

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <!-- blacklist -->
    <register>
        <!-- /IPIP -->
        <!-- filter-typeblacklist/whitelist -->
        <!-- service-name -->
        <!-- filter-value/IPIP; -->
        <!-- 10.1011.11IP -->
        <blacklist filter-value="10.10;11.11">
            <!-- 172.1610.1011.11IP -->
            <service service-name="discovery-springcloud-example-a" filter-value="172.16"/>
        </blacklist>

        <!-- <whitelist filter-value="">
            <service service-name="" filter-value=""/>
        </whitelist>  -->

        <!--  -->
        <!-- service-name -->
        <!-- filter-value -->
        <!-- 10000 -->
        <count filter-value="10000">
            <!-- 500010000 -->
            <service service-name="discovery-springcloud-example-a" filter-value="5000"/>
        </count>
    </register>

    <discovery>
        <!-- // -->
        <!-- 10.1011.11IP -->
        <blacklist filter-value="10.10;11.11">
            <!-- 172.1610.1011.11IP -->
            <service service-name="discovery-springcloud-example-b" filter-value="172.16"/>
        </blacklist>

        <!--  -->
        <!-- service-name -->
        <!-- version-value; -->
        <!--  -->
        <!-- 1.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-version-value="1.0" provider-version-value="1.0;1.1"/> 1.01.01.1 -->
        <!-- 2.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" provider-version-value="1.0;1.1"/> 1.01.1 -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-version-value="1.0"/> 1.0 -->
        <!--    <service consumer-service-name="a" provider-service-name="b"/>  -->
        <!-- 3.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-version-value="" provider-version-value="1.0;1.1"/> 1.01.1 -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-version-value="1.0" provider-version-value=""/> 1.0 -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-version-value="" provider-version-value=""/>  -->
        <!-- 4.  -->
        <!--  -->
        <!-- 1. application.properties -->
        <!-- 2. application.propertiesxml -->
        <version>
            <!-- g1.0a1.0 -->
            <service consumer-service-name="discovery-springcloud-example-gateway" provider-service-name="discovery-springcloud-example-a" consumer-version-value="1.0" provider-version-value="1.0"/>
            <!-- g1.1a1.1 -->
            <service consumer-service-name="discovery-springcloud-example-gateway" provider-service-name="discovery-springcloud-example-a" consumer-version-value="1.1" provider-version-value="1.1"/>
            <!-- z1.0a1.0 -->
            <service consumer-service-name="discovery-springcloud-example-zuul" provider-service-name="discovery-springcloud-example-a" consumer-version-value="1.0" provider-version-value="1.0"/>
            <!-- z1.1a1.1 -->
            <service consumer-service-name="discovery-springcloud-example-zuul" provider-service-name="discovery-springcloud-example-a" consumer-version-value="1.1" provider-version-value="1.1"/>
            <!-- a1.0b1.0 -->
            <service consumer-service-name="discovery-springcloud-example-a" provider-service-name="discovery-springcloud-example-b" consumer-version-value="1.0" provider-version-value="1.0"/>
            <!-- a1.1b1.1 -->
            <service consumer-service-name="discovery-springcloud-example-a" provider-service-name="discovery-springcloud-example-b" consumer-version-value="1.1" provider-version-value="1.1"/>
            <!-- b1.0c1.01.1 -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" consumer-version-value="1.0" provider-version-value="1.0;1.1"/>
            <!-- b1.1c1.2 -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" consumer-version-value="1.1" provider-version-value="1.2"/>
        </version>

        <!--  -->
        <!-- service-name -->
        <!-- region-value; -->
        <!--  -->
        <!-- 1.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-region-value="dev" provider-region-value="dev"/> devdev -->
        <!-- 2.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" provider-region-value="dev;qa"/> devqa -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-region-value="dev"/> dev -->
        <!--    <service consumer-service-name="a" provider-service-name="b"/>  -->
        <!-- 3.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-region-value="" provider-region-value="dev;qa"/> devqa -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-region-value="dev" provider-region-value=""/> dev -->
        <!--    <service consumer-service-name="a" provider-service-name="b" consumer-region-value="" provider-region-value=""/>  -->
        <!-- 4.  -->
        <!--  -->
        <!-- 1. application.properties -->
        <!-- 2. application.propertiesxml -->
        <region>
            <!-- devadevb -->
            <service consumer-service-name="discovery-springcloud-example-a" provider-service-name="discovery-springcloud-example-b" consumer-region-value="dev" provider-region-value="dev"/>
            <!-- qaaqab -->
            <service consumer-service-name="discovery-springcloud-example-a" provider-service-name="discovery-springcloud-example-b" consumer-region-value="qa" provider-region-value="qa"/>
            <!-- devbdevc -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" consumer-region-value="dev" provider-region-value="dev"/>
            <!-- qabqac -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" consumer-region-value="qa" provider-region-value="qa"/>
        </region>

        <!--  -->
        <!-- service-name -->
        <!-- weight-value"/="; -->
        <!--  -->
        <!-- 1.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" provider-weight-value="1.0=90;1.1=10"/> 1.090%1.110% -->
        <!--    <service provider-service-name="b" provider-weight-value="1.0=90;1.1=10"/> 1.090%1.110% -->
        <!-- 2. consumer-service-nameconsumer-service-name -->
        <!-- 3.  -->
        <!--  -->
        <!-- 1.  -->
        <!--    <version provider-weight-value="1.0=85;1.1=15"/> 1.085%1.115% -->
        <!-- 2.  -->
        <!-- 3.  -->

        <!--  -->
        <!-- 1.  -->
        <!--    <service consumer-service-name="a" provider-service-name="b" provider-weight-value="dev=85;qa=15"/> dev85%qa15% -->
        <!--    <service provider-service-name="b" provider-weight-value="dev=85;qa=15"/> dev85%qa15% -->
        <!-- 2. consumer-service-nameconsumer-service-name -->
        <!-- 3.  -->
        <!--  -->
        <!-- 1.  -->
        <!--    <region provider-weight-value="dev=85;qa=15"/> dev85%qa15% -->
        <!-- 2.  -->
        <!-- 3.  -->
        <weight>
            <!--  -->
            <!-- bcc1.090%1.110% -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" provider-weight-value="1.0=90;1.1=10" type="version"/>
            <!-- cc1.090%1.110% -->
            <service provider-service-name="discovery-springcloud-example-c" provider-weight-value="1.0=90;1.1=10" type="version"/>
            <!-- 1.090%1.110% -->
            <version provider-weight-value="1.0=90;1.1=10"/>

            <!-- bccdev85%qa15% -->
            <service consumer-service-name="discovery-springcloud-example-b" provider-service-name="discovery-springcloud-example-c" provider-weight-value="dev=85;qa=15" type="region"/>
            <!-- ccdev85%qa15% -->
            <service provider-service-name="discovery-springcloud-example-c" provider-weight-value="dev=85;qa=15" type="region"/>
            <!-- dev85%qa15% -->
            <region provider-weight-value="dev=85;qa=15"/>
        </weight>
    </discovery>

    <!-- Http Header -->
    <strategy>
        <!--  -->
        <version>{"discovery-springcloud-example-a":"1.0", "discovery-springcloud-example-b":"1.0", "discovery-springcloud-example-c":"1.0;1.2"}</version>
        <!-- <version>1.0</version> -->
        <!--  -->
        <region>{"discovery-springcloud-example-a":"qa;dev", "discovery-springcloud-example-b":"dev", "discovery-springcloud-example-c":"qa"}</region>
        <!-- <region>dev</region> -->
        <!-- IP -->
        <address>{"discovery-springcloud-example-a":"192.168.43.101:1100", "discovery-springcloud-example-b":"192.168.43.101:1201", "discovery-springcloud-example-c":"192.168.43.101:1300"}</address>
        <!--  -->
        <!--  -->
        <version-weight>{"discovery-springcloud-example-a":"1.0=90;1.1=10", "discovery-springcloud-example-b":"1.0=90;1.1=10", "discovery-springcloud-example-c":"1.0=90;1.1=10"}</version-weight>
        <!-- <version-weight>1.0=90;1.1=10</version-weight> -->
        <!--  -->
        <region-weight>{"discovery-springcloud-example-a":"dev=85;qa=15", "discovery-springcloud-example-b":"dev=85;qa=15", "discovery-springcloud-example-c":"dev=85;qa=15"}</region-weight>
        <!-- <region-weight>dev=85;qa=15</region-weight> -->
    </strategy>

    <!-- Http Header -->
    <strategy-release>
        <!-- SpelXML-->
        <!--  &  &amp;  -->
        <!--  <  &lt;  -->
        <!--  "  &quot;  -->
        <!--  >  &gt; -->
        <!--  '  &apos; -->

        <!-- IP -->
        <!-- ExpressionExpressionExpressionExpression -->
        <conditions type="blue-green">
            <condition id="1" expression="#H['a'] == '1' and #H['b'] == '2'" version-id="a-1" region-id="b-1" address-id="c-1" version-weight-id="d-1" region-weight-id="e-1"/>
            <condition id="2" expression="#H['c'] == '3'" version-id="a-2" region-id="b-2" address-id="c-2" version-weight-id="d-2" region-weight-id="e-2"/>
            <condition id="3" version-id="a-2" region-id="b-2" address-id="c-2" version-weight-id="d-2" region-weight-id="e-2"/>
        </conditions>

        <!-- IP -->
        <!-- ExpressionExpressionExpressionExpression -->
        <conditions type="gray">
            <condition id="1" expression="#H['a'] == '1' and #H['b'] == '2'" version-id="a-1=10;a-2=90" region-id="b-1=20;b-2=80" address-id="c-1=30;c-2=70"/>
            <condition id="2" expression="#H['c'] == '3'" version-id="a-1=90;a-2=10" region-id="b-1=80;b-2=20" address-id="c-1=70;c-2=30"/>
            <condition id="3" version-id="a-1=5;a-2=95" region-id="b-1=5;b-2=95" address-id="c-1=5;c-2=95"/>
        </conditions>

        <routes>
            <route id="a-1" type="version">{"discovery-springcloud-example-a":"1.0", "discovery-springcloud-example-b":"1.0", "discovery-springcloud-example-c":"1.0;1.2"}</route>
            <route id="a-2" type="version">{"discovery-springcloud-example-a":"1.1", "discovery-springcloud-example-b":"1.1", "discovery-springcloud-example-c":"1.2"}</route>
            <route id="b-1" type="region">{"discovery-springcloud-example-a":"qa;dev", "discovery-springcloud-example-b":"dev", "discovery-springcloud-example-c":"qa"}</route>
            <route id="b-2" type="region">{"discovery-springcloud-example-a":"qa", "discovery-springcloud-example-b":"qa", "discovery-springcloud-example-c":"qa"}</route>
            <route id="c-1" type="address">{"discovery-springcloud-example-a":"192.168.43.101:1100", "discovery-springcloud-example-b":"192.168.43.101:1201", "discovery-springcloud-example-c":"192.168.43.101:1300"}</route>
            <route id="c-2" type="address">{"discovery-springcloud-example-a":"192.168.43.101:1101", "discovery-springcloud-example-b":"192.168.43.101:1201", "discovery-springcloud-example-c":"192.168.43.101:1301"}</route>
            <route id="d-1" type="version-weight">{"discovery-springcloud-example-a":"1.0=90;1.1=10", "discovery-springcloud-example-b":"1.0=90;1.1=10", "discovery-springcloud-example-c":"1.0=90;1.1=10"}</route>
            <route id="d-2" type="version-weight">{"discovery-springcloud-example-a":"1.0=10;1.1=90", "discovery-springcloud-example-b":"1.0=10;1.1=90", "discovery-springcloud-example-c":"1.0=10;1.1=90"}</route>
            <route id="e-1" type="region-weight">{"discovery-springcloud-example-a":"dev=85;qa=15", "discovery-springcloud-example-b":"dev=85;qa=15", "discovery-springcloud-example-c":"dev=85;qa=15"}</route>
            <route id="e-2" type="region-weight">{"discovery-springcloud-example-a":"dev=15;qa=85", "discovery-springcloud-example-b":"dev=15;qa=85", "discovery-springcloud-example-c":"dev=15;qa=85"}</route>
        </routes>

        <!-- HeaderHeader -->
        <header>{"a":"1", "b":"2", "c":"3"}</header>
    </strategy-release>

    <!-- -->
    <strategy-blacklist>
        <!-- IDIDspring.application.uuid -->
        <id>{"discovery-springcloud-example-a":"20210601-222214-909-1146-372-698", "discovery-springcloud-example-b":"20210601-222623-277-4978-633-279", "discovery-springcloud-example-c":"20210601-222728-133-2597-222-609"}</id>
        <!-- IPIP+ -->
        <address>{"discovery-springcloud-example-a":"192.168.43.101:1100", "discovery-springcloud-example-b":"192.168.43.101:1201", "discovery-springcloud-example-c":"192.168.43.101:1300"}</address>        
    </strategy-blacklist>

    <!--  -->
    <parameter>
        <!-- a1.0db1a1.1db2 -->
        <!-- bdevqueue1bdevqueue2 -->
        <!-- cenv1db1cenv2db2 -->
        <!-- dzone1queue1dzone2queue2 -->
        <!-- cIP192.168.43.101:1201db1cIP192.168.43.102:1201db2 -->
        <service service-name="discovery-springcloud-example-a" tag-key="version" tag-value="1.0" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-springcloud-example-a" tag-key="version" tag-value="1.1" key="ShardingSphere" value="db2"/>
        <service service-name="discovery-springcloud-example-b" tag-key="region" tag-value="dev" key="RocketMQ" value="queue1"/>
        <service service-name="discovery-springcloud-example-b" tag-key="region" tag-value="qa" key="RocketMQ" value="queue2"/>
        <service service-name="discovery-springcloud-example-c" tag-key="env" tag-value="env1" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-springcloud-example-c" tag-key="env" tag-value="env2" key="ShardingSphere" value="db2"/>
        <service service-name="discovery-springcloud-example-d" tag-key="zone" tag-value="zone1" key="RocketMQ" value="queue1"/>
        <service service-name="discovery-springcloud-example-d" tag-key="zone" tag-value="zone2" key="RocketMQ" value="queue2"/>
        <service service-name="discovery-springcloud-example-e" tag-key="address" tag-value="192.168.43.101:1201" key="ShardingSphere" value="db1"/>
        <service service-name="discovery-springcloud-example-e" tag-key="address" tag-value="192.168.43.102:1201" key="ShardingSphere" value="db2"/>
    </parameter>
</rule>

Apollo

Apollohttps://awesomeopensource.com/project/ctripcorp/apolloApollo

  • AppIdapp.id

  • Namespaceapollo.plugin.namespaceapplication

    • eureka.instance.metadataMap.groupspring.application.namegroup+serviceIdKeygroup-serviceIdValueXmlJsongroupeureka.instance.metadataMap.groupserviceIdspring.application.name
    • eureka.instance.metadataMap.groupspring.application.namegroupKeygroup-groupValueXmlJsongroupeureka.instance.metadataMap.group
  • evn, clusterApollo

  • ApolloprivateApollopublic

  • namespacenamespaceapollo.bootstrap.namespacesapollo.plugin.namespacenamespaceapplication

  • namespacenamespaceapollo.plugin.namespacenamespace

Nacos

Redis

Consul

Etcd

Zookeeper

SwaggerRest

Swagger

  • SwaggerSwaggerConfigurationSwaggerConfiguration
swagger.service.scan.group=your-scan-group
swagger.service.scan.packages=your-scan-packages
  • Docket
swagger.service.base.group=your-base-group
  • Swagger
# Swaggertrue
swagger.service.enabled=true
# SwaggerDocket
swagger.service.base.group=Nepxion Discovery
# SwaggerDocket
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 HeaderSwagger
@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());
    }
}

SwaggerAutoConfigurationsrc/main/resources/META-INF/spring.factories

MetadataenvHeaderHeadern-d-envMetadata

env

spring.cloud.nacos.discovery.metadata.env=env1

envcommon

# defaultcommon
spring.application.strategy.environment.route=common

  • CommonMetadataenvCommon
  • Common
  • Headern-d-envSpring Cloud Ribbon

Metadatazone

spring.cloud.nacos.discovery.metadata.zone=zone
# Metadatazonefalse
spring.application.strategy.zone.affinity.enabled=false

# true
spring.application.strategy.zone.route.enabled=true

  • zone
  • EurekaRibbonEureka Client

GroupIDGroup

GroupGroup

# Groupfalse
spring.application.strategy.consumer.isolation.enabled=true

discovery-guide-service-bGroupPostmandiscovery-guide-service-adiscovery-guide-service-bdiscovery-guide-service-a

Header

GroupIDGroup

GroupGroupHeadern-d-service-group

# Groupfalse
spring.application.strategy.provider.isolation.enabled=true

# RestControllerRPC
spring.application.strategy.scan.packages=com.nepxion.discovery.guide.service.feign

Postmanhttp://localhost:4001/invoke/abcdiscovery-guide-service-bdiscovery-guide-service-b

Reject to invoke because of isolation with different service group

n-d-service-group=discovery-guide-groupHeaderGroup

IP

IP/IPIP

  • IP

IP

IPIP

  • AbstractRegisterListener
  • AbstractDiscoveryListenerConsulservicemanagement
  • AbstractLoadBalanceListener

Sentinel

Sentinel

Spring Cloud Alibaba SentinelSpring Cloud Alibaba Sentinel

Sentinel

  • Key
    • NacosRedisZookeeperGroup{group}DataId{serviceId}-{}
    • ApolloConsulEtcdKey{group}-{serviceId}-{}
    • {group}group
  • ValueJson
# Sentinelfalse
spring.application.strategy.sentinel.datasource.enabled=true

Sentinel

@SentinelResourcevaluesentinel-resourceblockHandlerfallback

@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

SentinelSentinel

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-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-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-degrade

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

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authority

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

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-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-bGroupdiscovery-guide-groupData Iddiscovery-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 LimitAppfalse
spring.application.strategy.sentinel.limit.app.enabled=true

Sentinel Request Origin KeyHeaderlimitApp

n-d-service-id

spring.application.strategy.sentinel.request.origin.key=n-d-service-id

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authoritydiscovery-guide-service-adiscovery-guide-service-b

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

Sentinel Request Origin KeyHeaderlimitApp

spring.application.strategy.sentinel.request.origin.key=n-d-service-group

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authoritymy-groupdiscovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "my-group",
        "strategy": 0
    }
]

Sentinel Request Origin KeyHeaderlimitApp

spring.application.strategy.sentinel.request.origin.key=n-d-service-version

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authority1.0discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0",
        "strategy": 0
    }
]

Sentinel Request Origin KeyHeaderlimitApp

spring.application.strategy.sentinel.request.origin.key=n-d-service-region

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authoritydevdiscovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "dev",
        "strategy": 0
    }
]

Sentinel Request Origin KeyHeaderlimitApp

spring.application.strategy.sentinel.request.origin.key=n-d-service-env

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authorityenv1discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "env1",
        "strategy": 0
    }
]

Sentinel Request Origin KeyHeaderlimitApp

spring.application.strategy.sentinel.request.origin.key=n-d-service-zone

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authorityzone1discovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "zone1",
        "strategy": 0
    }
]

IP

Sentinel Request Origin KeyIPHeaderlimitAppIP

spring.application.strategy.sentinel.request.origin.key=n-d-service-address

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authority192.168.0.88:8081192.168.0.88:8082discovery-guide-service-b

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

HeaderParameterCookie

// +
public class MySentinelStrategyRequestOriginAdapter extends DefaultSentinelStrategyRequestOriginAdapter {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String version = request.getHeader(DiscoveryConstant.N_D_SERVICE_VERSION);
        String location = request.getHeader("location");

        return version + "&" + location;
    }
}

@Bean

@Bean
public SentinelStrategyRequestOriginAdapter sentinelStrategyRequestOriginAdapter() {
    return new MySentinelStrategyRequestOriginAdapter();
}

discovery-guide-service-bGroupdiscovery-guide-groupData Iddiscovery-guide-service-b-sentinel-authority1.0Headerlocation=shanghaidiscovery-guide-service-b

[
    {
        "resource": "sentinel-resource",
        "limitApp": "1.0&shanghai",
        "strategy": 0
    }
]
  • Headerlocation=shanghaiAPIdiscovery-guide-service-a1.0discovery-guide-service-b

  • Headerlocation=beijingdiscovery-guide-service-b

  • Headerlocation=shanghaiAPIdiscovery-guide-service-a1.1discovery-guide-service-bversion=1.0discovery-guide-service-b

Sentinel-Rest-Endpoint

Rest Endpoint

http://[IP:PORT]/sentinel-core/update-flow-rules POST
http://[IP:PORT]/sentinel-core/clear-flow-rules POST
http://[IP:PORT]/sentinel-core/view-flow-rules GET
http://[IP:PORT]/sentinel-core/update-degrade-rules POST
http://[IP:PORT]/sentinel-core/clear-degrade-rules POST
http://[IP:PORT]/sentinel-core/view-degrade-rules GET
http://[IP:PORT]/sentinel-core/update-authority-rules POST
http://[IP:PORT]/sentinel-core/clear-authority-rules POST
http://[IP:PORT]/sentinel-core/view-authority-rules GET
http://[IP:PORT]/sentinel-core/update-system-rules POST
http://[IP:PORT]/sentinel-core/clear-system-rules POST
http://[IP:PORT]/sentinel-core/view-system-rules GET
http://[IP:PORT]/sentinel-param/update-param-flow-rules POST
http://[IP:PORT]/sentinel-param/clear-param-flow-rules POST
http://[IP:PORT]/sentinel-param/view-param-flow-rules GET

Rest Endpoint

http://[IP:PORT]/sentinel/update/{ruleType}/{serviceId} POST
http://[IP:PORT]/sentinel/clear/{ruleType}/{serviceId} POST
http://[IP:PORT]/sentinel/view/{ruleType}/{serviceId} GET

ruleType flow | degrade | authority | system | param-flow

n-d-service-group - 
n-d-service-type -  |  |  | 
n-d-service-id - ID
n-d-service-address - HostPort
n-d-service-version - 
n-d-service-region - 
n-d-service-env - 
n-d-version - 
n-d-region - 
n-d-env - 
n-d-address - 
n-d-version-weight - 
n-d-region-weight - 
n-d-id-blacklist - ID
n-d-address-blacklist - IP
  • n-d-service

  • n-d-

  • traceIdspanId

  • mobileuser

  • OpenTracing + Jaeger

  • OpenTracing + SkyWalking

Debug

DebugSystem.out.printlnIDE

Debug

# false
spring.application.strategy.monitor.enabled=true
# HeaderDebugfalse
spring.application.strategy.rest.intercept.debug.enabled=true
# Debugfalse
spring.application.strategy.logger.debug.enabled=true

Debug

----------------------- Logger Debug -----------------------
trace-id=dade3982ae65e9e1
span-id=997e31021e9fce20
n-d-service-group=discovery-guide-group
n-d-service-type=service
n-d-service-id=discovery-guide-service-a
n-d-service-address=172.27.208.1:3001
n-d-service-version=1.0
n-d-service-region=dev
n-d-service-env=env1
n-d-service-zone=zone1
n-d-version={"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}
mobile=13812345678
user=
------------------------------------------------------------

FeignRestTemplateWebClientDebug

--------- Feign Intercept Input Header Information ---------
n-d-service-group=discovery-guide-group
n-d-version={"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}
n-d-service-type=gateway
n-d-service-id=discovery-guide-zuul
n-d-service-env=default
mobile=13812345678
n-d-service-region=default
n-d-service-zone=default
n-d-service-address=172.27.208.1:5002
n-d-service-version=1.0
------------------------------------------------------------

FeignRestTemplateWebClientDebug

-------- Feign Intercept Output Header Information ---------
mobile=[13812345678]
n-d-service-address=[172.27.208.1:3001]
n-d-service-env=[env1]
n-d-service-group=[discovery-guide-group]
n-d-service-id=[discovery-guide-service-a]
n-d-service-region=[dev]
n-d-service-type=[service]
n-d-service-version=[1.0]
n-d-service-zone=[zone1]
n-d-version=[{"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}]
------------------------------------------------------------

Sentinel

  • OpenTracing + Jaeger + Sentinel

  • OpenTracing + SkyWalking + Sentinel

DefaultStrategyTracerAdapter

// 
// getTraceIdgetSpanIdOpenTracingOpenTracingHttp Header
// getCustomizationMapOpenTracingHttp Header
public class MyStrategyTracerAdapter extends DefaultStrategyTracerAdapter {
    @Override
    public String getTraceId() {
        return StringUtils.isNotEmpty(strategyContextHolder.getHeader(DiscoveryConstant.TRACE_ID)) ? strategyContextHolder.getHeader(DiscoveryConstant.TRACE_ID) : StringUtils.EMPTY;
    }

    @Override
    public String getSpanId() {
        return StringUtils.isNotEmpty(strategyContextHolder.getHeader(DiscoveryConstant.SPAN_ID)) ? strategyContextHolder.getHeader(DiscoveryConstant.SPAN_ID) : StringUtils.EMPTY;
    }

    @Override
    public Map<String, String> getCustomizationMap() {
        Map<String, String> customizationMap = new LinkedHashMap<String, String>();
        customizationMap.put("mobile", StringUtils.isNotEmpty(strategyContextHolder.getHeader("mobile")) ? strategyContextHolder.getHeader("mobile") : StringUtils.EMPTY);
        customizationMap.put("user", StringUtils.isNotEmpty(strategyContextHolder.getHeader("user")) ? strategyContextHolder.getHeader("user") : StringUtils.EMPTY);

        return customizationMap;
    }
}

@Bean

@Bean
public StrategyTracerAdapter strategyTracerAdapter() {
    return new MyStrategyTracerAdapter();
}

ServiceStrategyMonitorAdapter

// 
// parameterMap
// key
// value
public class MyServiceStrategyMonitorAdapter implements ServiceStrategyMonitorAdapter {
    @Override
    public Map<String, String> getCustomizationMap(ServiceStrategyMonitorInterceptor interceptor, MethodInvocation invocation, Map<String, Object> parameterMap, Object returnValue) {
        Map<String, String> customizationMap = new LinkedHashMap<String, String>();
        customizationMap.put(DiscoveryConstant.PARAMETER, parameterMap.toString());
        customizationMap.put(DiscoveryConstant.RETURN, returnValue != null ? returnValue.toString() : null);

        return customizationMap;
    }
}

@Bean

@Bean
public ServiceStrategyMonitorAdapter serviceStrategyMonitorAdapter() {
    return new MyServiceStrategyMonitorAdapter();
}

TraceIdSpanId

public class MyClass {
    @Autowired
    private StrategyMonitorContext strategyMonitorContext;

    public void doXXX() {
        String traceId = strategyMonitorContext.getTraceId();
        String spanId = strategyMonitorContext.getSpanId();
        ...
    }
}
# false
spring.application.strategy.monitor.enabled=true
# false
spring.application.strategy.alarm.enabled=true
# false
spring.application.strategy.logger.enabled=true
# MDCKeytrue
spring.application.strategy.logger.mdc.key.shown=true
# Debugfalse
spring.application.strategy.logger.debug.enabled=true
# false
spring.application.strategy.tracer.enabled=true
# SpanSpanSkyWalkingtrue
spring.application.strategy.tracer.separate.span.enabled=true
# true
spring.application.strategy.tracer.rule.output.enabled=true
# false
spring.application.strategy.tracer.exception.detail.output.enabled=true
# false
spring.application.strategy.tracer.method.context.output.enabled=true
# SpanNEPXION
spring.application.strategy.tracer.span.value=NEPXION
# Span TagNepxion Discovery
spring.application.strategy.tracer.span.tag.plugin.value=Nepxion Discovery
# SentinelSpantrue
spring.application.strategy.tracer.sentinel.rule.output.enabled=true
# SentinelSpanfalse
spring.application.strategy.tracer.sentinel.args.output.enabled=true

OpenTracingFinchleySpring Cloud Gatewayreactor-coreFinchleySpring Cloud GatewayOpenTracing

<dependency>
    <groupId>com.nepxion</groupId>
    <artifactId>discovery-plugin-strategy-starter-gateway</artifactId>
    <version>${discovery.version}</version>
    <exclusions>
        <exclusion>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
    <version>3.2.3.RELEASE</version>
</dependency>

reactor-core

logback.xmllog4j.xml

<!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
<configuration scan="true" scanPeriod="10 seconds">
    <!-- Simple file output -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>discovery %date %level [%thread] [%X{trace-id}] [%X{span-id}] [%X{n-d-service-group}] [%X{n-d-service-type}] [%X{n-d-service-app-id}] [%X{n-d-service-id}] [%X{n-d-service-address}] [%X{n-d-service-version}] [%X{n-d-service-region}] [%X{n-d-service-env}] [%X{n-d-service-zone}] [%X{mobile}] [%X{user}] %logger{10} [%file:%line] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>log/discovery-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>50MB</maxFileSize>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <!-- Safely log to the same file from multiple JVMs. Degrades performance! -->
        <prudent>true</prudent>
    </appender>

    <appender name="FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold>
        <queueSize>512</queueSize>
        <appender-ref ref="FILE" />
    </appender>

    <!-- Console output -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoder defaults to ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>discovery %date %level [%thread] [%X{trace-id}] [%X{span-id}] [%X{n-d-service-group}] [%X{n-d-service-type}] [%X{n-d-service-app-id}] [%X{n-d-service-id}] [%X{n-d-service-address}] [%X{n-d-service-version}] [%X{n-d-service-region}] [%X{n-d-service-env}] [%X{n-d-service-zone}] [%X{mobile}] [%X{user}] %logger{10} [%file:%line] - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- Only log level WARN and above -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!-- For loggers in the these namespaces, log at all levels. -->
    <logger name="pedestal" level="ALL" />
    <logger name="hammock-cafe" level="ALL" />
    <logger name="user" level="ALL" />

    <root level="INFO">
        <!-- <appender-ref ref="FILE_ASYNC" /> -->
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

Sentinel

Sentinel

  • Pass
  • Block
  • Success
  • Exception

Prometheus MicrometerGrafana

# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.pass.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.block.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.success.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.exception.qps.output.enabled=true

  • DebugHeader
  • Header
@EventBus
public class MySubscriber {
    @Subscribe
    public void onAlarm(StrategyAlarmEvent strategyAlarmEvent) {
        // StrategyConstant.STRATEGY_CONTEXT_ALARM
        String alarmType = strategyAlarmEvent.getAlarmType();

        // alarmMapElasticSearchMessageQueue
        Map<String, String> alarmMap = strategyAlarmEvent.getAlarmMap();
    }
}

@Bean

@Bean
public MySubscriber mySubscriber() {
    return new MySubscriber();
}
# false
spring.application.strategy.alarm.enabled=true

ElasticSearchMessageQueue

traceIdHeader

DevOps

com.nepxion.discovery.plugin.strategy.monitor.DefaultStrategyAlarm
{n-d-service-group=discovery-guide-group, n-d-version={"discovery-guide-service-a":"1.0", "discovery-guide-service-b":"1.0"}, n-d-service-type=service, n-d-service-id=discovery-guide-service-b, n-d-service-env=env1, mobile=, n-d-service-region=qa, span-id=c37b54d7fec6bd07, n-d-service-zone=zone1, n-d-service-address=192.168.0.107:4001, trace-id=64c79e1ef68eecf3, n-d-service-version=1.0}

[email protected]

# RestControllerRPC
spring.application.strategy.scan.packages=com.nepxion.discovery.guide.service.feign

[email protected]@[email protected]

API

[email protected]@PermissionAPI

  • RestHeader

Git

git-commit-id-plugingitgit.commit.idIDgit.build.versionMaven

Git

  • Git

4pom.xmlgit-commit-id-plugin

<plugin>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>revision</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- true -->
        <generateGitPropertiesFile>true</generateGitPropertiesFile>
        <!--  -->
        <dateFormat>yyyyMMdd</dateFormat>
        <!-- <dateFormat>yyyy-MM-dd-HH:mm:ss</dateFormat> -->
    </configuration>
</plugin>
<plugin>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>revision</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- gitfalse -->
        <generateGitPropertiesFile>true</generateGitPropertiesFile>
        <!-- .git${project.basedir}/.git -->
        <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
        <!-- git -->
        <generateGitPropertiesFilename>${project.build.outputDirectory}/git.json</generateGitPropertiesFilename>
        <!-- <generateGitPropertiesFilename>${project.basedir}/git.json</generateGitPropertiesFilename> -->
        <!-- gitproperties -->
        <format>json</format>
        <!-- .gittruefalsetrue -->
        <failOnNoGitDirectory>true</failOnNoGitDirectory>
        <!-- pomtrue -->
        <skipPoms>false</skipPoms>
        <!-- false -->
        <verbose>false</verbose>
        <dateFormat>yyyyMMdd</dateFormat>
        <!-- <dateFormat>yyyy-MM-dd-HH:mm:ss</dateFormat> -->
    </configuration>
</plugin>

https://github.com/git-commit-id/maven-git-commit-id-plugin/blob/master/maven/docs/using-the-plugin.md

# Gitfalse
spring.application.git.generator.enabled=true
# git-commit-id-plugingitpropertiesjsonclasspath:xxxfile:xxxclasspath:git.properties
spring.application.git.generator.path=classpath:git.properties
# spring.application.git.generator.path=classpath:git.json
# Git{git.commit.time}-{git.total.commit.count}
spring.application.git.version.key={git.commit.id.abbrev}-{git.commit.time}
# spring.application.git.version.key={git.build.version}-{git.commit.time}

Gitgit.commit.idgit.commit.id.abbrevgit.build.versiongit.total.commit.count

git.branch=master
git.build.host=Nepxion
git.build.time=2019-10-21-10\:07\:41
[email protected]
git.build.user.name=Nepxion
git.build.version=1.0.0
git.closest.tag.commit.count=
git.closest.tag.name=
git.commit.id=04d7e45b11b975db37bdcdbc5a97c02e9d80e5fa
git.commit.id.abbrev=04d7e45
git.commit.id.describe=04d7e45-dirty
git.commit.id.describe-short=04d7e45-dirty
git.commit.message.full=\u4FEE\u6539\u914D\u7F6E
git.commit.message.short=\u4FEE\u6539\u914D\u7F6E
git.commit.time=2019-10-21T09\:09\:25+0800
[email protected]
git.commit.user.name=Nepxion
git.dirty=true
git.local.branch.ahead=0
git.local.branch.behind=0
git.remote.origin.url=https\://github.com/Nepxion/DiscoveryGuide.git
git.tags=
git.total.commit.count=765

# 
<generateGitPropertiesFilename>${project.basedir}/git.json</generateGitPropertiesFilename>
# json
<format>json</format>
# json
spring.application.git.generator.path=file:git.json

SwaggerRestGit

GitMap http://[IP:PORT]/git/map GET
Git http://[IP:PORT]/git/text GET

# false
spring.application.group.generator.enabled=true
# 0
spring.application.group.generator.length=15
# 
spring.application.group.generator.character=-

  • VM arguments-Dmetadata.-Dmetadata.version=1.0

  • Program arguments--EurekaZookeeperNacosConsultag--spring.cloud.nacos.discovery.metadata.version=1.0

  • 0001-99991

20210601-0003202161

# RestControllerRPC
spring.application.strategy.scan.packages=com.nepxion.discovery.guide.service
# true
spring.application.strategy.auto.scan.packages.enabled=true
# false
spring.application.strategy.auto.scan.recursion.enabled=false

SpringBootcom.acom.aSpringComponentScancom.bcom.bSpringComponentScancom.c

SpringBoot;com.a;com.b;com.c
SpringBoot;com.a
public class MyService {
    @Autowired
    private StrategyPackagesExtractor strategyPackagesExtractor;

    public void getPackages() {
        // @SpringBootApplicationList<String>
        strategyPackagesExtractor.getBasePackagesList();

        // @[email protected]<String>
        strategyPackagesExtractor.getScanningPackagesList();

        // List<String>
        strategyPackagesExtractor.getAllPackagesList();
    }
}

spring.cloud.discovery.metadata.group=xxx-service-group
spring.cloud.discovery.metadata.version=1.0
spring.cloud.discovery.metadata.region=dev
spring.cloud.discovery.metadata.env=env1
spring.cloud.discovery.metadata.zone=zone1
# Eureka config for discovery
eureka.instance.metadataMap.group=xxx-service-group
eureka.instance.metadataMap.version=1.0
eureka.instance.metadataMap.region=dev
eureka.instance.metadataMap.env=env1
eureka.instance.metadataMap.zone=zone1

# Consul config for discovery
# https://springcloud.cc/spring-cloud-consul.html - Consul
spring.cloud.consul.discovery.tags=group=xxx-service-group,version=1.0,region=dev,env=env1,zone=zone1

# Zookeeper config for discovery
spring.cloud.zookeeper.discovery.metadata.group=xxx-service-group
spring.cloud.zookeeper.discovery.metadata.version=1.0
spring.cloud.zookeeper.discovery.metadata.region=dev
spring.cloud.zookeeper.discovery.metadata.env=env1
spring.cloud.zookeeper.discovery.metadata.zone=zone1

# Nacos config for discovery
spring.cloud.nacos.discovery.metadata.group=xxx-service-group
spring.cloud.nacos.discovery.metadata.version=1.0
spring.cloud.nacos.discovery.metadata.region=dev
spring.cloud.nacos.discovery.metadata.env=env1
spring.cloud.nacos.discovery.metadata.zone=zone1

Spring Cloud 202x

Spring Cloud 202xConsul

# Consul config for discovery
spring.cloud.consul.discovery.metadata.group=xxx-service-group
spring.cloud.consul.discovery.metadata.version=1.0
spring.cloud.consul.discovery.metadata.region=dev
spring.cloud.consul.discovery.metadata.env=env1
spring.cloud.consul.discovery.metadata.zone=zone1

[email protected]_-

# 
spring.cloud.consul.discovery.metadata.my_data=abc
spring.cloud.consul.discovery.metadata.my-data=abc

# 
spring.cloud.consul.discovery.metadata.my.data=abc
[email protected]=abc

  • Nacos
# Nacos config for discovery
spring.cloud.nacos.discovery.server-addr=localhost:8848
# spring.cloud.nacos.discovery.namespace=discovery
  • Eureka
# Eureka config for discovery
eureka.client.serviceUrl.defaultZone=http://localhost:9528/eureka/
eureka.instance.preferIpAddress=true
  • Consul
# Consul config for discovery
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.preferIpAddress=true
  • Zookeeper
# Zookeeper config for discovery
spring.cloud.zookeeper.connectString=localhost:2181
spring.cloud.zookeeper.discovery.instancePort=${server.port}
spring.cloud.zookeeper.discovery.root=/spring-cloud
spring.cloud.zookeeper.discovery.preferIpAddress=true
  • Apollo
# Apollo config for rule
app.id=discovery
apollo.meta=http://localhost:8080
# apollo.plugin.namespace=application
  • Nacos
# Nacos config for rule
spring.cloud.nacos.config.server-addr=localhost:8848
# spring.cloud.nacos.config.namespace=application
  • Redis
# Redis config for rule
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
  • Zookeeper
# Zookeeper config for rule
zookeeper.connect-string=localhost:2181
zookeeper.retry-count=3
zookeeper.sleep-time=3000
  • Consul
# Consul config for rule
consul.host=localhost
consul.port=8500
consul.timeout=1
consul.token=
  • Etcd
# Etcd config for rule
etcd.server.addr=http://localhost:2379
etcd.username=
etcd.password=
  • OpenTracing + Jaeger
# OpenTracing config for jaeger
opentracing.jaeger.enabled=true
opentracing.jaeger.http-sender.url=http://localhost:14268/api/traces
  • SkyWalking
-javaagent:C:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=discovery-guide-service-a
  • Spring Boot Admin
# Spring boot admin config
spring.boot.admin.client.instance.prefer-ip=true
spring.boot.admin.client.url=http://localhost:9728

Agent

-javaagent:C:/opt/discovery-agent/discovery-agent-starter-${discovery.agent.version}.jar -Dthread.scan.packages=com.nepxion.discovery.guide.service.feign

# Plugin core config
# /true
spring.application.register.control.enabled=true
# IPtrue
spring.application.discovery.control.enabled=true
# Resttrue
spring.application.config.rest.control.enabled=true
# MapWeightRandom
spring.application.weight.random.type=MapWeightRandom
# xmljsonxml
spring.application.config.format=xml
# spring.application.config.format=json
# classpath:rule.xmlrule.json - resourcesjarfile:rule.xmlrule.json - 
spring.application.config.path=classpath:rule.xml
# spring.application.config.path=classpath:rule.json
# Keygroupeureka.instance.metadataMap.group=xxx-groupeureka.instance.metadataMap.application=xxx-applicationgroup
spring.application.group.key=group
# spring.application.group.key=application
# SpringSpringBootSpringCloud
# resourcespring-application-default.properties
spring.application.default.properties.path=spring-application-default.properties
# false
spring.application.no.servers.retry.enabled=false
# 5
spring.application.no.servers.retry.times=5
# 2000
spring.application.no.servers.retry.await.time=2000
# false
spring.application.no.servers.notify.enabled=false
# [email protected]@SERVICE_IDGROUPtrue
spring.application.nacos.service.id.filter.enabled=true

# Plugin strategy config
# RibbonZoneAvoidanceRuleRoundRobintrue
spring.application.strategy.zone.avoidance.rule.enabled=true
# RESTtrue
spring.application.strategy.rest.intercept.enabled=true
# RESTRequestRequestDestoryHeadertrue
spring.application.strategy.rest.request.decorator.enabled=true
# HeaderDebugfalse
spring.application.strategy.rest.intercept.debug.enabled=true
# Order0
spring.application.strategy.service.route.filter.order=0
# HeaderHeaderHeadertruetrue
spring.application.strategy.service.header.priority=true
# FeignHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.feign.core.header.transmission.enabled=true
# RestTemplateHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.rest.template.core.header.transmission.enabled=true
# WebClientHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.web.client.core.header.transmission.enabled=true
# RESTFeignRestTemplateWebClientHeaderHeadertrace-id, span-id;
spring.application.strategy.context.request.headers=trace-id;span-id
# RESTFeignRestTemplateWebClientHeaderHeadermobile;
spring.application.strategy.business.request.headers=token
# URI/actuator/;
spring.application.strategy.uri.filter.exclusion=/actuator/
# RPCfalse
spring.application.strategy.rpc.intercept.enabled=true
# RestControllerRPC
spring.application.strategy.scan.packages=com.nepxion.discovery.plugin.example.service.feign
# Groupfalse
spring.application.strategy.consumer.isolation.enabled=true
# Groupfalse
spring.application.strategy.provider.isolation.enabled=true

# false
spring.application.strategy.monitor.enabled=true
# false
spring.application.strategy.alarm.enabled=true
# false
spring.application.strategy.logger.enabled=true
# MDCKeytrue
spring.application.strategy.logger.mdc.key.shown=true
# Debugfalse
spring.application.strategy.logger.debug.enabled=true
# false
spring.application.strategy.tracer.enabled=true
# SpanSpanSkyWalkingtrue
spring.application.strategy.tracer.separate.span.enabled=true
# true
spring.application.strategy.tracer.rule.output.enabled=true
# false
spring.application.strategy.tracer.exception.detail.output.enabled=true
# false
spring.application.strategy.tracer.method.context.output.enabled=true
# SpanNEPXION
spring.application.strategy.tracer.span.value=NEPXION
# Span TagNepxion Discovery
spring.application.strategy.tracer.span.tag.plugin.value=Nepxion Discovery
# SentinelSpantrue
spring.application.strategy.tracer.sentinel.rule.output.enabled=true
# SentinelSpanfalse
spring.application.strategy.tracer.sentinel.args.output.enabled=true

# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.pass.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.block.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.success.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.exception.qps.output.enabled=true

# Sentinelfalse
spring.application.strategy.sentinel.datasource.enabled=true
# classpath:sentinel-flow.json
spring.application.strategy.sentinel.flow.path=classpath:sentinel-flow.json
# classpath:sentinel-degrade.json
spring.application.strategy.sentinel.degrade.path=classpath:sentinel-degrade.json
# classpath:sentinel-authority.json
spring.application.strategy.sentinel.authority.path=classpath:sentinel-authority.json
# classpath:sentinel-system.json
spring.application.strategy.sentinel.system.path=classpath:sentinel-system.json
# classpath:sentinel-param-flow.json
spring.application.strategy.sentinel.param.flow.path=classpath:sentinel-param-flow.json

# Sentinel LimitAppfalse
spring.application.strategy.sentinel.limit.app.enabled=true
# Sentinel LimitAppHttpHeaderKeyn-d-service-idKey
spring.application.strategy.sentinel.request.origin.key=n-d-service-id

# defaultcommon
spring.application.strategy.environment.route=common

# Metadatazonefalse
spring.application.strategy.zone.affinity.enabled=true
# true
spring.application.strategy.zone.route.enabled=true

# 
# false
spring.application.strategy.version.failover.enabled=true
# Header
# false
spring.application.strategy.version.prefer.enabled=true

# true
spring.application.parameter.event.onstart.enabled=true

# true
spring.application.strategy.auto.scan.packages.enabled=true
# false
spring.application.strategy.auto.scan.recursion.enabled=false

# false
spring.application.group.generator.enabled=true
# 0
spring.application.group.generator.length=15
# 
spring.application.group.generator.character=-

# Gitfalse
spring.application.git.generator.enabled=true
# git-commit-id-plugingitpropertiesjsonclasspath:xxxfile:xxxclasspath:git.properties
spring.application.git.generator.path=classpath:git.properties
# spring.application.git.generator.path=classpath:git.json
# Git{git.commit.time}-{git.total.commit.count}
spring.application.git.version.key={git.commit.id.abbrev}-{git.commit.time}
# spring.application.git.version.key={git.build.version}-{git.commit.time}

# Hystrixspring.application.strategy.hystrix.threadlocal.supportedtruediscovery-plugin-strategy-starter-hystrixThreadLocalfalse
spring.application.strategy.hystrix.threadlocal.supported=true

# Swaggertrue
swagger.service.enabled=true
# SwaggerDocket
swagger.service.base.group=Nepxion Discovery
# SwaggerDocket
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

Spring Cloud Gateway

# Plugin core config
# /true
spring.application.register.control.enabled=true
# IPtrue
spring.application.discovery.control.enabled=true
# Resttrue
spring.application.config.rest.control.enabled=true
# MapWeightRandom
spring.application.weight.random.type=MapWeightRandom
# xmljsonxml
spring.application.config.format=xml
# spring.application.config.format=json
# classpath:rule.xmlrule.json - resourcesjarfile:rule.xmlrule.json - 
spring.application.config.path=classpath:rule.xml
# spring.application.config.path=classpath:rule.json
# Keygroupeureka.instance.metadataMap.group=xxx-groupeureka.instance.metadataMap.application=xxx-applicationgroup
spring.application.group.key=group
# spring.application.group.key=application
# SpringSpringBootSpringCloud
# resourcespring-application-default.properties
spring.application.default.properties.path=spring-application-default.properties
# false
spring.application.no.servers.retry.enabled=false
# 5
spring.application.no.servers.retry.times=5
# 2000
spring.application.no.servers.retry.await.time=2000
# false
spring.application.no.servers.notify.enabled=false
# [email protected]@SERVICE_IDGROUPtrue
spring.application.nacos.service.id.filter.enabled=true

# Plugin strategy config
# RibbonZoneAvoidanceRuleRoundRobintrue
spring.application.strategy.zone.avoidance.rule.enabled=true
# Order9000
spring.application.strategy.gateway.route.filter.order=9000
# HeaderHeaderHeadertruetrue
spring.application.strategy.gateway.header.priority=false
# HeaderHeaderHeadertrue
spring.application.strategy.gateway.original.header.ignored=true
# false
spring.application.strategy.gateway.dynamic.route.enabled=true
# HeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.gateway.core.header.transmission.enabled=true
# Groupfalse
spring.application.strategy.consumer.isolation.enabled=true

# false
spring.application.strategy.monitor.enabled=true
# false
spring.application.strategy.alarm.enabled=true
# false
spring.application.strategy.logger.enabled=true
# MDCKeytrue
spring.application.strategy.logger.mdc.key.shown=true
# Debugfalse
spring.application.strategy.logger.debug.enabled=true
# false
spring.application.strategy.tracer.enabled=true
# SpanSpanSkyWalkingtrue
spring.application.strategy.tracer.separate.span.enabled=true
# true
spring.application.strategy.tracer.rule.output.enabled=true
# false
spring.application.strategy.tracer.exception.detail.output.enabled=true
# SpanNEPXION
spring.application.strategy.tracer.span.value=NEPXION
# Span TagNepxion Discovery
spring.application.strategy.tracer.span.tag.plugin.value=Nepxion Discovery
# SentinelSpantrue
spring.application.strategy.tracer.sentinel.rule.output.enabled=true
# SentinelSpanfalse
spring.application.strategy.tracer.sentinel.args.output.enabled=true

# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.pass.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.block.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.success.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.exception.qps.output.enabled=true

# Sentinelfalse
spring.application.strategy.sentinel.datasource.enabled=true
# classpath:sentinel-flow.json
spring.application.strategy.sentinel.flow.path=classpath:sentinel-flow.json
# classpath:sentinel-degrade.json
spring.application.strategy.sentinel.degrade.path=classpath:sentinel-degrade.json
# classpath:sentinel-authority.json
spring.application.strategy.sentinel.authority.path=classpath:sentinel-authority.json
# classpath:sentinel-system.json
spring.application.strategy.sentinel.system.path=classpath:sentinel-system.json
# classpath:sentinel-param-flow.json
spring.application.strategy.sentinel.param.flow.path=classpath:sentinel-param-flow.json

# defaultcommon
spring.application.strategy.environment.route=common

# Metadatazonefalse
spring.application.strategy.zone.affinity.enabled=true
# true
spring.application.strategy.zone.route.enabled=true

# 
# false
spring.application.strategy.version.failover.enabled=true
# Header
# false
spring.application.strategy.version.prefer.enabled=true

# true
spring.application.parameter.event.onstart.enabled=true

# true
spring.application.strategy.auto.scan.packages.enabled=true
# false
spring.application.strategy.auto.scan.recursion.enabled=false

# false
spring.application.group.generator.enabled=true
# 0
spring.application.group.generator.length=15
# 
spring.application.group.generator.character=-

# Gitfalse
spring.application.git.generator.enabled=true
# git-commit-id-plugingitpropertiesjsonclasspath:xxxfile:xxxclasspath:git.properties
spring.application.git.generator.path=classpath:git.properties
# spring.application.git.generator.path=classpath:git.json
# Git{git.commit.time}-{git.total.commit.count}
spring.application.git.version.key={git.commit.id.abbrev}-{git.commit.time}
# spring.application.git.version.key={git.build.version}-{git.commit.time}

# SkyWalking apm-agent-coreTraceIdSkyWalkingWebFluxThreadlocalTraceIdTraceIdtrue
spring.application.strategy.gateway.skywalking.traceid.enabled=true

# FeignRestTemplateWebClient
# RESTtrue
spring.application.strategy.rest.intercept.enabled=true
# HeaderDebugfalse
spring.application.strategy.rest.intercept.debug.enabled=true
# FeignHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.feign.core.header.transmission.enabled=true
# RestTemplateHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.rest.template.core.header.transmission.enabled=true
# WebClientHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.web.client.core.header.transmission.enabled=true
# RESTFeignRestTemplateWebClientHeaderHeadertrace-id, span-id;
spring.application.strategy.context.request.headers=trace-id;span-id
# RESTFeignRestTemplateWebClientHeaderHeadermobile;
spring.application.strategy.business.request.headers=user;mobile;location

# Spring Cloud GatewayHystrixspring.application.strategy.hystrix.threadlocal.supportedtruediscovery-plugin-strategy-starter-hystrixThreadLocalfalse
spring.application.strategy.hystrix.threadlocal.supported=true

Zuul

# Plugin core config
# /true
spring.application.register.control.enabled=true
# IPtrue
spring.application.discovery.control.enabled=true
# Resttrue
spring.application.config.rest.control.enabled=true
# MapWeightRandom
spring.application.weight.random.type=MapWeightRandom
# xmljsonxml
spring.application.config.format=xml
# spring.application.config.format=json
# classpath:rule.xmlrule.json - resourcesjarfile:rule.xmlrule.json - 
spring.application.config.path=classpath:rule.xml
# spring.application.config.path=classpath:rule.json
# Keygroupeureka.instance.metadataMap.group=xxx-groupeureka.instance.metadataMap.application=xxx-applicationgroup
spring.application.group.key=group
# spring.application.group.key=application
# SpringSpringBootSpringCloud
# resourcespring-application-default.properties
spring.application.default.properties.path=spring-application-default.properties
# false
spring.application.no.servers.retry.enabled=false
# 5
spring.application.no.servers.retry.times=5
# 2000
spring.application.no.servers.retry.await.time=2000
# false
spring.application.no.servers.notify.enabled=false
# [email protected]@SERVICE_IDGROUPtrue
spring.application.nacos.service.id.filter.enabled=true

# Plugin strategy config
# RibbonZoneAvoidanceRuleRoundRobintrue
spring.application.strategy.zone.avoidance.rule.enabled=true
# Order0
spring.application.strategy.zuul.route.filter.order=0
# HeaderHeaderHeadertruetrue
spring.application.strategy.zuul.header.priority=false
# HeaderHeaderHeadertrue
spring.application.strategy.zuul.original.header.ignored=true
# false
spring.application.strategy.zuul.dynamic.route.enabled=true
# HeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.zuul.core.header.transmission.enabled=true
# Groupfalse
spring.application.strategy.consumer.isolation.enabled=true

# false
spring.application.strategy.monitor.enabled=true
# false
spring.application.strategy.logger.enabled=true
# MDCKeytrue
spring.application.strategy.logger.mdc.key.shown=true
# Debugfalse
spring.application.strategy.logger.debug.enabled=true
# false
spring.application.strategy.tracer.enabled=true
# SpanSpanSkyWalkingtrue
spring.application.strategy.tracer.separate.span.enabled=true
# true
spring.application.strategy.tracer.rule.output.enabled=true
# false
spring.application.strategy.tracer.exception.detail.output.enabled=true
# SpanNEPXION
spring.application.strategy.tracer.span.value=NEPXION
# Span TagNepxion Discovery
spring.application.strategy.tracer.span.tag.plugin.value=Nepxion Discovery
# SentinelSpantrue
spring.application.strategy.tracer.sentinel.rule.output.enabled=true
# SentinelSpanfalse
spring.application.strategy.tracer.sentinel.args.output.enabled=true

# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.pass.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.block.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.success.qps.output.enabled=true
# Sentinel Metrictrue
spring.application.strategy.metric.sentinel.exception.qps.output.enabled=true

# Sentinelfalse
spring.application.strategy.sentinel.datasource.enabled=true
# classpath:sentinel-flow.json
spring.application.strategy.sentinel.flow.path=classpath:sentinel-flow.json
# classpath:sentinel-degrade.json
spring.application.strategy.sentinel.degrade.path=classpath:sentinel-degrade.json
# classpath:sentinel-authority.json
spring.application.strategy.sentinel.authority.path=classpath:sentinel-authority.json
# classpath:sentinel-system.json
spring.application.strategy.sentinel.system.path=classpath:sentinel-system.json
# classpath:sentinel-param-flow.json
spring.application.strategy.sentinel.param.flow.path=classpath:sentinel-param-flow.json

# defaultcommon
spring.application.strategy.environment.route=common

# Metadatazonefalse
spring.application.strategy.zone.affinity.enabled=true
# true
spring.application.strategy.zone.route.enabled=true

# 
# false
spring.application.strategy.version.failover.enabled=true
# Header
# false
spring.application.strategy.version.prefer.enabled=true

# true
spring.application.parameter.event.onstart.enabled=true

# true
spring.application.strategy.auto.scan.packages.enabled=true
# false
spring.application.strategy.auto.scan.recursion.enabled=false

# false
spring.application.group.generator.enabled=true
# 0
spring.application.group.generator.length=15
# 
spring.application.group.generator.character=-

# Gitfalse
spring.application.git.generator.enabled=true
# git-commit-id-plugingitpropertiesjsonclasspath:xxxfile:xxxclasspath:git.properties
spring.application.git.generator.path=classpath:git.properties
# spring.application.git.generator.path=classpath:git.json
# Git{git.commit.time}-{git.total.commit.count}
# spring.application.git.version.key={git.commit.id.abbrev}-{git.commit.time}
# spring.application.git.version.key={git.build.version}-{git.commit.time}

# FeignRestTemplateWebClient
# RESTtrue
spring.application.strategy.rest.intercept.enabled=true
# HeaderDebugfalse
spring.application.strategy.rest.intercept.debug.enabled=true
# FeignHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.feign.core.header.transmission.enabled=true
# RestTemplateHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.rest.template.core.header.transmission.enabled=true
# WebClientHeadertrueHeaderHeader
# 1. n-d-version
# 2. n-d-region
# 3. n-d-address
# 4. n-d-version-weight
# 5. n-d-region-weight
# 6. n-d-id-blacklist
# 7. n-d-address-blacklist
# 8. n-d-env (Header)
spring.application.strategy.web.client.core.header.transmission.enabled=true
# RESTFeignRestTemplateWebClientHeaderHeadertrace-id, span-id;
spring.application.strategy.context.request.headers=trace-id;span-id
# RESTFeignRestTemplateWebClientHeaderHeadermobile;
spring.application.strategy.business.request.headers=user;mobile;location

# ZuulHystrixspring.application.strategy.hystrix.threadlocal.supportedtruediscovery-plugin-strategy-starter-hystrixThreadLocalfalse
spring.application.strategy.hystrix.threadlocal.supported=true

spring-application-default.propertiessrc/main/resourcesspring-application-default.properties

DockerKubernetes

Docker

Spring 2.3.xDockerPolaris

Windows10LinuxDocker

4pom.xmlspring-boot-maven-plugindocker-maven-plugin

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
        <mainClass>com.nepxion.discovery.guide.gateway.DiscoveryGuideGateway</mainClass>
        <layout>JAR</layout>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
            <configuration>
                <attach>false</attach>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <configuration>
        <imageName>${ImageName}</imageName>
        <baseImage>openjdk:8-jre-alpine</baseImage>
        <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
        <exposes>
            <expose>${ExposePort}</expose>
        </exposes>
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
    </configuration>
</plugin>

discovery-guide-docker

MIDDLEWARE_HOST=10.0.75.1IPDockerlocalhost

Docker

  • install-docker-gateway.bat.shSpring Cloud Gateway
  • install-docker-zuul.bat.shZuul
  • install-docker-service-xx.bat.sh
  • install-docker-console.bat.sh
  • install-docker-admin.bat.sh

DevOps

Docker

  • Docker Desktop

  • Docker Windows

  • Docker Linux

Kubernetes

Spring Boot/Spring CloudSentinelFF4jSpring BootFeignRestTemplateWebClient

Matrix AopTestAutoScanProxyTestInterceptor

DiscoveryGuideConsole.java

# 
# 
spring.application.test.scan.packages=com.nepxion.discovery.guide.test
# true
spring.application.test.config.print.enabled=true
# 3000
spring.application.test.config.operation.await.time=5000
# 
spring.application.test.console.url=http://localhost:6001/

# 
# Spring Cloud Gateway
gateway.group=discovery-guide-group
gateway.service.id=discovery-guide-gateway
gateway.test.url=http://localhost:5001/discovery-guide-service-a/invoke/gateway
gateway.route0.test.url=http://localhost:5001/x/invoke/gateway
gateway.route1.test.url=http://localhost:5001/y/invoke/gateway
gateway.route2.test.url=http://localhost:5001/z/invoke/gateway
gateway.inspect.url=http://localhost:5001/discovery-guide-service-a/inspector/inspect

# Zuul
zuul.group=discovery-guide-group
zuul.service.id=discovery-guide-zuul
zuul.test.url=http://localhost:5002/discovery-guide-service-a/invoke/zuul
zuul.route0.test.url=http://localhost:5002/x/invoke/zuul
zuul.route1.test.url=http://localhost:5002/y/invoke/zuul
zuul.route2.test.url=http://localhost:5002/z/invoke/zuul
zuul.inspect.url=http://localhost:5002/discovery-guide-service-a/inspector/inspect

# 
testcase.loop.times=1

# true
gray.weight.testcases.enabled=true
# 
gray.weight.testcase.sample.count=1500
# 
gray.weight.testcase.result.offset=5

EurekaSpring CloudEurekazone

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

@DTestConfigSpringSpelgroup = "#group", serviceId = "#serviceId"Java8"-parameters"

IDE"-parameters"Compiler Argument

Spring Boot

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
                <encoding>${project.build.sourceEncoding}</encoding>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Spring Boot [email protected]est

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestApplication.class, DiscoveryGuideTestConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DiscoveryGuideTest {
    @Autowired
    private DiscoveryGuideTestCases discoveryGuideTestCases;

    private static long startTime;

    @BeforeClass
    public static void beforeTest() {
        startTime = System.currentTimeMillis();
    }

    @AfterClass
    public static void afterTest() {
        LOG.info("* Finished automation test in {} seconds", (System.currentTimeMillis() - startTime) / 1000);
    }

    @Test
    public void testNoGray() throws Exception {
        discoveryGuideTestCases.testNoGray(gatewayTestUrl);
        discoveryGuideTestCases.testNoGray(zuulTestUrl);
    }

    @Test
    public void testVersionStrategyGray() throws Exception {
        discoveryGuideTestCases.testVersionStrategyGray1(gatewayGroup, gatewayServiceId, gatewayTestUrl);
        discoveryGuideTestCases.testVersionStrategyGray1(zuulGroup, zuulServiceId, zuulTestUrl);
    }
}
@Configuration
public class DiscoveryGuideTestConfiguration {
    @Bean
    public DiscoveryGuideTestCases discoveryGuideTestCases() {
        return new DiscoveryGuideTestCases();
    }
}

@[email protected]

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DTest {

}
public class DiscoveryGuideTestCases {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @DTest
    public void testNoGray(String testUrl) {
        int noRepeatCount = 0;
        List<String> resultList = new ArrayList<String>();
        for (int i = 0; i < 4; i++) {
            String result = testRestTemplate.getForEntity(testUrl, String.class).getBody();

            LOG.info("Result{} : {}", i + 1, result);

            if (!resultList.contains(result)) {
                noRepeatCount++;
            }
            resultList.add(result);
        }

        Assert.assertEquals(noRepeatCount, 4);
    }
}

@DTestConfigAssertDTestConfig

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DTestConfig {
    // 
    String group();

    // 
    String serviceId();

    // 
    FormatType formatType() default FormatType.TEXT_FORMAT;

    // -
    String prefix() default StringUtils.EMPTY;

    // -
    String suffix() default StringUtils.EMPTY;

    // 
    String executePath();

    // 
    // -
    String resetPath() default StringUtils.EMPTY;
}
public class DiscoveryGuideTestCases {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @DTestConfig(group = "#group", serviceId = "#serviceId", executePath = "gray-strategy-version-1.xml", resetPath = "gray-default.xml")
    public void testVersionStrategyGray(String group, String serviceId, String testUrl) {
        for (int i = 0; i < 4; i++) {
            String result = testRestTemplate.getForEntity(testUrl, String.class).getBody();

            LOG.info("Result{} : {}", i + 1, result);

            int index = result.indexOf("[V=1.0]");
            int lastIndex = result.lastIndexOf("[V=1.0]");

            Assert.assertNotEquals(index, -1);
            Assert.assertNotEquals(lastIndex, -1);
            Assert.assertNotEquals(index, lastIndex);
        }
    }
}

gray-strategy-version-1.xml

<?xml version="1.0" encoding="UTF-8"?>
<rule>
    <strategy>
        <version>1.0</version>
    </strategy>
</rule>

gray-default.xml

<?xml version="1.0" encoding="UTF-8"?>
<rule>

</rule>

SentinelPolarisGuide

NacosApollo

  • NacosKey
GroupDEFAULT_GROUPData IDsentinel-authority-${spring.application.name}Sentinel
  • ApolloKey
namespaceapplicationKeysentinel-authoritySentinel

executePath = "sentinel-authority-2.json"

Assert

resetPath = "sentinel-authority-1.json"

public class PolarisTestCases {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @DTestConfig(group = "DEFAULT_GROUP", serviceId = "sentinel-authority-polaris-service-b", executePath = "sentinel-authority-2.json", resetPath = "sentinel-authority-1.json")
    public void testSentinelAuthority1(String testUrl) {
        int count = 0;
        for (int i = 0; i < 4; i++) {
            String result = testRestTemplate.postForEntity(testUrl, "gateway", String.class).getBody();

            LOG.info("Result{} : {}", i + 1, result);

            if (result.contains("AuthorityRule")) {
                count++;
            }
        }

        Assert.assertEquals(count, 4);
    }
}

---------- Run automation testcase :: testNoGray() ----------
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testEnabledStrategyGray1() ----------
Header : [mobile:"138"]
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testVersionStrategyGray1() ----------
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testRegionStrategyGray1() ----------
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testVersionWeightStrategyGray() ----------
Sample count=3000
Weight result offset desired=5%
A service desired : 1.0 version weight=90%, 1.1 version weight=10%
B service desired : 1.0 version weight=20%, 1.1 version weight=80%
Result : A service 1.0 version weight=89.6%
Result : A service 1.1 version weight=10.4%
Result : B service 1.0 version weight=20.1333%
Result : B service 1.1 version weight=79.8667%
* Passed
---------- Run automation testcase :: testRegionWeightStrategyGray() ----------
Sample count=3000
Weight result offset desired=5%
A service desired : dev region weight=85%, qa region weight=15%
B service desired : dev region weight=85%, qa region weight=15%
Result : A service dev region weight=83.7667%
Result : A service qa region weight=16.2333%
Result : B service dev region weight=86.2%
Result : B service qa region weight=13.8%
* Passed
---------- Run automation testcase :: testStrategyGray1() ----------
Header : [a:"1", b:"2"]
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testVersionRuleGray() ----------
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testRegionRuleGray() ----------
Result1 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result2 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
Result3 : gateway -> discovery-guide-service-a[192.168.0.107:3002][V=1.1][R=qa][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4001][V=1.0][R=qa][G=discovery-guide-group]
Result4 : gateway -> discovery-guide-service-a[192.168.0.107:3001][V=1.0][R=dev][G=discovery-guide-group] -> discovery-guide-service-b[192.168.0.107:4002][V=1.1][R=dev][G=discovery-guide-group]
* Passed
---------- Run automation testcase :: testVersionWeightRuleGray() ----------
Sample count=3000
Weight result offset desired=5%
A service desired : 1.0 version weight=75%, 1.1 version weight=25%
B service desired : 1.0 version weight=35%, 1.1 version weight=65%
Result : A service 1.0 version weight=75.2667%
Result : A service 1.1 version weight=24.7333%
Result : B service 1.0 version weight=35.1667%
Result : B service 1.1 version weight=64.8333%
* Passed
---------- Run automation testcase :: testRegionWeightRuleGray() ----------
Sample count=3000
Weight result offset desired=5%
A service desired : dev region weight=95%, qa region weight=5%
B service desired : dev region weight=95%, qa region weight=5%
Result : A service dev region weight=94.9333%
Result : A service qa region weight=5.0667%
Result : B service dev region weight=95.0667%
Result : B service qa region weight=4.9333%
* Passed
---------- Run automation testcase :: testVersionCompositeRuleGray() ----------
Sample count=3000
Weight result offset desired=5%
A service desired : 1.0 version weight=40%, 1.1 version weight=60%
Route desired : A Service 1.0 version -> B Service 1.0 version, A Service 1.1 version -> B Service 1.1 version
Result : A service 1.0 version weight=39.8333%
A service 1.1 version weight=60.1667%
* Passed

WRK

Spring Cloud

Spring CloudZuul

Spring Cloud Gateway 16C 32G 1
Zuul 1.x 16C 32G 1
Service 4C 8G 2
  • Spring Cloud Gateway
  • Zuul 1.x
zuul.host.max-per-route-connections=1000
zuul.host.max-total-connections=1000
zuul.semaphore.max-semaphores=5000

: wrk <> <HTTPURL>
  Options:
    -c, --connections TCP
    -d, --duration    2s2m2h
    -t, --threads     
    -s, --script      Lua
    -H, --header      HTTPHTTP-H "id: 123" -H "token: abc"
        --latency     
        --timeout     
  • Requests/sec

WRK

Spring Cloud Gateway 5000 20000 28100 CPU42%
Spring Cloud Gateway 5000 20000 27800 CPU42.3%
Zuul 1.x 5000 20000 24050 CPU56%
Zuul 1.x 5000 20000 23500 CPU56.5%

Nacos

Consul

Eureka

Zookeeper

Nacos

Apollo

Redis

Etcd

Sentinel

Jaeger

SkyWalking

Zipkin

Prometheus

Grafana

Spring Boot Admin

H2

Star

Stargazers over time


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Java (705,197
Spring Cloud (1,660
Apollo (1,278
Sentinel (183
Opentelemetry (161
Nacos (155
Related Projects