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