Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request help: Correspondence between matched rules and upstreams within one route #4090

Closed
Ben0625 opened this issue Apr 20, 2021 · 9 comments

Comments

@Ben0625
Copy link
Contributor

Ben0625 commented Apr 20, 2021

Request:

Set just one route and the path is "/test".
Set correspondence between many matched rules and upstreams. For example:

if args_id == 1, choose upstream A
if args_id == 2, choose upstream B
if args_id == 3, choose upstream C
......

For now, if I have 10 correspondence, I have to create 10 routes with the same path "/test". Then set one correspondence for each route.
I check traffic-split plugin, it works well for 2 upstreams, but it doesn't seem to match more than 2 correspondence.

Is it possible to set just one route and have multiple correspondence as Request describes?

@Ben0625 Ben0625 changed the title Correspondence between matched rules and upstreams within one route Request help: Correspondence between matched rules and upstreams within one route Apr 20, 2021
@spacewander
Copy link
Member

spacewander commented Apr 21, 2021

You can write your own plugin like traffic-split.

Look like the rules in traffic-split is an array, so you can use it with multiple upstream but not just for 2.

@Firstsawyou
Copy link
Contributor

You can try the traffic-split plug-in. Here is an example of configuration:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/hello",
    "plugins": {
        "traffic-split": {
            "rules": [
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","1"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                },
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","2"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_B",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1982":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

However, it may not take effect in APISIX 2.5. You can try it in versions before 2.5.

@Ben0625
Copy link
Contributor Author

Ben0625 commented Apr 21, 2021

You can try the traffic-split plug-in. Here is an example of configuration:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/hello",
    "plugins": {
        "traffic-split": {
            "rules": [
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","1"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1981":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                },
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","2"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_B",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1982":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

However, it may not take effect in APISIX 2.5. You can try it in versions before 2.5.

I modify some input args at Line 281 of traffic-spllit.lua and try it in version 2.0 and there exist a bug. When I first send a request with "id = 1", it correctly chooses upstream_A. But after that, no matter what I send with "id = 1" or "id = 2", it always chooses upstream_A and never chooses upstream_B.

Then I reload APISIX, this time I first send a request with "id = 2", it correctly chooses upstream_B. Then if I request with "id = 1" or "id = 2", it always chooses upstream_B.

It seems that the problem is at Line 281 and Line 288 of traffic-split.lua

local rr_up, err = core.lrucache.plugin_ctx(plugin_name, ctx, new_rr_obj, weighted_upstreams)
local upstream = rr_up:find()

I print the log to see weighted_upstreams before Line 281 and it is correct. But Line 288 does not give the right output.

@Firstsawyou
Copy link
Contributor

I modify some input args at Line 281 of traffic-spllit.lua and try it in version 2.0 and there exist a bug. When I first send a request with "id = 1", it correctly chooses upstream_A. But after that, no matter what I send with "id = 1" or "id = 2", it always chooses upstream_A and never chooses upstream_B.

Then I reload APISIX, this time I first send a request with "id = 2", it correctly chooses upstream_B. Then if I request with "id = 1" or "id = 2", it always chooses upstream_B.

It seems that the problem is at Line 281 and Line 288 of traffic-split.lua

local rr_up, err = core.lrucache.plugin_ctx(plugin_name, ctx, new_rr_obj, weighted_upstreams)
local upstream = rr_up:find()

I print the log to see weighted_upstreams before Line 281 and it is correct. But Line 288 does not give the right output.

Yes, this is a known bug. If you want to implement this function in APISIX 2.5, you can refer to the following PR to modify the traffic-split.lua code.
https://github.com/apache/apisix/pull/4092/files#diff-95a2018f002f15f5fb0714075b5ef27a1db113c186bfe20ae705f6023080b38fL280-L283

@Ben0625
Copy link
Contributor Author

Ben0625 commented Apr 21, 2021

Since I use APISIX 2.0 before, I try your change at APISIX 2.0 and it works!
local rr_up, err = lrucache(weighted_upstreams, nil, new_rr_obj, weighted_upstreams)
Good job! @Firstsawyou

@Ben0625 Ben0625 closed this as completed Apr 21, 2021
@Ben0625
Copy link
Contributor Author

Ben0625 commented May 20, 2021

I find a new bug here:
When I set 2 nodes in "upstream.nodes" attribute for 2 rules, something unexpected happens.

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/hello",
    "plugins": {
        "traffic-split": {
            "rules": [
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","1"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_A",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1980":1,
                                    "127.0.0.1:1981":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                },
                {
                    "match": [
                        {
                            "vars": [
                                ["http_id","==","2"]
                            ]
                        }
                    ],
                    "weighted_upstreams": [
                        {
                            "upstream": {
                                "name": "upstream_B",
                                "type": "roundrobin",
                                "nodes": {
                                    "127.0.0.1:1982":1,
                                    "127.0.0.1:1983":1
                                }
                            },
                            "weight": 3
                        }
                    ]
                }
            ]
        }
    },
    "upstream": {
            "type": "roundrobin",
            "nodes": {
                "127.0.0.1:1980": 1
            }
    }
}'

Reproduce steps:

  1. Request with id=1 for several times
  2. Request with id=2 for several times

Then you will see nodes of upstream_A be picked when requesting with id = 2 for some time. It looks messed up.

@Ben0625 Ben0625 reopened this May 20, 2021
@Firstsawyou
Copy link
Contributor

Reproduce steps:

  1. Request with id=1 for several times
  2. Request with id=2 for several times

Then you will see nodes of upstream_A be picked when requesting with id = 2 for some time. It looks messed up.

This scenario has been covered by test cases, please see here: https://github.com/apache/apisix/blob/master/t/plugin/traffic-split2.t#L513-L613
By the way, what is your APISIX version?

@Ben0625
Copy link
Contributor Author

Ben0625 commented May 20, 2021

This scenario has been covered by test cases, please see here: https://github.com/apache/apisix/blob/master/t/plugin/traffic-split2.t#L513-L613
By the way, what is your APISIX version?

My APISIX version is 2.0. I modify a little bit (At Line 194) to let this plugin run successfully.
upstream.set(ctx, upstream_key, ctx.conf_version, up_conf, matched_route)
This test case you mention works good for me too, but what I want to point out is the number of "upstream.nodes" attribute

"nodes": {
"127.0.0.1:1980":1,
"127.0.0.1:1981":1
}
"nodes": {
"127.0.0.1:1982":1,
"127.0.0.1:1983":1
}

I set 2 nodes instead of 1 and run the Reproduce steps. Then it messed up.

@Firstsawyou
Copy link
Contributor

My APISIX version is 2.0. I modify a little bit (At Line 194) to let this plugin run successfully.
upstream.set(ctx, upstream_key, ctx.conf_version, up_conf, matched_route)
This test case you mention works good for me too, but what I want to point out is the number of "upstream.nodes" attribute

The number of upstream nodes is not affected. There are many bug fixes between APISIX 2.0 and APISIX 2.5. You should upgrade to version 2.5 and try again.

@Ben0625 Ben0625 closed this as completed May 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants