I like this proposal very much and think it will be the final form.
This function can be divided into two parts:
1.label &&  selector;
2. A grayscale upgrade configuration;
These two things can be done simultaneously.

1. Implement label && selector to replace the current upstream_id binding
relationship;
2. The configuration method of grayscale upgrade can be realized by a
plug-in version first.
After waiting for the label function to be implemented, the gray scale
capability is migrated to the native implementation in the apisix object.

The plug-in configuration is similar to this

```json
"plugins":{
    "routex": {
        "rules": [
            {
                "match": [
                    {
                        "vars": [
                            ["arg_user_id",">=",13],
                            ["arg_user_id","<=",133]
                        ]
                    },
                    {
                        "vars": [
                            ["arg_user_id","==",222]
                        ]
                    }
                ],
                "upstreams": [
                    {
                        "upstream_id": 3,
                        "weight": 20
                    },
                    {
                        "upstream_id": 5,
                        "weight": 80
                    }
                ]
            }
        ]
    }
}
```

YuanSheng Wang <[email protected]> 于2020年9月26日周六 下午5:25写道:

> wow, this is an interesting feature.
>
> It is very different from the current way.  I need time to understand it.
> ^_^
>
>
> On Fri, Sep 25, 2020 at 10:08 AM Zhang Chao <[email protected]> wrote:
>
> >
> > ### Background
> >
> > I observed the Pull Request https://github.com/apache/apisix/pull/2279
> > adds labels for `upstream` object, which inspires me that if we attach
> > labels for each node in `upstream`,  then we can implement fancy traffic
> > split feature.
> >
> > ### Design
> >
> > Traffic split, which means to setup several route rules and schedule
> > requests by respecting these rules to specified upstream (or a subset
> nodes
> > in a single upstream). With this feature, we can support the  Canary
> > Release (
> >
> https://martinfowler.com/bliki/CanaryRelease.html#:~:text=Canary%20release%20is%20a%20technique,making%20it%20available%20to%20everybody.
> ),
> > Blue Green Release (
> >
> https://docs.cloudfoundry.org/devguide/deploy-apps/blue-green.html#:~:text=Blue%2Dgreen%20deployment%20is%20a,live%20and%20Green%20is%20idle
> .)
> > for backend applications when they are releasing, it's useful to reduce
> the
> > downtime when something fault happens.
> >
> > But it's not a good idea to introduce these concepts into APISIX
> directly,
> > since features like Blue Green Release is closer to business, not the
> > infrastructure, so what we can do is introducing the concept traffic
> split
> > , to abstract all the business logics into the traffic split rules (route
> > rules), and it can be implemented as a plugin.
> >
> > Both the Istio and SMI (https://github.com/servicemeshinterface/smi-spec
> )
> > support traffic split by `VirtualService` and `TrafficSplit` CRD
> > respectively, although the latter is not perfect (at lease for now), we
> > still can be aware of the similarity between them.
> >
> > In general, we need two parts to define a traffic split rule, match and
> > route, the `match` defines the conditions that needed to judge wether a
> > request is eligible to apply the `route`, for instance, a `match` might
> be
> > "the method of HTTP request must be `GET`, and the parameter `id` must be
> > equal to `1006`. From APISIX's point of view, match conditions can be
> > scoped to HTTP, TLS, so conditions can vary, like URI, method, headers,
> SNI
> > and even other APISIX instance-scoped variables (hostname, env and etc).
> >
> > The APISIX Route already defines a fantastic match mechanism which is
> > similar with the traffic split. But that not means we don't need to embed
> > the match part in traffic split plugin, instead, we can reuse the match
> > mechanism in Route as it's own match mechanism to further split requests
> > that hit the same Route. See
> > https://github.com/api7/lua-resty-radixtree#new for more details about
> > Route match.
> >
> > The route, decides the ultimate upstream that a request will go, either
> > specifying the upstream name or with a label selector to filter an
> eligible
> > subset from that upstream. What's more, multiple upstreams can be
> > specified, each with a non-negative weight to support probabilistic
> > selection. For now, node in APISIX Upstream doesn't contain labels
> > attribute,  so we can implement it by the metadata map in node
> indirectly.
> >
> > ```json
> > # route requests to the nodes that has label release=canary in
> > fake_upstream,
> > {
> >     "route": [
> >         {
> >             "upstream_id": "1",
> >             "labels": {
> >                 "release": "canary"
> >             }
> >         }
> >     ]
> > }
> >
> > # route 75% requests to upstream 2 and other 25% to upstream 3.
> > {
> >     "route": [
> >         {
> >             "upstream_id": "2",
> >             "weight": 75
> >         },
> >         {
> >             "upstream_id": "3",
> >             "weight": 25
> >         }
> >     ]
> > }
> > ```
> >
> > The Route already contains an upstream, after introducing the traffic
> > split plugin, this upstream will be treated as the default upstream and
> > will be used when requests can not hit the route rules.
> >
> > ### Examples
> >
> > #### Weighted Blue Green Release
> >
> > Say we have two upstreams `app-blue` (id: 1) and `app-green` (id: 2),
> > which represent the old and new releases for `app` respectively. Now we
> > want to route 10% requests which UA is Android to `app-green`.
> >
> > ```json
> > [
> >     {
> >         "match": [
> >             {
> >                 "vars": [
> >                     [ "http_user_agent", "~~", "Android"]
> >                 ]
> >             }
> >         ],
> >         "route": [
> >             {
> >                 "upstream_id": 2,
> >                 "weight": 10
> >             }
> >         ]
> >     },
> >     {
> >         "route": [
> >             {
> >                 "upstream_id": 1,
> >                 "weight": 90
> >             }
> >         ]
> >     }
> > ]
> > ```
> >
> > #### Canary Release in a single upstream
> >
> > Say we updated a node in upstream `app` (id: 3), and this node have a
> > unique label `release=canary`, other nodes in `app` has label
> > `release=stable`, now we want to route requests which parameter `user_id`
> > is between [13, 133] to this node.
> >
> > ```json
> > [
> >     {
> >         "match": [
> >             {
> >                 "vars": [
> >                     [ "arg_user_id", ">=", 13],
> >                     [ "arg_user_id", "<=", 133]
> >                 ]
> >             }
> >         ],
> >         "route": [
> >             {
> >                 "upstream_id": 3,
> >                 "labels": "release=canary"
> >             }
> >         ]
> >     },
> >     {
> >         "route": [
> >             {
> >                 "upstream_id": 3,
> >                 "labels": "release=stable"
> >             }
> >         ]
> >     }
> > ]
> > ```
> >
> > ### References
> >
> > * VirtualService:
> > https://istio.io/latest/docs/reference/config/networking/virtual-service
> > * TrafficSplit:
> >
> https://github.com/servicemeshinterface/smi-spec/blob/master/apis/traffic-split/v1alpha3/traffic-split.md
> >
> >
> > Chao Zhang
> > [email protected]
> >
> >
> >
> >
>
> --
>
> *MembPhis*
> My GitHub: https://github.com/membphis
> Apache APISIX: https://github.com/apache/incubator-apisix
>

Reply via email to