Using Alibaba cloud's MSE, the last real gray publishing scheme

1. What is MSE

Alibaba cloud MSE (Microservices Engine) microservice engine includes the following three main modules: microservice registry, microservice governance and cloud native gateway. The label routing in the microservice governance function can realize the gray function.

 2. Gray demand

Except for traffic entry (such as pile service, gateway service, etc.), all back-end services shall be able to support grouping by version;
Isolate the relevant versions of the application into an independent running environment, and route the request traffic that meets the rules to the target version application by setting flow control routing rules.
Sketch Map:

  • Online service version v1111;
  • New version v2222, i.e. grayscale version;
  • Set the traffic rules. The traffic that meets the rules will enter the gray version, and the traffic that does not meet the rules will enter the online version;

Key requirements:

  1. It shall be able to route accurately according to traffic rules;
  2. The traffic must be full link;

3.demo program

There are four services: device - > charge - > order - > base, of which charge and order have two versions.
Architecture: k8s + springcloud + eureka + feign
Registration Center:

All services accept two parameters:

  • str: record the link passed and output it in the last service;
  • userId: route selection based on this value;

3.1.device \ charge \ order

Accept and process STR and pass str \ userId

EchoController.java

package com.ykc.edas;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
 
@RestController
public class EchoController {
    @Autowired
    private EchoFeign echoFeign;
 
    @RequestMapping(value = "/device", method = RequestMethod.GET)
    public String echo(@RequestParam(value="str", required = false) String str,
                       @RequestParam(value="userId", required = false) String userId){
        return echoFeign.echo(str + "device.v1111 -> ",userId);
    }
 
}

EchoFeign.java

package com.ykc.edas;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
 
@RestController
@FeignClient(name = "edas-test2.charge")
public interface EchoFeign {
 
    @RequestMapping(value = "/charge", method = RequestMethod.GET)
    String echo(@RequestParam(value="str", required = false) String str,
                @RequestParam(value="userId", required = false) String userId);
}

3.2.base

Return str and userId

EchoController.java

package com.ykc.edas;
import org.springframework.web.bind.annotation.*;
 
@RestController
public class EchoController {
    @RequestMapping(value = "/base", method = RequestMethod.GET)
    public String echo(@RequestParam(value = "str", required = false) String str,
                       @RequestParam(value = "userId", required = false) String userId)
    {
        return str + "base.v1111  (userId: " + userId + ")";
    }
}

3.3. Request and output

Request device service: http://172.16.1.192:30000/device?userId="xxx"
If the route is online version, return: device v1111 -> charge. v1111 --> order. v1111 --> base. v1111  (userId: xxx)
If the route is grayscale version, return: device v1111 -> charge. v2222 --> order. v2222 --> base. v1111  (userId: xxx)

4. Deployment and configuration

4.1. Install the pack MSE pilot

Create in the specified K8S cluster

After creation, create the namespace MSE pilot in K8S and create the MSE pilot service under the namespace

 4.2. Open "microservice governance" of the namespace where the service is located

Optional: enable microservice governance for all services under the namespace;
It does not need to be executed during production implementation. Start the configuration of individual applications one by one through the next step.

 4.3. Apply deployment configuration

The online version and grayscale version of the same service are independent deployment in K8S, corresponding to different deployment configurations

deployment adds three configurations
Production configuration:

Grayscale configuration:

After the application is published, run 6 independent deployment s in k8s

4.4.MSE configuration

4.4.1.MSE application list

Four applications are automatically generated in the MSE application list, and the production version and gray version of the same application are aggregated together.

4.4. 2. Create label routing rules

The service directly called by the traffic portal service needs to configure routing rules; On the contrary, it is not necessary, because routing rules can be "link delivery";
For example, the five services a, b, c, d and e have the following call chains:
a -> b -> c -> d -> e
a -> c -> d -> e
Then b and c services need to configure traffic rules, and d and e services do not need to be configured.

4.4. 3. Parameter types supported by routing rules

Routing parameter type:

  1. cookie
  2. header
  3. parameter
  4. body content

Routing parameter expression:

  • =
  • !=
  • >
  • >=
  • <
  • <=
  • in
  • percentage
  • Module 100

Expressions supported by modulo 100:

  • =
  • !=
  • >
  • >=
  • <
  • <=

The test case uses a mixture of parameter and header types:
Condition mode: meet any condition (another option is to meet all conditions)
Specific conditions:

  • parameter: userId in (111, 222, 333)
  • parameter: userId modulo 100 = 1
  • header parameters: MSE username in (msd01, msd02, msd03)

4.4. 4. Real time traffic comparison view

4.4. 5. Gray routing rules and percentage logic

5. Test

Requests with userids 111, 222, 333 are routed to the grayscale version

[root@iZbp1ckjqrnvsfle1x9kzdZ deployment]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId='111';echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 111)
[root@iZbp1ckjqrnvsfle1x9kzdZ deployment]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId='222';echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 222)
[root@iZbp1ckjqrnvsfle1x9kzdZ deployment]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId='333';echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 333)

Requests with userId modulo 100 = 1 will be routed to the grayscale version

[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId=101;echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 101)
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId=201;echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 201)
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId=1001;echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111  (userId: 1001)

Requests whose userId is not in the above range are routed to the production version

[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId=444;echo; done
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 444)
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device?userId=1002;echo; done
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: 1002)
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device;echo; done
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111  (userId: null)

Header: MSE username is in the rule range and is routed to the grayscale version

[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl -H "mse-username:msd01" http://172.16.1.192:30000/device;echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl -H "mse-username:msd02" http://172.16.1.192:30000/device;echo; done
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111
device.v1111 -> charge.v2222 --> order.v2222 --> base.v1111

Header: MSE username is not in the above range and is routed to the production version

[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl -H "mse-username:msd04" http://172.16.1.192:30000/device;echo; done
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
[root@iZbp1ckjqrnvsfle1x9kzdZ ~]# for i in {1..10}; do curl http://172.16.1.192:30000/device;echo; done
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111
device.v1111 -> charge.v1111 --> order.v1111 --> base.v1111

6. Implementation and risk of MSE label routing

Using Java agent technology, load the plug-in arms-bootstrap-1.7 0-SNAPSHOT. Jar to realize no intrusion into user code

In essence, Alibaba's SDK is implanted to distribute requests according to custom routing rules.
Alibaba cloud's reply on risks:

  • At present, many large customers have used MSE gray function;
  • As long as there is no compatibility problem in the test phase, there will be no risk in production;
  • The code realizes the emergency dynamic degradation ability, and the function degradation can be triggered by deleting the gray rule.

My supplementary:

  • The performance impact shall be pressure tested;
  • The worst way to reveal the risk is to remove the mse configuration from the deployment and trigger the application restart (msepilotauutoenable: 'on' is changed to 'off').

7. Gray publishing function landing

The change cost of the mse scheme to the existing environment (including R & D, operation and maintenance) is very small. After the implementation of the gray scheme, if you do not want to use gray or leave Alibaba cloud, the code does not need to be changed.

7.1. Changes on operation and maintenance side

1) Create components in K8S and create a container named MSE pilot;
2) For the business container to be opened, add notes to the deployment configuration:

  • msePilotAutoEnable: 'on'
  • msePilotCreateAppName: device / charge / order / base
  • alicloud.service.tag: prod/gray

3) For traffic entry services (such as pile service and gateway service), add environment variables to deployment configuration:
alicloud.service.header =  "mse-userId,mse-userName,mse-ipAddress,mse-deviceCode"

7.2. R & D side changes

Among the four parameters provided, the header is the most convenient: Alibaba cloud supports the header specified by the automatic transparent traffic portal service (the other three parameters need to be transmitted by the service itself).
The R & D needs to set the header in the traffic portal service, and other services do not need to be changed:
For example, set MSE devicecode in the gateway service and MSE userid, MSE username, MSE IPAddress, etc. in the gateway service.

Keywords: Kubernetes architecture Microservices

Added by jera on Sun, 02 Jan 2022 14:35:39 +0200