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

feat: allow user-defined balancer with metadata in node #4605

Merged
merged 2 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@ local upstream_schema = {
type = {
description = "algorithms of load balancing",
type = "string",
enum = {"chash", "roundrobin", "ewma", "least_conn"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to test the behaviour when a non-user-defined algorithm is chosen

},
checks = health_checker,
hash_on = {
Expand Down
2 changes: 1 addition & 1 deletion apisix/utils/upstream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function _M.compare_upstream_node(up_conf, new_t)
for i = 1, #new_t do
local new_node = new_t[i]
local old_node = old_t[i]
for _, name in ipairs({"host", "port", "weight", "priority"}) do
for _, name in ipairs({"host", "port", "weight", "priority", "metadata"}) do
if new_node[name] ~= old_node[name] then
return false
end
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst
* `chash`: consistent hash
* `ewma`: pick one of node which has minimum latency. See https://en.wikipedia.org/wiki/EWMA_chart for details.
* `least_conn`: pick node which has the lowest `(active_conn + 1) / weight`. Note the `active connection` concept is the same with Nginx: it is a connection in used by a request.
* user-defined balancer which can be loaed via `require("apisix.balancer.your_balancer")`.
Yiyiyimu marked this conversation as resolved.
Show resolved Hide resolved

`hash_on` can be set to different types:

Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ APISIX 的 Upstream 除了基本的负载均衡算法选择外,还支持对上
- `chash`: 一致性哈希
- `ewma`: 选择延迟最小的节点,计算细节参考 https://en.wikipedia.org/wiki/EWMA_chart
- `least_conn`: 选择 `(active_conn + 1) / weight` 最小的节点。注意这里的 `active connection` 概念跟 Nginx 的相同:它是当前正在被请求使用的连接。
- 用户自定义的 balancer,需要可以通过 `require("apisix.balancer.your_balancer")` 来加载。

`hash_on` 比较复杂,这里专门说明下:

Expand Down
9 changes: 4 additions & 5 deletions t/admin/upstream.t
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ passed



=== TEST 13: invalid type
=== TEST 13: unknown type
--- config
location /t {
content_by_lua_block {
Expand All @@ -465,7 +465,7 @@ passed
"nodes": {
"127.0.0.1:8080": 1
},
"type": "invalid_type"
"type": "unknown"
}]]
)

Expand All @@ -475,9 +475,8 @@ passed
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"type\" validation failed: matches none of the enum values"}
--- response_body chomp
passed
--- no_error_log
[error]

Expand Down
33 changes: 2 additions & 31 deletions t/node/invalid-upstream.t
Original file line number Diff line number Diff line change
Expand Up @@ -89,36 +89,7 @@ passed



=== TEST 4: invalid upstream(wrong type)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/upstreams/1',
ngx.HTTP_PUT,
[[{
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin_invalid"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.print(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body
{"error_msg":"invalid configuration: property \"type\" validation failed: matches none of the enum values"}



=== TEST 5: set valid upstream(id: 1)
=== TEST 4: set valid upstream(id: 1)
--- config
location /t {
content_by_lua_block {
Expand All @@ -145,7 +116,7 @@ qr/"nodes":\{"127.0.0.1:1980":1\}/



=== TEST 6: no error log
=== TEST 5: no error log
--- config
location /t {
content_by_lua_block {
Expand Down
93 changes: 93 additions & 0 deletions t/node/upstream-discovery.t
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,96 @@ qr/proxy request to \S+/
--- grep_error_log_out
proxy request to 127.0.0.1:1979
proxy request to 0.0.0.0:1980



=== TEST 7: create new server picker when metadata change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = {a = 1}},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = {}},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)

discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = {a = 1}},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = {b = 1}},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes:
create_obj_fun(): upstream nodes:



=== TEST 8: don't create new server picker when metadata doesn't change
--- apisix_yaml
routes:
-
uris:
- /hello
upstream_id: 1
--- config
location /t {
content_by_lua_block {
local discovery = require("apisix.discovery.init").discovery
local meta1 = {a = 1}
local meta2 = {b = 2}
discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = meta1},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = meta2},
}
end
}
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
ngx.say(res.status)

discovery.mock = {
nodes = function()
return {
{host = "127.0.0.1", port = 1980, weight = 1, metadata = meta1},
{host = "0.0.0.0", port = 1980, weight = 1, metadata = meta2},
}
end
}
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local httpc = http.new()
local res, err = httpc:request_uri(uri, {method = "GET", keepalive = false})
}
}
--- grep_error_log eval
qr/create_obj_fun\(\): upstream nodes:/
--- grep_error_log_out
create_obj_fun(): upstream nodes: