mirror of
https://gitee.com/iresty/apisix.git
synced 2024-12-03 12:37:36 +08:00
feat: allow user-defined balancer with metadata in node (#4605)
This commit is contained in:
parent
1bd710db65
commit
e7d26dc4f0
@ -420,7 +420,6 @@ local upstream_schema = {
|
||||
type = {
|
||||
description = "algorithms of load balancing",
|
||||
type = "string",
|
||||
enum = {"chash", "roundrobin", "ewma", "least_conn"}
|
||||
},
|
||||
checks = health_checker,
|
||||
hash_on = {
|
||||
|
@ -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
|
||||
|
@ -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")`.
|
||||
|
||||
`hash_on` can be set to different types:
|
||||
|
||||
|
@ -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` 比较复杂,这里专门说明下:
|
||||
|
||||
|
9
t/admin/upstream.t
vendored
9
t/admin/upstream.t
vendored
@ -453,7 +453,7 @@ passed
|
||||
|
||||
|
||||
|
||||
=== TEST 13: invalid type
|
||||
=== TEST 13: unknown type
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
@ -465,7 +465,7 @@ passed
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "invalid_type"
|
||||
"type": "unknown"
|
||||
}]]
|
||||
)
|
||||
|
||||
@ -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]
|
||||
|
||||
|
33
t/node/invalid-upstream.t
vendored
33
t/node/invalid-upstream.t
vendored
@ -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 {
|
||||
@ -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 {
|
||||
|
95
t/node/upstream-discovery.t
vendored
95
t/node/upstream-discovery.t
vendored
@ -334,7 +334,100 @@ proxy request to 0.0.0.0:1980
|
||||
|
||||
|
||||
|
||||
=== TEST 7: bad nodes return by the discovery
|
||||
=== 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:
|
||||
|
||||
|
||||
|
||||
=== TEST 9: bad nodes return by the discovery
|
||||
--- apisix_yaml
|
||||
routes:
|
||||
-
|
||||
|
Loading…
Reference in New Issue
Block a user