1. If you are in charge of operations, how often do you find that the service registry in your test environment is registered with the local development environment by some irresponsible developer, causing testers to fail their tests? You want to be able to block the local development environment registration from being registered.

  2. If you are the operations leader, an instance of a microservice cluster in a production environment has a temporary problem, but you don’t want it to go offline. You want to be able to block this instance from being called for the time being.

  3. If you are a business owner, instances under a microservice cluster release different versions due to the rapid iteration of business services. You want to route according to versioning policies, providing the downstream microservices for differentiated calls, such as access control to quickly switch between versions, such as traffic dialing between different versions.

  4. If you are in charge of the business, you want the grayscale publishing function to be customized based on the characteristics of the business scenario, for example, routing different servers according to the user’s mobile phone number.

  5. If you are in charge of the DBA, you want the grayscale publishing function to be switched on based on the database.

  6. If you are A test lead and want to do A/B testing of microservices, do this by dynamically changing versions.

Filtering IP address registration in black/white lists
Maximum number of registrations limit filtering
Filter the discovery of IP addresses in the black and white lists
Greyscale control for multi-version access
Multi-version weight grayscale control
Multi-data source database gray control
Dynamic changes to microservice versions

  • We can query different users based on different tokens on the gateway and route the request to the specified server.

  • We can route requests to specific servers on the service based on different business parameters, such as mobile phone numbers or ID numbers.

  • It has great flexibility – support filtering control and grayscale publishing in any link.

  • Has minimal restrictions – as long as service registration discovery is enabled, the program entry is added with @enableDiscoveryClient.

  • Great usability – Grayscale publishing via Rest when remote configuration centers are all down.

  • The IP address filtering mechanism based on black and white lists prohibits the registration of corresponding micro-services.

  • Limit microservice registrations based on the maximum number of registrations. Once the number of registered instances in a microservice cluster reaches the upper limit, subsequent microservices are prohibited from being registered.

  • The IP address filtering mechanism based on black and white lists prevents the corresponding micro-services from being discovered.

  • Based on version number matching, multi-version access control is implemented at the service discovery and load balancing levels by configuring the mapping between the accessible versions of the consumer and provider.

  • Based on the version weight pairing, you can configure the mapping between the version weight (traffic) of the consumer and provider to implement multi-version traffic allocation access control at the service discovery and load balancing levels.

  • Through the dynamic change of version, the grayscale publishing can be switched.

  • Through the change of version access rules, the grayscale distribution can be switched.

  • Smooth grayscale publishing is realized by changing version weight rules.

  • Connect to the remote configuration center, integrate Nacos and Redis, asynchronously accept the rule information pushed by the remote configuration center actively, and dynamically change the rules of microservices.

  • In addition, Spring Boot Actuator asynchronously accepts Rest active push rule information and dynamically changes the rules of microservices, supporting synchronous and asynchronous push.

  • Combined with Spring Boot Actuator, the version of micro services can be dynamically changed, supporting synchronous and asynchronous push.

  • In the control of service registration level, once the condition prohibiting registration is triggered, asynchronous events are actively pushed so that users can subscribe.

  • The user can monitor the core event of service registration discovery, so that users can customize and program grayscale routing strategy through expansion.

  • Users can implement routing policies related to services to balance load to different servers based on service parameters.

  • Users can achieve the required routing function according to the built-in version routing policy + user-defined policy.

  • In application.properties or application.yml, you must define a version number for the microservice, and you must define a group name or application name for the microservice.

  • Users only need to pay attention to relevant rule notifications. You can use either of the following methods:

  1. Push rules through the remote configuration center

  2. Push rules through the console interface

  3. Push through a client tool, such as Postman

<register> <blacklist> <service service-name="a" filter-value="172.16"/> </blacklist> <whitelist> <service Service - name = "a" filter - value = "10.10" / > < / whitelist > < / register >Copy the code
<register>    <count>        <service service-name="a" filter-value="500"/>    </count></register>Copy the code
<discovery> <blacklist> <service service-name="a" filter-value="172.16"/> </blacklist> <whitelist> <service Service - name = "a" filter - value = "10.10" / > < / whitelist > < / discovery >Copy the code
<discovery> <version> <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="1.1" The provider - version - value = "1.1" / > < / version > < / discovery >Copy the code
<discovery> <weight> <service consumer-service-name="a" provider-service-name="b" provider-weight-value="1.0=90; 1.1 = 10 "/ > < / weight > < / discovery >Copy the code
<customization>    <service service-name="discovery-springcloud-example-b" key="database" value="prod"/></customization>Copy the code


Grayscale publishing based on gateway version weight

  1. The gateway does not need to be configured with a version

  2. Gateway -> Service A(V1.0), 100% weight (traffic) of Gateway ration Service A(V1.0)

  1. On-line Service A(V1.1)

  2. At the gateway layer, 10% weight (traffic) is assigned to A(V1.1), and the weight (traffic) assigned to A(V1.0) is reduced to 90%

  3. Confirm the validity of gray scale by observation, and switch all the weight (flow) of A(V1.0) to A(V1.1).

  1. Offline service A(V1.0), gray scale successful


Grayscale publishing based on gateway version switching

  1. Assuming the current production environment, the call path is Gateway (V1.0)-> Service A(V1.0)

  2. O&m will release A new production environment and deploy A new service cluster, Service A(V1.1)

  3. Because gateways (1.0) do not point to service A(V1.1), they cannot be invoked

  1. Added Gateway for Grayscale publishing (V1.1), pointing to Service A(V1.1)

  2. Grayscale gateway (V1.1) is published to the service registry discovery center, but is forbidden to be discovered by the service. Calls coming in from outside the gateway cannot be load-balanced to the gateway (V1.1)

  3. Grayscale test is performed in the call path of Grayscale Gateway (V1.1)-> Service A(V1.1)

  4. After successful greyscale test, point gateway (V1.0) to service A(V1.1)

  1. Offline service A(V1.0), gray scale successful

  2. Gray gateway (V1.1) can not be offline, reserved for the next version online again gray release

  3. If you are more confident about the new service, you can simplify it by using grayscale gateway and grayscale test. When service A(V1.1) goes online, the original gateway points directly to service A(V1.1) and then goes offline to service A(V1.0).

  1. Based on service programming gray routing, realize DiscoveryEnabledExtension, The business context parameters are obtained by RequestContextHolder (which gets the Header parameter from the gateway) and ServiceStrategyContext (which gets the method parameter from the RPC mode) for route customization

  2. Zuul based programming gray routing, realize DiscoveryEnabledExtension, on Zuul own RequestContext (obtain from gateway Header parameters) for business context parameters, routed the custom

  3. Spring-based programming gray Cloud Api Gateway routing, realize DiscoveryEnabledExtension, through GatewayStrategyContext (obtain from Gateway Header parameters) for business context parameters, routed the custom

@Beanpublic MyDiscoveryEnabledExtension myDiscoveryEnabledExtension() { return new MyDiscoveryEnabledExtension(); }Copy the code
public class MyDiscoveryEnabledExtension implements DiscoveryEnabledExtension { private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledExtension.class); @Override public boolean apply(Server server, Map<String, String> metadata) {return applyFromHeader(server, metadata); String> metadata) {return applyFromHeader(server, metadata); } // According to the Header argument (such as Token) passed in the Rest call, Private Boolean applyFromHeader(Server Server, Map<String, String> metadata) { RequestContext context = RequestContext.getCurrentContext(); String token = context.getRequest().getHeader("token"); // String value = context.getRequest().getParameter("value"); String serviceId = server.getMetaInfo().getAppName().toLowerCase(); Log.info ("Zuul side load balancing user customized trigger: serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context); String filterToken = "abc"; If (stringutils.isnotempty (token) &&token. Contains (filterToken)) {log.info (" filterToken: Tokens with '{}' cannot be loaded with ", filterToken) by the Ribbon; return false; } return true; }}Copy the code
public class MyDiscoveryEnabledExtension implements DiscoveryEnabledExtension { private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledExtension.class); @Override public boolean apply(Server server, Map<String, String> metadata) {return applyFromMethd(server, metadata); }Copy the code
    @SuppressWarnings("unchecked")Copy the code
private boolean applyFromMethd(Server server, Map<String, String> metadata) { ServiceStrategyContext context = ServiceStrategyContext.getCurrentContext(); Map<String, Object> attributes = context.getAttributes(); String serviceId = server.getMetaInfo().getAppName().toLowerCase(); String version = metadata.get(DiscoveryConstant.VERSION); Log.info ("Serivice side load balancing user customization trigger: serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context); String filterServiceId = "discovery-springcloud-example-b"; String filterVersion = "1.0"; String filterBusinessValue = "abc"; if (StringUtils.equals(serviceId, filterServiceId) && StringUtils.equals(version, filterVersion)) { if (attributes.containsKey(ServiceStrategyConstant.PARAMETER_MAP)) { Map<String, Object> parameterMap = (Map<String, Object>) attributes.get(ServiceStrategyConstant.PARAMETER_MAP); String value = parameterMap.get("value").toString(); If (stringutils.isnotempty (value) && value.contains(filterBusinessValue)) {log.info (" filterBusinessValue: ServiceId ={} && version={} && service parameters with '{}' cannot be loaded with ", filterServiceId, filterVersion, filterBusinessValue). return false; } } } return true; }}Copy the code
@EventBuspublic class MySubscriber { @Autowired private PluginAdapter pluginAdapter; @Subscribe public void onCustomization(CustomizationEvent customizationEvent) { CustomizationEntity customizationEntity = customizationEvent.getCustomizationEntity(); String serviceId = pluginAdapter.getServiceId(); if (customizationEntity ! = null) { Map<String, Map<String, String>> customizationMap = customizationEntity.getCustomizationMap(); Map<String, String> customizationParameter = customizationMap.get(serviceId); // Dynamically switch data source according to the parameter of customizationParameter} else {// dynamically switch data source according to the parameter of customizationParameter}} @subscribe public void OnRegisterFailure (RegisterFailureEvent RegisterFailureEvent) {system.out.println ("========== register failed, eventType=" + registerFailureEvent.getEventType() + ", eventDescription=" + registerFailureEvent.getEventDescription() + ", serviceId=" + registerFailureEvent.getServiceId() + ", host=" + registerFailureEvent.getHost() + ", port=" + registerFailureEvent.getPort()); }}Copy the code

public class MyRegisterListener extends AbstractRegisterListener {    @Override    public void onRegister(Registration registration) {    }    @Override    public void onDeregister(Registration registration) {    }    @Override    public void onSetStatus(Registration registration, String status) {    }    @Override    public void onClose() {    }}Copy the code

public class MyDiscoveryListener extends AbstractDiscoveryListener {    @Override    public void onGetInstances(String serviceId, List<ServiceInstance> instances) {    }    @Override    public void onGetServices(List<String> services) {    }}

public class MyLoadBalanceListener extends AbstractLoadBalanceListener {    @Override    public void onGetServers(String serviceId, List<? extends Server> servers) {    }}Copy the code

@EventBuspublic class MySubscriber { @Subscribe public void onRegisterFailure(RegisterFailureEvent registerFailureEvent) {}}