From 2d746533ada10561b71a0e97fd647f8692aee636 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 7 Jul 2021 23:24:57 +0800 Subject: [PATCH 01/35] feat Request-ID plugin adds Snowflake algorithm --- apisix/plugins/request-id.lua | 171 ++++++++++++++++++++++-- t/plugin/request-id.t | 242 ++++++++++++++++++++++++++++++++++ 2 files changed, 404 insertions(+), 9 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 79b8b183dad1..a7691c805eb3 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -14,36 +14,160 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -local core = require("apisix.core") -local plugin_name = "request-id" -local ngx = ngx -local uuid = require("resty.jit-uuid") + +local ngx = ngx +local bit = require("bit") +local core = require("apisix.core") +local snowflake = require("snowflake") +local uuid = require("resty.jit-uuid") +local process = require("ngx.process") +local tostring = tostring +local math_pow = math.pow + +local plugin_name = "request-id" + +local worker_number = nil +local snowflake_init = nil + +local attr = nil local schema = { type = "object", properties = { header_name = {type = "string", default = "X-Request-Id"}, - include_in_response = {type = "boolean", default = true} + include_in_response = {type = "boolean", default = true}, + algorithm = {type = "string", enum = {"uuid", "snowflake"}, default = "uuid"} } } +local attr_schema = { + type = "object", + properties = { + snowflake = { + type = "object", + properties = { + enable = {type = "boolean"}, + snowflake_epoc = {type = "integer", minimum = 1, default = 1609459200000}, + node_id_bits = {type = "integer", minimum = 1, default = 5}, + sequence_bits = {type = "integer", minimum = 1, default = 10}, + datacenter_id_bits = {type = "integer", minimum = 1, default = 5}, + worker_number_ttl = {type = "integer", minimum = 1, default = 30}, + worker_number_interval = {type = "integer", minimum = 1, default = 10} + } + } + } +} local _M = { version = 0.1, priority = 11010, name = plugin_name, - schema = schema, + schema = schema } - function _M.check_schema(conf) return core.schema.check(schema, conf) end +local function gen_worker_number(max_number) + if worker_number == nil then + local etcd_cli, prefix = core.etcd.new() + local res, _ = etcd_cli:grant(attr.snowflake.worker_number_ttl) + + local prefix = prefix .. "/plugins/request-id/snowflake/" + local uuid = uuid.generate_v4() + local id = 1 + while (id <= max_number) do + ::continue:: + local _, err1 = etcd_cli:setnx(prefix .. tostring(id), uuid) + local res2, err2 = etcd_cli:get(prefix .. tostring(id)) + + if err1 or err2 or res2.body.kvs[1].value ~= uuid then + core.log.notice("worker_number " .. id .. " is not available") + id = id + 1 + else + worker_number = id + + local _, err3 = + etcd_cli:set( + prefix .. tostring(id), + uuid, + { + prev_kv = true, + lease = res.body.ID + } + ) + + if err3 then + id = id + 1 + etcd_cli:delete(prefix .. tostring(id)) + core.log.error("set worker_number " .. id .. " lease error: " .. err3) + goto continue + end + + local handler = function(premature, etcd_cli, lease_id) + local _, err4 = etcd_cli:keepalive(lease_id) + if err4 then + snowflake_init = nil + worker_number = nil + core.log.error("snowflake worker_number lease faild.") + end + core.log.info("snowflake worker_number lease success.") + end + ngx.timer.every(attr.snowflake.worker_number_interval, handler, etcd_cli, res.body.ID) + + core.log.notice("snowflake worker_number: " .. id) + break + end + end + + if worker_number == nil then + core.log.error("No worker_number is not available") + return nil + end + end + return worker_number +end + +local function split_worker_number(worker_number, node_id_bits, datacenter_id_bits) + local num = bit.tobit(worker_number) + local worker_id = bit.band(num, math_pow(2, node_id_bits) - 1) + 1 + num = bit.rshift(num, node_id_bits) + local datacenter_id = bit.band(num, math_pow(2, datacenter_id_bits) - 1) + 1 + return worker_id, datacenter_id +end + +local function next_id() + if snowflake_init == nil then + local max_number = math_pow(2, (attr.snowflake.node_id_bits + attr.snowflake.datacenter_id_bits)) + worker_number = gen_worker_number(max_number) + if worker_number == nil then + return "" + end + local worker_id, datacenter_id = + split_worker_number(worker_number, attr.snowflake.node_id_bits, attr.snowflake.datacenter_id_bits) + core.log.notice("snowflake init datacenter_id: " .. datacenter_id .. " worker_id: " .. worker_id) + snowflake.init( + worker_id, + datacenter_id, + attr.snowflake.snowflake_epoc, + attr.snowflake.node_id_bits, + attr.snowflake.datacenter_id_bits, + attr.snowflake.sequence_bits + ) + snowflake_init = true + end + return snowflake:next_id() +end function _M.rewrite(conf, ctx) local headers = ngx.req.get_headers() - local uuid_val = uuid() + local uuid_val + if conf.algorithm == "uuid" then + uuid_val = uuid() + else + uuid_val = next_id() + end if not headers[conf.header_name] then core.request.set_header(ctx, conf.header_name, uuid_val) end @@ -53,7 +177,6 @@ function _M.rewrite(conf, ctx) end end - function _M.header_filter(conf, ctx) if not conf.include_in_response then return @@ -65,4 +188,34 @@ function _M.header_filter(conf, ctx) end end +function _M.init() + local local_conf = core.config.local_conf() + attr = core.table.try_read_attr(local_conf, "plugin_attr", plugin_name) + local ok, err = core.schema.check(attr_schema, attr) + if not ok then + core.log.error("failed to check the plugin_attr[", plugin_name, "]", ": ", err) + return + end + if attr.snowflake.enable then + if process.type() == "worker" then + ngx.timer.at(0, next_id) + end + end +end + +function _M.api() + return { + { + methods = {"GET"}, + uri = "/apisix/plugin/request_id/uuid", + handler = uuid + }, + { + methods = {"GET"}, + uri = "/apisix/plugin/request_id/snowflake", + handler = next_id + } + } +end + return _M diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index 5fadc447738e..ecc25daf60da 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -470,3 +470,245 @@ GET /t X-Request-Id and Custom-Header-Name are different --- no_error_log [error] + + + +=== TEST 12: check for snowflake id +--- yaml_config +plugins: + - request-id +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1609459200000 + node_id_bits: 5 + sequence_bits: 5 + datacenter_id_bits: 10 + worker_number_ttl: 30 + worker_number_interval: 10 +--- config +location /t { + content_by_lua_block { + ngx.sleep(3) + local core = require("apisix.core") + local key = "/plugins/request-id/snowflake/1" + local res, err = core.etcd.get(key) + if err ~= nil then + ngx.status = 500 + ngx.say(err) + return + end + if res.body.node.key ~= "/apisix/plugins/request-id/snowflake/1" then + ngx.say(core.json.encode(res.body.node)) + end + ngx.say("ok") + } +} +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] + + + +=== TEST 13: check to get snowflake_id interface +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, err, id = t('/apisix/plugin/request_id/snowflake_id', + ngx.HTTP_GET + ) + if code > 200 then + ngx.status = code + ngx.say(err) + return + end + ngx.status = code + } + } +--- request +GET /t +--- response_body +--- no_error_log +[error] + + + +=== TEST 14: check to get uuid interface +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, err, id = t('/apisix/plugin/request_id/uuid', + ngx.HTTP_GET + ) + if code > 200 then + ngx.status = code + ngx.say(err) + return + end + ngx.status = code + } + } +--- request +GET /t +--- response_body +--- no_error_log +[error] + + + +=== TEST 15: check to get snowflake interface +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, err, id = t('/apisix/plugin/request_id/snowflake', + ngx.HTTP_GET + ) + if code > 200 then + ngx.status = code + ngx.say(err) + return + end + ngx.status = code + } + } +--- request +GET /t +--- response_body +--- no_error_log +[error] + + +=== TEST 16: wrong type +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.request-id") + local ok, err = plugin.check_schema({algorithm = "bad_algorithm"}) + if not ok then + ngx.say(err) + end + ngx.say("done") + } + } +--- request +GET /t +--- response_body +property "algorithm" validation failed: matches none of the enum values +done +--- no_error_log +[error] + + + +=== TEST 17: add plugin with algorithm snowflake (default uuid) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "request-id": { + "algorithm": "snowflake" + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/opentracing" + }]], + [[{ + "node": { + "value": { + "plugins": { + "request-id": { + "algorithm": "snowflake" + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/opentracing" + }, + "key": "/apisix/routes/1" + }, + "action": "set" + }]] + ) + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 18: check for snowflake id +--- config + location /t { + content_by_lua_block { + local http = require "resty.http" + local t = {} + local ids = {} + for i = 1, 180 do + local th = assert(ngx.thread.spawn(function() + local httpc = http.new() + local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/opentracing" + local res, err = httpc:request_uri(uri, + { + method = "GET", + headers = { + ["Content-Type"] = "application/json", + } + } + ) + if not res then + ngx.log(ngx.ERR, err) + return + end + local id = res.headers["X-Request-Id"] + if not id then + return -- ignore if the data is not synced yet. + end + if ids[id] == true then + ngx.say("ids not unique") + return + end + ids[id] = true + end, i)) + table.insert(t, th) + end + for i, th in ipairs(t) do + ngx.thread.wait(th) + end + ngx.say("true") + } + } +--- request +GET /t +--- wait: 5 +--- response_body +true +--- no_error_log +[error] \ No newline at end of file From ce66bfbc1a1f4c362f4bd418246575dc970b4ea2 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 7 Jul 2021 23:31:55 +0800 Subject: [PATCH 02/35] fixed no newline at end of file --- t/plugin/request-id.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index ecc25daf60da..eb4392cf0886 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -711,4 +711,4 @@ GET /t --- response_body true --- no_error_log -[error] \ No newline at end of file +[error] From c3529cc421cc1434415882505a343bff97039099 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 7 Jul 2021 23:43:21 +0800 Subject: [PATCH 03/35] feat Request-ID plugin adds Snowflake algorithm --- rockspec/apisix-master-0.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec index f9d73da0224d..20bfa119e12a 100644 --- a/rockspec/apisix-master-0.rockspec +++ b/rockspec/apisix-master-0.rockspec @@ -67,6 +67,7 @@ dependencies = { "lua-resty-consul = 0.3-2", "penlight = 1.9.2-1", "ext-plugin-proto = 0.1.1", + "api7-snowflake = 2.0-1", } build = { From 1ca0f464205d6f9a2471f7e425889d7099d66182 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 7 Jul 2021 23:46:09 +0800 Subject: [PATCH 04/35] sytle line is to long --- apisix/plugins/request-id.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index a7691c805eb3..f7492b0c5de2 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -114,7 +114,8 @@ local function gen_worker_number(max_number) end core.log.info("snowflake worker_number lease success.") end - ngx.timer.every(attr.snowflake.worker_number_interval, handler, etcd_cli, res.body.ID) + ngx.timer.every(attr.snowflake.worker_number_interval, + handler, etcd_cli, res.body.ID) core.log.notice("snowflake worker_number: " .. id) break @@ -139,14 +140,16 @@ end local function next_id() if snowflake_init == nil then - local max_number = math_pow(2, (attr.snowflake.node_id_bits + attr.snowflake.datacenter_id_bits)) + local max_number = math_pow(2, (attr.snowflake.node_id_bits + + attr.snowflake.datacenter_id_bits)) worker_number = gen_worker_number(max_number) if worker_number == nil then return "" end - local worker_id, datacenter_id = - split_worker_number(worker_number, attr.snowflake.node_id_bits, attr.snowflake.datacenter_id_bits) - core.log.notice("snowflake init datacenter_id: " .. datacenter_id .. " worker_id: " .. worker_id) + local worker_id, datacenter_id = split_worker_number(worker_number, + attr.snowflake.node_id_bits, attr.snowflake.datacenter_id_bits) + core.log.notice("snowflake init datacenter_id: " .. + datacenter_id .. " worker_id: " .. worker_id) snowflake.init( worker_id, datacenter_id, From c239679e42c1e10b0c660bb587e0608a4ee470e5 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 00:31:34 +0800 Subject: [PATCH 05/35] fixed default config --- conf/config-default.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/conf/config-default.yaml b/conf/config-default.yaml index eedf77febdfa..f8c5933a6c65 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -136,7 +136,13 @@ nginx_config: # config for render the template to generate n # if you're not root user,the default is current user. error_log: "logs/error.log" error_log_level: "warn" # warn,error +<<<<<<< Updated upstream worker_processes: auto # if you want use multiple cores in container, you can inject the number of cpu as environment variable "APISIX_WORKER_PROCESSES" +======= + worker_processes: 17 # one worker will get best performance, you can use "auto", but remember it is just work well only on physical machine + # no more than 8 workers, otherwise competition between workers will consume a lot of resources + # if you want use multiple cores in container, you can inject the number of cpu as environment variable "APISIX_WORKER_PROCESSES" +>>>>>>> Stashed changes enable_cpu_affinity: true # enable cpu affinity, this is just work well only on physical machine worker_rlimit_nofile: 20480 # the number of files a worker process can open, should be larger than worker_connections worker_shutdown_timeout: 240s # timeout for a graceful shutdown of worker processes @@ -316,3 +322,12 @@ plugin_attr: report_ttl: 3600 # live time for server info in etcd (unit: second) dubbo-proxy: upstream_multiplex_count: 32 + request-id: + snowflake: + enable: true + snowflake_epoc: 1609459200000 + node_id_bits: 5 + sequence_bits: 5 + datacenter_id_bits: 10 + worker_number_ttl: 30 + worker_number_interval: 10 From da2370e101419559cae7e2711efa291f20acf61f Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 00:42:10 +0800 Subject: [PATCH 06/35] fixed conflict --- conf/config-default.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/conf/config-default.yaml b/conf/config-default.yaml index f8c5933a6c65..7d6d89bd7b94 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -136,13 +136,7 @@ nginx_config: # config for render the template to generate n # if you're not root user,the default is current user. error_log: "logs/error.log" error_log_level: "warn" # warn,error -<<<<<<< Updated upstream worker_processes: auto # if you want use multiple cores in container, you can inject the number of cpu as environment variable "APISIX_WORKER_PROCESSES" -======= - worker_processes: 17 # one worker will get best performance, you can use "auto", but remember it is just work well only on physical machine - # no more than 8 workers, otherwise competition between workers will consume a lot of resources - # if you want use multiple cores in container, you can inject the number of cpu as environment variable "APISIX_WORKER_PROCESSES" ->>>>>>> Stashed changes enable_cpu_affinity: true # enable cpu affinity, this is just work well only on physical machine worker_rlimit_nofile: 20480 # the number of files a worker process can open, should be larger than worker_connections worker_shutdown_timeout: 240s # timeout for a graceful shutdown of worker processes From f2f9cc0f95e79405e032afb097644d05bc10b56e Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 00:55:42 +0800 Subject: [PATCH 07/35] fixed lint --- t/plugin/request-id.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index eb4392cf0886..77f8ff80dcc7 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -585,6 +585,7 @@ GET /t [error] + === TEST 16: wrong type --- config location /t { From 1b8565e2460ea2add9b961ab4f1ef1f31d497092 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 11:32:34 +0800 Subject: [PATCH 08/35] fixed ci --- t/plugin/request-id.t | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index 77f8ff80dcc7..ec7a2347278a 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -514,12 +514,12 @@ ok -=== TEST 13: check to get snowflake_id interface +=== TEST 13: check to get snowflake interface --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, id = t('/apisix/plugin/request_id/snowflake_id', + local code, err, id = t('/apisix/plugin/request_id/snowflake', ngx.HTTP_GET ) if code > 200 then @@ -562,31 +562,7 @@ GET /t -=== TEST 15: check to get snowflake interface ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, id = t('/apisix/plugin/request_id/snowflake', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - ngx.status = code - } - } ---- request -GET /t ---- response_body ---- no_error_log -[error] - - - -=== TEST 16: wrong type +=== TEST 15: wrong type --- config location /t { content_by_lua_block { @@ -608,7 +584,7 @@ done -=== TEST 17: add plugin with algorithm snowflake (default uuid) +=== TEST 16: add plugin with algorithm snowflake (default uuid) --- config location /t { content_by_lua_block { @@ -665,7 +641,7 @@ passed -=== TEST 18: check for snowflake id +=== TEST 17: check for snowflake id --- config location /t { content_by_lua_block { From bdf46f4f9fa901e71dfadede2121b2d0c46dc7c5 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 17:21:41 +0800 Subject: [PATCH 09/35] fixed test case --- apisix/plugins/request-id.lua | 23 ++++++++++++++++++----- conf/config-default.yaml | 2 +- t/plugin/request-id.t | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index f7492b0c5de2..cf60e7319955 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -207,18 +207,31 @@ function _M.init() end function _M.api() - return { + local api = { { methods = {"GET"}, uri = "/apisix/plugin/request_id/uuid", handler = uuid - }, - { + } + } + + local local_conf = core.config.local_conf() + attr = core.table.try_read_attr(local_conf, "plugin_attr", plugin_name) + local ok, err = core.schema.check(attr_schema, attr) + if not ok then + core.log.error("failed to check the plugin_attr[", plugin_name, "]", ": ", err) + return + end + + if attr.snowflake.enable then + core.table.insert(api, { methods = {"GET"}, uri = "/apisix/plugin/request_id/snowflake", handler = next_id - } - } + }) + end + + return api end return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 7d6d89bd7b94..3f6f9fd506a4 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -318,7 +318,7 @@ plugin_attr: upstream_multiplex_count: 32 request-id: snowflake: - enable: true + enable: false snowflake_epoc: 1609459200000 node_id_bits: 5 sequence_bits: 5 diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index ec7a2347278a..b2d7876b664e 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -515,6 +515,13 @@ ok === TEST 13: check to get snowflake interface +--- yaml_config +plugins: + - request-id +plugin_attr: + request-id: + snowflake: + enable: true --- config location /t { content_by_lua_block { @@ -642,6 +649,13 @@ passed === TEST 17: check for snowflake id +--- yaml_config +plugins: + - request-id +plugin_attr: + request-id: + snowflake: + enable: true --- config location /t { content_by_lua_block { @@ -689,3 +703,22 @@ GET /t true --- no_error_log [error] + + + +=== TEST 18: check to get snowflake interface +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, err, id = t('/apisix/plugin/request_id/snowflake', + ngx.HTTP_GET + ) + ngx.status = code + } + } +--- request +GET /t +--- error_code: 404 +--- no_error_log +[error] \ No newline at end of file From d0953012f906718d54d734f01e44e604c528a43a Mon Sep 17 00:00:00 2001 From: dickens7 Date: Thu, 8 Jul 2021 17:28:01 +0800 Subject: [PATCH 10/35] fixed no newline at end of file --- t/plugin/request-id.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index b2d7876b664e..6dfb563e07b3 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -721,4 +721,4 @@ true GET /t --- error_code: 404 --- no_error_log -[error] \ No newline at end of file +[error] From 1245d9fe095bdbc70657789cc3c1423a2cb8b24b Mon Sep 17 00:00:00 2001 From: dickens7 Date: Sat, 10 Jul 2021 21:45:28 +0800 Subject: [PATCH 11/35] optimied: Split function --- apisix/plugins/request-id.lua | 43 +++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index cf60e7319955..671b4870d6d2 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -27,7 +27,7 @@ local math_pow = math.pow local plugin_name = "request-id" local worker_number = nil -local snowflake_init = nil +local snowflake_inited = nil local attr = nil @@ -65,10 +65,13 @@ local _M = { schema = schema } + function _M.check_schema(conf) return core.schema.check(schema, conf) end + +-- Generates the current process worker number local function gen_worker_number(max_number) if worker_number == nil then local etcd_cli, prefix = core.etcd.new() @@ -108,7 +111,7 @@ local function gen_worker_number(max_number) local handler = function(premature, etcd_cli, lease_id) local _, err4 = etcd_cli:keepalive(lease_id) if err4 then - snowflake_init = nil + snowflake_inited = nil worker_number = nil core.log.error("snowflake worker_number lease faild.") end @@ -130,6 +133,8 @@ local function gen_worker_number(max_number) return worker_number end + +-- Split 'Worker Number' into 'Worker ID' and 'datacenter ID' local function split_worker_number(worker_number, node_id_bits, datacenter_id_bits) local num = bit.tobit(worker_number) local worker_id = bit.band(num, math_pow(2, node_id_bits) - 1) + 1 @@ -138,8 +143,10 @@ local function split_worker_number(worker_number, node_id_bits, datacenter_id_bi return worker_id, datacenter_id end -local function next_id() - if snowflake_init == nil then + +-- Initialize the snowflake algorithm +local function snowflake_init() + if snowflake_inited == nil then local max_number = math_pow(2, (attr.snowflake.node_id_bits + attr.snowflake.datacenter_id_bits)) worker_number = gen_worker_number(max_number) @@ -158,19 +165,31 @@ local function next_id() attr.snowflake.datacenter_id_bits, attr.snowflake.sequence_bits ) - snowflake_init = true + snowflake_inited = true + end +end + + +-- generate snowflake id +local function next_id() + if snowflake_inited == nil then + snowflake_init() end return snowflake:next_id() end + +local function get_request_id(algorithm) + if algorithm == "uuid" then + return uuid() + end + return next_id() +end + + function _M.rewrite(conf, ctx) local headers = ngx.req.get_headers() - local uuid_val - if conf.algorithm == "uuid" then - uuid_val = uuid() - else - uuid_val = next_id() - end + local uuid_val = get_request_id(conf.algorithm) if not headers[conf.header_name] then core.request.set_header(ctx, conf.header_name, uuid_val) end @@ -201,7 +220,7 @@ function _M.init() end if attr.snowflake.enable then if process.type() == "worker" then - ngx.timer.at(0, next_id) + ngx.timer.at(0, snowflake_init) end end end From 89cdec096159be4fdd8e2152fe4bc8d5c0b6bdc2 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Sat, 10 Jul 2021 23:18:04 +0800 Subject: [PATCH 12/35] optimized: use apisix.timers --- apisix/plugins/request-id.lua | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 671b4870d6d2..7a2ca090726c 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -21,6 +21,7 @@ local core = require("apisix.core") local snowflake = require("snowflake") local uuid = require("resty.jit-uuid") local process = require("ngx.process") +local timers = require("apisix.timers") local tostring = tostring local math_pow = math.pow @@ -75,13 +76,12 @@ end local function gen_worker_number(max_number) if worker_number == nil then local etcd_cli, prefix = core.etcd.new() - local res, _ = etcd_cli:grant(attr.snowflake.worker_number_ttl) - local prefix = prefix .. "/plugins/request-id/snowflake/" local uuid = uuid.generate_v4() local id = 1 while (id <= max_number) do ::continue:: + local res, _ = etcd_cli:grant(attr.snowflake.worker_number_ttl) local _, err1 = etcd_cli:setnx(prefix .. tostring(id), uuid) local res2, err2 = etcd_cli:get(prefix .. tostring(id)) @@ -108,19 +108,28 @@ local function gen_worker_number(max_number) goto continue end - local handler = function(premature, etcd_cli, lease_id) + local lease_id = res.body.ID + local start_at = ngx.time() + local handler = function() + local now = ngx.time() + if now - start_at < attr.snowflake.worker_number_interval then + return + end + local _, err4 = etcd_cli:keepalive(lease_id) if err4 then snowflake_inited = nil worker_number = nil - core.log.error("snowflake worker_number lease faild.") + core.log.error("snowflake worker_number: " .. id .." lease faild.") end - core.log.info("snowflake worker_number lease success.") + start_at = now + core.log.info("snowflake worker_number: " .. id .." lease success.") end - ngx.timer.every(attr.snowflake.worker_number_interval, - handler, etcd_cli, res.body.ID) - core.log.notice("snowflake worker_number: " .. id) + timers.register_timer("plugin#request-id", handler) + core.log.info("timer created to lease snowflake algorithm worker number, interval: ", + attr.snowflake.worker_number_interval) + core.log.notice("lease snowflake worker_number: " .. id) break end end @@ -225,6 +234,7 @@ function _M.init() end end + function _M.api() local api = { { From 428cb0892b65e845853901cc17d454ec1b5e5421 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Sun, 11 Jul 2021 00:03:21 +0800 Subject: [PATCH 13/35] remove: api --- apisix/plugins/request-id.lua | 33 ++------------ conf/config-default.yaml | 4 +- t/plugin/request-id.t | 84 +++-------------------------------- 3 files changed, 10 insertions(+), 111 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 7a2ca090726c..cacc4d6c05d3 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -115,7 +115,7 @@ local function gen_worker_number(max_number) if now - start_at < attr.snowflake.worker_number_interval then return end - + local _, err4 = etcd_cli:keepalive(lease_id) if err4 then snowflake_inited = nil @@ -127,7 +127,8 @@ local function gen_worker_number(max_number) end timers.register_timer("plugin#request-id", handler) - core.log.info("timer created to lease snowflake algorithm worker number, interval: ", + core.log.info( + "timer created to lease snowflake algorithm worker number, interval: ", attr.snowflake.worker_number_interval) core.log.notice("lease snowflake worker_number: " .. id) break @@ -235,32 +236,4 @@ function _M.init() end -function _M.api() - local api = { - { - methods = {"GET"}, - uri = "/apisix/plugin/request_id/uuid", - handler = uuid - } - } - - local local_conf = core.config.local_conf() - attr = core.table.try_read_attr(local_conf, "plugin_attr", plugin_name) - local ok, err = core.schema.check(attr_schema, attr) - if not ok then - core.log.error("failed to check the plugin_attr[", plugin_name, "]", ": ", err) - return - end - - if attr.snowflake.enable then - core.table.insert(api, { - methods = {"GET"}, - uri = "/apisix/plugin/request_id/snowflake", - handler = next_id - }) - end - - return api -end - return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 3f6f9fd506a4..644b53a2fd3a 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -321,7 +321,7 @@ plugin_attr: enable: false snowflake_epoc: 1609459200000 node_id_bits: 5 - sequence_bits: 5 - datacenter_id_bits: 10 + datacenter_id_bits: 5 + sequence_bits: 10 worker_number_ttl: 30 worker_number_interval: 10 diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index 6dfb563e07b3..e825aef3cac2 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -483,8 +483,8 @@ plugin_attr: enable: true snowflake_epoc: 1609459200000 node_id_bits: 5 - sequence_bits: 5 - datacenter_id_bits: 10 + datacenter_id_bits: 5 + sequence_bits: 10 worker_number_ttl: 30 worker_number_interval: 10 --- config @@ -514,62 +514,7 @@ ok -=== TEST 13: check to get snowflake interface ---- yaml_config -plugins: - - request-id -plugin_attr: - request-id: - snowflake: - enable: true ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, id = t('/apisix/plugin/request_id/snowflake', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - ngx.status = code - } - } ---- request -GET /t ---- response_body ---- no_error_log -[error] - - - -=== TEST 14: check to get uuid interface ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, id = t('/apisix/plugin/request_id/uuid', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - ngx.status = code - } - } ---- request -GET /t ---- response_body ---- no_error_log -[error] - - - -=== TEST 15: wrong type +=== TEST 13: wrong type --- config location /t { content_by_lua_block { @@ -591,7 +536,7 @@ done -=== TEST 16: add plugin with algorithm snowflake (default uuid) +=== TEST 14: add plugin with algorithm snowflake (default uuid) --- config location /t { content_by_lua_block { @@ -648,7 +593,7 @@ passed -=== TEST 17: check for snowflake id +=== TEST 15: check for snowflake id --- yaml_config plugins: - request-id @@ -703,22 +648,3 @@ GET /t true --- no_error_log [error] - - - -=== TEST 18: check to get snowflake interface ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, id = t('/apisix/plugin/request_id/snowflake', - ngx.HTTP_GET - ) - ngx.status = code - } - } ---- request -GET /t ---- error_code: 404 ---- no_error_log -[error] From 4f1717fa067e5754ac42c32d9489b45c88c98541 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Mon, 12 Jul 2021 00:36:57 +0800 Subject: [PATCH 14/35] feat: support timestamp delta offset configuration --- apisix/plugins/request-id.lua | 27 +++++---- conf/config-default.yaml | 13 +++-- rockspec/apisix-master-0.rockspec | 2 +- t/plugin/request-id.t | 91 ++++++++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index cacc4d6c05d3..305dc7bc6cce 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -24,6 +24,8 @@ local process = require("ngx.process") local timers = require("apisix.timers") local tostring = tostring local math_pow = math.pow +local math_ceil = math.ceil +local math_floor = math.floor local plugin_name = "request-id" @@ -49,9 +51,9 @@ local attr_schema = { properties = { enable = {type = "boolean"}, snowflake_epoc = {type = "integer", minimum = 1, default = 1609459200000}, - node_id_bits = {type = "integer", minimum = 1, default = 5}, + data_machine_bits = {type = "integer", minimum = 1, default = 12}, sequence_bits = {type = "integer", minimum = 1, default = 10}, - datacenter_id_bits = {type = "integer", minimum = 1, default = 5}, + delta_offset = {type = "integer", default = 1, enum = {1, 10, 100, 1000}}, worker_number_ttl = {type = "integer", minimum = 1, default = 30}, worker_number_interval = {type = "integer", minimum = 1, default = 10} } @@ -157,23 +159,28 @@ end -- Initialize the snowflake algorithm local function snowflake_init() if snowflake_inited == nil then - local max_number = math_pow(2, (attr.snowflake.node_id_bits + - attr.snowflake.datacenter_id_bits)) + local max_number = math_pow(2, (attr.snowflake.data_machine_bits)) + local datacenter_id_bits = math_floor(attr.snowflake.data_machine_bits / 2) + local node_id_bits = math_ceil(attr.snowflake.data_machine_bits / 2) worker_number = gen_worker_number(max_number) if worker_number == nil then return "" end + local worker_id, datacenter_id = split_worker_number(worker_number, - attr.snowflake.node_id_bits, attr.snowflake.datacenter_id_bits) - core.log.notice("snowflake init datacenter_id: " .. + node_id_bits, datacenter_id_bits) + + -- core.log.error(datacenter_id_bits, datacenter_id, node_id_bits, worker_id) + core.log.info("snowflake init datacenter_id: " .. datacenter_id .. " worker_id: " .. worker_id) snowflake.init( - worker_id, datacenter_id, + worker_id, attr.snowflake.snowflake_epoc, - attr.snowflake.node_id_bits, - attr.snowflake.datacenter_id_bits, - attr.snowflake.sequence_bits + node_id_bits, + datacenter_id_bits, + attr.snowflake.sequence_bits, + attr.delta_offset ) snowflake_inited = true end diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 644b53a2fd3a..d664f42223bf 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -319,9 +319,10 @@ plugin_attr: request-id: snowflake: enable: false - snowflake_epoc: 1609459200000 - node_id_bits: 5 - datacenter_id_bits: 5 - sequence_bits: 10 - worker_number_ttl: 30 - worker_number_interval: 10 + snowflake_epoc: 1609459200000 # the starting timestamp is expressed in milliseconds + data_machine_bits: 12 # data machine bit + sequence_bits: 10 # each machine generates a maximum of (1 << sequence_bits) serial numbers per millisecond + delta_offset: 1 # timestamp delta offset (unit: milliseconds) + worker_number_ttl: 30 # live time for worker number in etcd (unit: second) + worker_number_interval: 10 # lease renewal interval in etcd (unit: second) + diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec index 20bfa119e12a..dede89be27d2 100644 --- a/rockspec/apisix-master-0.rockspec +++ b/rockspec/apisix-master-0.rockspec @@ -67,7 +67,7 @@ dependencies = { "lua-resty-consul = 0.3-2", "penlight = 1.9.2-1", "ext-plugin-proto = 0.1.1", - "api7-snowflake = 2.0-1", + "api7-snowflake = 2.1-1", } build = { diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index e825aef3cac2..7e683b1bcd30 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -482,8 +482,7 @@ plugin_attr: snowflake: enable: true snowflake_epoc: 1609459200000 - node_id_bits: 5 - datacenter_id_bits: 5 + data_machine_bits: 10 sequence_bits: 10 worker_number_ttl: 30 worker_number_interval: 10 @@ -648,3 +647,91 @@ GET /t true --- no_error_log [error] + + + +=== TEST 16: check for delta_offset 1000 milliseconds +--- yaml_config +plugins: + - request-id +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1609459200000 + data_machine_bits: 12 + sequence_bits: 10 + worker_number_ttl: 30 + worker_number_interval: 10 + delta_offset: 1000 +--- config + location /t { + content_by_lua_block { + local http = require "resty.http" + local t = {} + local ids = {} + for i = 1, 180 do + local th = assert(ngx.thread.spawn(function() + local httpc = http.new() + local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/opentracing" + local res, err = httpc:request_uri(uri, + { + method = "GET", + headers = { + ["Content-Type"] = "application/json", + } + } + ) + if not res then + ngx.log(ngx.ERR, err) + return + end + local id = res.headers["X-Request-Id"] + if not id then + return -- ignore if the data is not synced yet. + end + if ids[id] == true then + ngx.say("ids not unique") + return + end + ids[id] = true + end, i)) + table.insert(t, th) + end + for i, th in ipairs(t) do + ngx.thread.wait(th) + end + ngx.say("true") + } + } +--- request +GET /t +--- wait: 5 +--- response_body +true +--- no_error_log +[error] + + + +=== TEST 17: wrong delta_offset +--- yaml_config +plugins: + - request-id +plugin_attr: + request-id: + snowflake: + enable: true + delta_offset: 1001 +--- config + location /t { + content_by_lua_block { + ngx.say("done") + } + } +--- request +GET /t +--- response_body +done +--- error_log +ailed to check the plugin_attr[request-id]: property "snowflake" validation failed: property "delta_offset" validation failed: matches none of the enum values From 7c6bfa75156826f55cd271ae481fcb4b3eeddf68 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Mon, 12 Jul 2021 00:45:35 +0800 Subject: [PATCH 15/35] docs: add snowflake algorithm instructions --- docs/zh/latest/plugins/request-id.md | 98 +++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index cf2373cd0b36..cb98a68cfced 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -37,8 +37,9 @@ title: request-id | 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | | ------------------- | ------- | -------- | -------------- | ------ | ------------------------------ | -| header_name | string | 可选 | "X-Request-Id" | | Request ID header name | -| include_in_response | boolean | 可选 | false | | 是否需要在返回头中包含该唯一ID | +| header_name | string | 可选 | "X-Request-Id" | | Request ID header name | +| include_in_response | boolean | 可选 | false | | 是否需要在返回头中包含该唯一ID | +| algorithm | string | 可选 | "uuid" | ["uuid", "snowflake"] | ID 生成算法 | ## 如何启用 @@ -71,6 +72,99 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ...... ``` + +### 使用 snowflake 算法 + +> 支持使用 snowflake 算法来生成ID。 +> 在决定使用snowflake时,请优先阅读一下文档。因为一旦启用配置信息则不可随意调整配置信息。否则可能会导致生成重复ID。 + +snowflake 算法默认是不启用的,需要在 `conf/config.yaml` 中开启配置。 + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1609459200000 + data_machine_bits: 12 + sequence_bits: 10 + worker_number_ttl: 30 + worker_number_interval: 10 +``` +#### 配置参数 + +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +| ------------------- | ------- | -------- | -------------- | ------ | ------------------------------ | +| enable | boolean | 可选 | false | | 当设置为true时, 启用snowflake算法。 | +| snowflake_epoc | integer | 可选 | 1609459200000 | | 起始时间戳(单位: 毫秒) | +| data_machine_bits | integer | 可选 | 12 | | 数据机器位`datacenterId` + `workerId`(1 << node_id_bits) | +| sequence_bits | integer | 可选 | 10 | | 每个节点每毫秒内最多产生ID数量 (1 << sequence_bits) | +| delta_offset | integer | 可选 | 1 | | 时间戳增量偏移(单位: 毫秒) | +| worker_number_ttl | integer | 可选 | 30 | | `etcd` 中 `worker_number` 注册有效时间(单位: 秒)| +| worker_number_interval | integer | 可选 | 10 | | `etcd` 中 `worker_number` 续约间隔时间(单位: 秒)| + +- snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` +- data_machine_bits 默认占 `12 bits` 最多支持 `4096` 个进程 +- sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID +- delta_offset 时间戳增量偏移 (单位: 毫秒) [`delta_offset=1` 每毫秒, `delta_offset=10` 每10毫秒, `delta_offset=100` 每100毫秒, `delta_offset=1000` 每1秒`] + +#### 配置示例 + +> snowflake 支持灵活配置来满足各式各样的需求 + +- snowflake 原版配置 + +> - 起始时间 2014-10-20T15:00:00.000Z, 精确到毫秒为单位。大约可以使用 `69年` +> - 最多支持 `1024` 个进程 +> - 每个进程每秒最多产生 `4096` 个ID + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1413817200000 + data_machine_bits: 10 + sequence_bits: 12 +``` + +- [sonyflake](https://github.com/sony/sonyflake) + +> - 39 bit 为时间戳,精确到 `10ms` 大约可以使用174年。 +> - 16 bit 做为机器号, 可同时支持 `65536` 个进程运行。 +> - 8 bit 做为序列号,每10毫最大生成256个,1秒最多生成25600个。 + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1413817200000 + data_machine_bits: 16 + sequence_bits: 8 + delta_offset: 10 +``` + +- [baidu UidGenerator](https://github.com/baidu/uid-generator) + +不支持 Double RingBuffer + +> - delta seconds (28 bits) +> - 当前时间,相对于时间基点"2016-05-20"的增量值,单位:秒,最多可支持约8.7年 +> - worker id (22 bits) 机器id,最多可支持约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略。 +> - sequence (13 bits) 每秒下的并发序列,13 bits可支持每秒8192个并发。 + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1463644800000 + data_machine_bits: 22 + sequence_bits: 13 + delta_offset: 1000 +``` + ## 禁用插件 在路由 `plugins` 配置块中删除 `request-id 配置,即可禁用该插件,无需重启 APISIX。 From e0284a29b546e268ef6bb9b5701a57b9706eb2e7 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 13 Jul 2021 23:36:25 +0800 Subject: [PATCH 16/35] rename worker_number to data_machine --- apisix/plugins/request-id.lua | 48 ++++++++++++++-------------- conf/config-default.yaml | 4 +-- docs/zh/latest/plugins/request-id.md | 8 ++--- t/plugin/request-id.t | 8 ++--- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 305dc7bc6cce..1021446fc801 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -29,7 +29,7 @@ local math_floor = math.floor local plugin_name = "request-id" -local worker_number = nil +local data_machine = nil local snowflake_inited = nil local attr = nil @@ -54,8 +54,8 @@ local attr_schema = { data_machine_bits = {type = "integer", minimum = 1, default = 12}, sequence_bits = {type = "integer", minimum = 1, default = 10}, delta_offset = {type = "integer", default = 1, enum = {1, 10, 100, 1000}}, - worker_number_ttl = {type = "integer", minimum = 1, default = 30}, - worker_number_interval = {type = "integer", minimum = 1, default = 10} + data_machine_ttl = {type = "integer", minimum = 1, default = 30}, + data_machine_interval = {type = "integer", minimum = 1, default = 10} } } } @@ -75,23 +75,23 @@ end -- Generates the current process worker number -local function gen_worker_number(max_number) - if worker_number == nil then +local function gen_data_machine(max_number) + if data_machine == nil then local etcd_cli, prefix = core.etcd.new() local prefix = prefix .. "/plugins/request-id/snowflake/" local uuid = uuid.generate_v4() local id = 1 while (id <= max_number) do ::continue:: - local res, _ = etcd_cli:grant(attr.snowflake.worker_number_ttl) + local res, _ = etcd_cli:grant(attr.snowflake.data_machine_ttl) local _, err1 = etcd_cli:setnx(prefix .. tostring(id), uuid) local res2, err2 = etcd_cli:get(prefix .. tostring(id)) if err1 or err2 or res2.body.kvs[1].value ~= uuid then - core.log.notice("worker_number " .. id .. " is not available") + core.log.notice("data_machine " .. id .. " is not available") id = id + 1 else - worker_number = id + data_machine = id local _, err3 = etcd_cli:set( @@ -106,7 +106,7 @@ local function gen_worker_number(max_number) if err3 then id = id + 1 etcd_cli:delete(prefix .. tostring(id)) - core.log.error("set worker_number " .. id .. " lease error: " .. err3) + core.log.error("set data_machine " .. id .. " lease error: " .. err3) goto continue end @@ -114,41 +114,41 @@ local function gen_worker_number(max_number) local start_at = ngx.time() local handler = function() local now = ngx.time() - if now - start_at < attr.snowflake.worker_number_interval then + if now - start_at < attr.snowflake.data_machine_interval then return end local _, err4 = etcd_cli:keepalive(lease_id) if err4 then snowflake_inited = nil - worker_number = nil - core.log.error("snowflake worker_number: " .. id .." lease faild.") + data_machine = nil + core.log.error("snowflake data_machine: " .. id .." lease faild.") end start_at = now - core.log.info("snowflake worker_number: " .. id .." lease success.") + core.log.info("snowflake data_machine: " .. id .." lease success.") end timers.register_timer("plugin#request-id", handler) core.log.info( "timer created to lease snowflake algorithm worker number, interval: ", - attr.snowflake.worker_number_interval) - core.log.notice("lease snowflake worker_number: " .. id) + attr.snowflake.data_machine_interval) + core.log.notice("lease snowflake data_machine: " .. id) break end end - if worker_number == nil then - core.log.error("No worker_number is not available") + if data_machine == nil then + core.log.error("No data_machine is not available") return nil end end - return worker_number + return data_machine end --- Split 'Worker Number' into 'Worker ID' and 'datacenter ID' -local function split_worker_number(worker_number, node_id_bits, datacenter_id_bits) - local num = bit.tobit(worker_number) +-- Split 'Data Machine' into 'Worker ID' and 'datacenter ID' +local function split_data_machine(data_machine, node_id_bits, datacenter_id_bits) + local num = bit.tobit(data_machine) local worker_id = bit.band(num, math_pow(2, node_id_bits) - 1) + 1 num = bit.rshift(num, node_id_bits) local datacenter_id = bit.band(num, math_pow(2, datacenter_id_bits) - 1) + 1 @@ -162,12 +162,12 @@ local function snowflake_init() local max_number = math_pow(2, (attr.snowflake.data_machine_bits)) local datacenter_id_bits = math_floor(attr.snowflake.data_machine_bits / 2) local node_id_bits = math_ceil(attr.snowflake.data_machine_bits / 2) - worker_number = gen_worker_number(max_number) - if worker_number == nil then + data_machine = gen_data_machine(max_number) + if data_machine == nil then return "" end - local worker_id, datacenter_id = split_worker_number(worker_number, + local worker_id, datacenter_id = split_data_machine(data_machine, node_id_bits, datacenter_id_bits) -- core.log.error(datacenter_id_bits, datacenter_id, node_id_bits, worker_id) diff --git a/conf/config-default.yaml b/conf/config-default.yaml index d664f42223bf..6475f1bf1ee0 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -323,6 +323,6 @@ plugin_attr: data_machine_bits: 12 # data machine bit sequence_bits: 10 # each machine generates a maximum of (1 << sequence_bits) serial numbers per millisecond delta_offset: 1 # timestamp delta offset (unit: milliseconds) - worker_number_ttl: 30 # live time for worker number in etcd (unit: second) - worker_number_interval: 10 # lease renewal interval in etcd (unit: second) + data_machine_ttl: 30 # live time for data_machine in etcd (unit: second) + data_machine_interval: 10 # lease renewal interval in etcd (unit: second) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index cb98a68cfced..b9eb859035cf 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -88,8 +88,8 @@ plugin_attr: snowflake_epoc: 1609459200000 data_machine_bits: 12 sequence_bits: 10 - worker_number_ttl: 30 - worker_number_interval: 10 + data_machine_ttl: 30 + data_machine_interval: 10 ``` #### 配置参数 @@ -100,8 +100,8 @@ plugin_attr: | data_machine_bits | integer | 可选 | 12 | | 数据机器位`datacenterId` + `workerId`(1 << node_id_bits) | | sequence_bits | integer | 可选 | 10 | | 每个节点每毫秒内最多产生ID数量 (1 << sequence_bits) | | delta_offset | integer | 可选 | 1 | | 时间戳增量偏移(单位: 毫秒) | -| worker_number_ttl | integer | 可选 | 30 | | `etcd` 中 `worker_number` 注册有效时间(单位: 秒)| -| worker_number_interval | integer | 可选 | 10 | | `etcd` 中 `worker_number` 续约间隔时间(单位: 秒)| +| data_machine_ttl | integer | 可选 | 30 | | `etcd` 中 `data_machine` 注册有效时间(单位: 秒)| +| data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| - snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` - data_machine_bits 默认占 `12 bits` 最多支持 `4096` 个进程 diff --git a/t/plugin/request-id.t b/t/plugin/request-id.t index 7e683b1bcd30..61ebc014e3f0 100644 --- a/t/plugin/request-id.t +++ b/t/plugin/request-id.t @@ -484,8 +484,8 @@ plugin_attr: snowflake_epoc: 1609459200000 data_machine_bits: 10 sequence_bits: 10 - worker_number_ttl: 30 - worker_number_interval: 10 + data_machine_ttl: 30 + data_machine_interval: 10 --- config location /t { content_by_lua_block { @@ -661,8 +661,8 @@ plugin_attr: snowflake_epoc: 1609459200000 data_machine_bits: 12 sequence_bits: 10 - worker_number_ttl: 30 - worker_number_interval: 10 + data_machine_ttl: 30 + data_machine_interval: 10 delta_offset: 1000 --- config location /t { From fe8568b181e658fd4d3297f068062b81346fb94e Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 13 Jul 2021 23:38:09 +0800 Subject: [PATCH 17/35] fixed workerid and datacenter_id computation error --- apisix/plugins/request-id.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 1021446fc801..2b2560a15c67 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -149,9 +149,9 @@ end -- Split 'Data Machine' into 'Worker ID' and 'datacenter ID' local function split_data_machine(data_machine, node_id_bits, datacenter_id_bits) local num = bit.tobit(data_machine) - local worker_id = bit.band(num, math_pow(2, node_id_bits) - 1) + 1 + local worker_id = bit.band(num, math_pow(2, node_id_bits) - 1) num = bit.rshift(num, node_id_bits) - local datacenter_id = bit.band(num, math_pow(2, datacenter_id_bits) - 1) + 1 + local datacenter_id = bit.band(num, math_pow(2, datacenter_id_bits) - 1) return worker_id, datacenter_id end @@ -170,7 +170,6 @@ local function snowflake_init() local worker_id, datacenter_id = split_data_machine(data_machine, node_id_bits, datacenter_id_bits) - -- core.log.error(datacenter_id_bits, datacenter_id, node_id_bits, worker_id) core.log.info("snowflake init datacenter_id: " .. datacenter_id .. " worker_id: " .. worker_id) snowflake.init( From 90e3544719b78cc3f098b3a6e6d0aea38939a524 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 13 Jul 2021 23:42:11 +0800 Subject: [PATCH 18/35] etcd grant add exception validation --- apisix/plugins/request-id.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 2b2560a15c67..da89be4c1f2e 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -83,7 +83,11 @@ local function gen_data_machine(max_number) local id = 1 while (id <= max_number) do ::continue:: - local res, _ = etcd_cli:grant(attr.snowflake.data_machine_ttl) + local res, err = etcd_cli:grant(attr.snowflake.data_machine_ttl) + if err then + core.log.error("Etcd grant failure, err: ".. err) + end + local _, err1 = etcd_cli:setnx(prefix .. tostring(id), uuid) local res2, err2 = etcd_cli:get(prefix .. tostring(id)) From cb0735136bfaad66c3eacd0a2e2938c8fed2ff06 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 13 Jul 2021 23:48:18 +0800 Subject: [PATCH 19/35] fix: goto may causes the id > max_number --- apisix/plugins/request-id.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index da89be4c1f2e..e0f0cb63d0c3 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -81,8 +81,8 @@ local function gen_data_machine(max_number) local prefix = prefix .. "/plugins/request-id/snowflake/" local uuid = uuid.generate_v4() local id = 1 + ::continue:: while (id <= max_number) do - ::continue:: local res, err = etcd_cli:grant(attr.snowflake.data_machine_ttl) if err then core.log.error("Etcd grant failure, err: ".. err) From 61ed66ecd2184e0731fc942da19d3825e0723b16 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 13 Jul 2021 23:49:39 +0800 Subject: [PATCH 20/35] chore: fix name comment --- apisix/plugins/request-id.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index e0f0cb63d0c3..45e92382a225 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -74,7 +74,7 @@ function _M.check_schema(conf) end --- Generates the current process worker number +-- Generates the current process data machine local function gen_data_machine(max_number) if data_machine == nil then local etcd_cli, prefix = core.etcd.new() @@ -134,7 +134,7 @@ local function gen_data_machine(max_number) timers.register_timer("plugin#request-id", handler) core.log.info( - "timer created to lease snowflake algorithm worker number, interval: ", + "timer created to lease snowflake algorithm data_machine, interval: ", attr.snowflake.data_machine_interval) core.log.notice("lease snowflake data_machine: " .. id) break From b97bb94368185d3b8bf4d29ae4e4277152114817 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 14 Jul 2021 00:29:23 +0800 Subject: [PATCH 21/35] feat: limit data_machine_bits maximun --- apisix/plugins/request-id.lua | 2 +- conf/config-default.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 45e92382a225..e138f7251732 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -51,7 +51,7 @@ local attr_schema = { properties = { enable = {type = "boolean"}, snowflake_epoc = {type = "integer", minimum = 1, default = 1609459200000}, - data_machine_bits = {type = "integer", minimum = 1, default = 12}, + data_machine_bits = {type = "integer", minimum = 1, maximum = 31, default = 12}, sequence_bits = {type = "integer", minimum = 1, default = 10}, delta_offset = {type = "integer", default = 1, enum = {1, 10, 100, 1000}}, data_machine_ttl = {type = "integer", minimum = 1, default = 30}, diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 6475f1bf1ee0..442da050032e 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -320,7 +320,7 @@ plugin_attr: snowflake: enable: false snowflake_epoc: 1609459200000 # the starting timestamp is expressed in milliseconds - data_machine_bits: 12 # data machine bit + data_machine_bits: 12 # data machine bit, maximum 31, because Lua cannot do bit operations greater than 31 sequence_bits: 10 # each machine generates a maximum of (1 << sequence_bits) serial numbers per millisecond delta_offset: 1 # timestamp delta offset (unit: milliseconds) data_machine_ttl: 30 # live time for data_machine in etcd (unit: second) From 3c2d4e74fc778468b0453e24d0a33fdf8579b9bb Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 14 Jul 2021 00:31:41 +0800 Subject: [PATCH 22/35] chore: use the old version lua-snowflake first --- rockspec/apisix-master-0.rockspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec index dede89be27d2..20bfa119e12a 100644 --- a/rockspec/apisix-master-0.rockspec +++ b/rockspec/apisix-master-0.rockspec @@ -67,7 +67,7 @@ dependencies = { "lua-resty-consul = 0.3-2", "penlight = 1.9.2-1", "ext-plugin-proto = 0.1.1", - "api7-snowflake = 2.1-1", + "api7-snowflake = 2.0-1", } build = { From cd39e27ff31c890739bd607ae9842fa8df58c9b3 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 14 Jul 2021 00:39:20 +0800 Subject: [PATCH 23/35] docs: optimzie 'data_machine_bits' describe --- docs/zh/latest/plugins/request-id.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index b9eb859035cf..157f410bdf91 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -104,7 +104,7 @@ plugin_attr: | data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| - snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` -- data_machine_bits 默认占 `12 bits` 最多支持 `4096` 个进程 +- data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程, - sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID - delta_offset 时间戳增量偏移 (单位: 毫秒) [`delta_offset=1` 每毫秒, `delta_offset=10` 每10毫秒, `delta_offset=100` 每100毫秒, `delta_offset=1000` 每1秒`] From 77dd4410228ca08cf0b50fe4d699b1c79d4a1d2b Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 14 Jul 2021 00:47:36 +0800 Subject: [PATCH 24/35] docs: fix end of line --- docs/zh/latest/plugins/request-id.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index 157f410bdf91..723854272db3 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -104,7 +104,7 @@ plugin_attr: | data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| - snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` -- data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程, +- data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程。 - sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID - delta_offset 时间戳增量偏移 (单位: 毫秒) [`delta_offset=1` 每毫秒, `delta_offset=10` 每10毫秒, `delta_offset=100` 每100毫秒, `delta_offset=1000` 每1秒`] From 5941f62021682f55cc76ebde54ab98c2b3cadaaf Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 14 Jul 2021 00:50:42 +0800 Subject: [PATCH 25/35] docs: fix markdownlint --- docs/zh/latest/plugins/request-id.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index 723854272db3..ddc7560378f5 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -72,7 +72,6 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ...... ``` - ### 使用 snowflake 算法 > 支持使用 snowflake 算法来生成ID。 @@ -91,6 +90,7 @@ plugin_attr: data_machine_ttl: 30 data_machine_interval: 10 ``` + #### 配置参数 | 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | From 49aae465c94601e9da47a8d4737e88528a8ef805 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 20 Jul 2021 22:43:17 +0800 Subject: [PATCH 26/35] fix: plugin destroy unregister timer --- apisix/plugins/request-id.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index e138f7251732..900a10dcfa64 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -245,5 +245,8 @@ function _M.init() end end +function _M.destroy() + timers.unregister_timer("plugin#request-id") +end return _M From ea7c7c6dbe348bdcb5fd6cdb762ddafd9e744d88 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 20 Jul 2021 23:10:58 +0800 Subject: [PATCH 27/35] chore: remove delta offset --- conf/config-default.yaml | 1 - docs/zh/latest/plugins/request-id.md | 52 ++++------------------------ 2 files changed, 7 insertions(+), 46 deletions(-) diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 442da050032e..7040d087e7e5 100644 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -322,7 +322,6 @@ plugin_attr: snowflake_epoc: 1609459200000 # the starting timestamp is expressed in milliseconds data_machine_bits: 12 # data machine bit, maximum 31, because Lua cannot do bit operations greater than 31 sequence_bits: 10 # each machine generates a maximum of (1 << sequence_bits) serial numbers per millisecond - delta_offset: 1 # timestamp delta offset (unit: milliseconds) data_machine_ttl: 30 # live time for data_machine in etcd (unit: second) data_machine_interval: 10 # lease renewal interval in etcd (unit: second) diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index ddc7560378f5..25488d2d29d4 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -72,7 +72,7 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ...... ``` -### 使用 snowflake 算法 +### 使用 snowflake 算法生成ID > 支持使用 snowflake 算法来生成ID。 > 在决定使用snowflake时,请优先阅读一下文档。因为一旦启用配置信息则不可随意调整配置信息。否则可能会导致生成重复ID。 @@ -97,16 +97,15 @@ plugin_attr: | ------------------- | ------- | -------- | -------------- | ------ | ------------------------------ | | enable | boolean | 可选 | false | | 当设置为true时, 启用snowflake算法。 | | snowflake_epoc | integer | 可选 | 1609459200000 | | 起始时间戳(单位: 毫秒) | -| data_machine_bits | integer | 可选 | 12 | | 数据机器位`datacenterId` + `workerId`(1 << node_id_bits) | -| sequence_bits | integer | 可选 | 10 | | 每个节点每毫秒内最多产生ID数量 (1 << sequence_bits) | -| delta_offset | integer | 可选 | 1 | | 时间戳增量偏移(单位: 毫秒) | -| data_machine_ttl | integer | 可选 | 30 | | `etcd` 中 `data_machine` 注册有效时间(单位: 秒)| -| data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| +| data_machine_bits | integer | 可选 | 12 | | 最多支持机器(进程)数量 `1 << data_machine_bits` | +| sequence_bits | integer | 可选 | 10 | | 每个节点每毫秒内最多产生ID数量 `1 << sequence_bits` | +| data_machine_ttl | integer | 可选 | 30 | | `etcd` 中 `data_machine` 注册有效时间(单位: 秒)| +| data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| - snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` - data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程。 - sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID -- delta_offset 时间戳增量偏移 (单位: 毫秒) [`delta_offset=1` 每毫秒, `delta_offset=10` 每10毫秒, `delta_offset=100` 每100毫秒, `delta_offset=1000` 每1秒`] + #### 配置示例 @@ -128,46 +127,9 @@ plugin_attr: sequence_bits: 12 ``` -- [sonyflake](https://github.com/sony/sonyflake) - -> - 39 bit 为时间戳,精确到 `10ms` 大约可以使用174年。 -> - 16 bit 做为机器号, 可同时支持 `65536` 个进程运行。 -> - 8 bit 做为序列号,每10毫最大生成256个,1秒最多生成25600个。 - -```yaml -plugin_attr: - request-id: - snowflake: - enable: true - snowflake_epoc: 1413817200000 - data_machine_bits: 16 - sequence_bits: 8 - delta_offset: 10 -``` - -- [baidu UidGenerator](https://github.com/baidu/uid-generator) - -不支持 Double RingBuffer - -> - delta seconds (28 bits) -> - 当前时间,相对于时间基点"2016-05-20"的增量值,单位:秒,最多可支持约8.7年 -> - worker id (22 bits) 机器id,最多可支持约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略。 -> - sequence (13 bits) 每秒下的并发序列,13 bits可支持每秒8192个并发。 - -```yaml -plugin_attr: - request-id: - snowflake: - enable: true - snowflake_epoc: 1463644800000 - data_machine_bits: 22 - sequence_bits: 13 - delta_offset: 1000 -``` - ## 禁用插件 -在路由 `plugins` 配置块中删除 `request-id 配置,即可禁用该插件,无需重启 APISIX。 +在路由 `plugins` 配置块中删除 `request-id 配置,reload 即可禁用该插件,无需重启 APISIX。 ```shell curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' From 82e6250a50a2db71891f75765f0a8166eb0d1224 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 20 Jul 2021 23:11:44 +0800 Subject: [PATCH 28/35] docs: added English doc --- docs/en/latest/plugins/request-id.md | 56 ++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/en/latest/plugins/request-id.md b/docs/en/latest/plugins/request-id.md index babca3d30391..78609b148acb 100644 --- a/docs/en/latest/plugins/request-id.md +++ b/docs/en/latest/plugins/request-id.md @@ -72,6 +72,62 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ...... ``` + +### Use the snowflake algorithm to generate an ID + +> supports using the Snowflake algorithm to generate ID. +> read the documentation first before deciding to use snowflake. Because once the configuration information is enabled, you cannot arbitrarily adjust the configuration information. Failure to do so may result in duplicate ID being generated. + +The Snowflake algorithm is not enabled by default and needs to be configured in 'conf/config.yaml'. + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1609459200000 + data_machine_bits: 12 + sequence_bits: 10 + data_machine_ttl: 30 + data_machine_interval: 10 +``` + +#### Configuration parameters + +| Name | Type | Requirement | Default | Valid | Description | +| ------------------- | ------- | ------------- | -------------- | ------- | ------------------------------ | +| enable | boolean | required | false | | When set it to true, enable the snowflake algorithm. | +| snowflake_epoc | integer | required | 1609459200000 | | Start timestamp (in milliseconds) | +| data_machine_bits | integer | deprecated | 12 | | Maximum number of supported machines (processes) `1 << data_machine_bits` | +| sequence_bits | integer | deprecated | 10 | | Maximum number of generated ID per millisecond per node `1 << sequence_bits` | +| data_machine_ttl | integer | deprecated | 30 | | Valid time of registration of 'data_machine' in 'etcd' (unit: seconds) | +| data_machine_interval | integer | deprecated | 10 | | Time between 'data_machine' renewal in 'etcd' (unit: seconds) | + +- `snowflake_epoc` default start time is `2021-01-01T00:00:00Z`, and it can support `69 year` approximately to `2090-09-0715:47:35Z` according to the default configuration +- `data_machine_bits` corresponds to the set of workIDs and datacEnteridd in the snowflake definition. The plug-in aslocates a unique ID to each process. Maximum number of supported processes is `pow(2, data_machine_bits)`. The default number of `12 bits` is up to `4096`. +- `sequence_bits` defaults to `10 bits` and each process generates up to `1024` ID per second + + +#### example + +> Snowflake supports flexible configuration to meet a wide variety of needs + +- Snowflake original configuration + +> - Start time 2014-10-20 T15:00:00.000z, accurate to milliseconds. It can last about 69 years +> - supports up to `1024` processes +> - Up to `4096` ID per second per process + +```yaml +plugin_attr: + request-id: + snowflake: + enable: true + snowflake_epoc: 1413817200000 + data_machine_bits: 10 + sequence_bits: 12 +``` + ## Disable Plugin Remove the corresponding json configuration in the plugin configuration to disable the `request-id`. From c487aeb1651136c3882924124b1ad63c6b314f54 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 20 Jul 2021 23:14:26 +0800 Subject: [PATCH 29/35] fix: markdownlint --- docs/en/latest/plugins/request-id.md | 2 -- docs/zh/latest/plugins/request-id.md | 1 - 2 files changed, 3 deletions(-) diff --git a/docs/en/latest/plugins/request-id.md b/docs/en/latest/plugins/request-id.md index 78609b148acb..a56a666ba39d 100644 --- a/docs/en/latest/plugins/request-id.md +++ b/docs/en/latest/plugins/request-id.md @@ -72,7 +72,6 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ...... ``` - ### Use the snowflake algorithm to generate an ID > supports using the Snowflake algorithm to generate ID. @@ -107,7 +106,6 @@ plugin_attr: - `data_machine_bits` corresponds to the set of workIDs and datacEnteridd in the snowflake definition. The plug-in aslocates a unique ID to each process. Maximum number of supported processes is `pow(2, data_machine_bits)`. The default number of `12 bits` is up to `4096`. - `sequence_bits` defaults to `10 bits` and each process generates up to `1024` ID per second - #### example > Snowflake supports flexible configuration to meet a wide variety of needs diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index 25488d2d29d4..eaf4b419a45c 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -106,7 +106,6 @@ plugin_attr: - data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程。 - sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID - #### 配置示例 > snowflake 支持灵活配置来满足各式各样的需求 From 9e5e70a20ceb44a18a8f2a0c252bffda064b2de2 Mon Sep 17 00:00:00 2001 From: seven dickens Date: Thu, 22 Jul 2021 09:33:54 +0800 Subject: [PATCH 30/35] fixcheck if the timer is registered --- apisix/plugins/request-id.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 900a10dcfa64..b7067d4faf50 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -246,7 +246,9 @@ function _M.init() end function _M.destroy() - timers.unregister_timer("plugin#request-id") + if snowflake_inited then + timers.unregister_timer("plugin#request-id") + end end return _M From 756ba1978f21e4c697fcdb9d32b8af2970f61125 Mon Sep 17 00:00:00 2001 From: seven dickens Date: Thu, 22 Jul 2021 11:32:52 +0800 Subject: [PATCH 31/35] fix: etcd_cli:grant error continue --- apisix/plugins/request-id.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index b7067d4faf50..19a579f43b38 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -86,6 +86,7 @@ local function gen_data_machine(max_number) local res, err = etcd_cli:grant(attr.snowflake.data_machine_ttl) if err then core.log.error("Etcd grant failure, err: ".. err) + goto continue end local _, err1 = etcd_cli:setnx(prefix .. tostring(id), uuid) From 8e7d777da03a33bbdb320938bc9fe1310fd70d9c Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 27 Jul 2021 21:47:02 +0800 Subject: [PATCH 32/35] fix: infinite loop --- apisix/plugins/request-id.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index 900a10dcfa64..ee810e0f44ab 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -49,14 +49,15 @@ local attr_schema = { snowflake = { type = "object", properties = { - enable = {type = "boolean"}, + enable = {type = "boolean", default = false}, snowflake_epoc = {type = "integer", minimum = 1, default = 1609459200000}, data_machine_bits = {type = "integer", minimum = 1, maximum = 31, default = 12}, sequence_bits = {type = "integer", minimum = 1, default = 10}, delta_offset = {type = "integer", default = 1, enum = {1, 10, 100, 1000}}, data_machine_ttl = {type = "integer", minimum = 1, default = 30}, data_machine_interval = {type = "integer", minimum = 1, default = 10} - } + }, + required = {"enable", "snowflake_epoc"} } } } @@ -85,6 +86,7 @@ local function gen_data_machine(max_number) while (id <= max_number) do local res, err = etcd_cli:grant(attr.snowflake.data_machine_ttl) if err then + id = id + 1 core.log.error("Etcd grant failure, err: ".. err) end From 99bc9f397c06111545255c0418a7dc0c0ca7efd6 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 27 Jul 2021 21:48:05 +0800 Subject: [PATCH 33/35] docs: fix describe the error --- docs/en/latest/plugins/request-id.md | 10 +++++----- docs/zh/latest/plugins/request-id.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/latest/plugins/request-id.md b/docs/en/latest/plugins/request-id.md index a56a666ba39d..ee26e2f7de65 100644 --- a/docs/en/latest/plugins/request-id.md +++ b/docs/en/latest/plugins/request-id.md @@ -75,7 +75,7 @@ X-Request-Id: fe32076a-d0a5-49a6-a361-6c244c1df956 ### Use the snowflake algorithm to generate an ID > supports using the Snowflake algorithm to generate ID. -> read the documentation first before deciding to use snowflake. Because once the configuration information is enabled, you cannot arbitrarily adjust the configuration information. Failure to do so may result in duplicate ID being generated. +> read the documentation first before deciding to use snowflake. Because once the configuration information is enabled, you can not arbitrarily adjust the configuration information. Failure to do so may result in duplicate ID being generated. The Snowflake algorithm is not enabled by default and needs to be configured in 'conf/config.yaml'. @@ -97,10 +97,10 @@ plugin_attr: | ------------------- | ------- | ------------- | -------------- | ------- | ------------------------------ | | enable | boolean | required | false | | When set it to true, enable the snowflake algorithm. | | snowflake_epoc | integer | required | 1609459200000 | | Start timestamp (in milliseconds) | -| data_machine_bits | integer | deprecated | 12 | | Maximum number of supported machines (processes) `1 << data_machine_bits` | -| sequence_bits | integer | deprecated | 10 | | Maximum number of generated ID per millisecond per node `1 << sequence_bits` | -| data_machine_ttl | integer | deprecated | 30 | | Valid time of registration of 'data_machine' in 'etcd' (unit: seconds) | -| data_machine_interval | integer | deprecated | 10 | | Time between 'data_machine' renewal in 'etcd' (unit: seconds) | +| data_machine_bits | integer | optional | 12 | | Maximum number of supported machines (processes) `1 << data_machine_bits` | +| sequence_bits | integer | optional | 10 | | Maximum number of generated ID per millisecond per node `1 << sequence_bits` | +| data_machine_ttl | integer | optional | 30 | | Valid time of registration of 'data_machine' in 'etcd' (unit: seconds) | +| data_machine_interval | integer | optional | 10 | | Time between 'data_machine' renewal in 'etcd' (unit: seconds) | - `snowflake_epoc` default start time is `2021-01-01T00:00:00Z`, and it can support `69 year` approximately to `2090-09-0715:47:35Z` according to the default configuration - `data_machine_bits` corresponds to the set of workIDs and datacEnteridd in the snowflake definition. The plug-in aslocates a unique ID to each process. Maximum number of supported processes is `pow(2, data_machine_bits)`. The default number of `12 bits` is up to `4096`. diff --git a/docs/zh/latest/plugins/request-id.md b/docs/zh/latest/plugins/request-id.md index eaf4b419a45c..0781c677b823 100644 --- a/docs/zh/latest/plugins/request-id.md +++ b/docs/zh/latest/plugins/request-id.md @@ -103,7 +103,7 @@ plugin_attr: | data_machine_interval | integer | 可选 | 10 | | `etcd` 中 `data_machine` 续约间隔时间(单位: 秒)| - snowflake_epoc 默认起始时间为 `2021-01-01T00:00:00Z`, 按默认配置可以支持 `69年` 大约可以使用到 `2090-09-07 15:47:35Z` -- data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterIDd的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程。 +- data_machine_bits 对应的是 snowflake 定义中的 WorkerID 和 DatacenterID 的集合,插件会为每一个进程分配一个唯一ID,最大支持进程数为 `pow(2, data_machine_bits)`。默认占 `12 bits` 最多支持 `4096` 个进程。 - sequence_bits 默认占 `10 bits`, 每个进程每秒最多生成 `1024` 个ID #### 配置示例 From 9894d698914d0d6ef73d9f90fa8d331c8f8d9ab9 Mon Sep 17 00:00:00 2001 From: dickens7 Date: Tue, 27 Jul 2021 22:17:36 +0800 Subject: [PATCH 34/35] docs: fixed attributes --- docs/en/latest/plugins/request-id.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/latest/plugins/request-id.md b/docs/en/latest/plugins/request-id.md index 9f05023f3705..e9cdcc303088 100644 --- a/docs/en/latest/plugins/request-id.md +++ b/docs/en/latest/plugins/request-id.md @@ -39,7 +39,8 @@ API request. The plugin will not add a request id if the `header_name` is alread | Name | Type | Requirement | Default | Valid | Description | | ------------------- | ------- | ----------- | -------------- | ----- | -------------------------------------------------------------- | | header_name | string | optional | "X-Request-Id" | | Request ID header name | -| include_in_response | boolean | optional | true | | Option to include the unique request ID in the response header | +| include_in_response | boolean | optional | true | | Option to include the unique request ID in the response header | +| algorithm | string | optional | "uuid" | ["uuid", "snowflake"] | ID generation algorithm | ## How To Enable From 72a7b0bfa4b94809a12be59aae1e3de5e71a237d Mon Sep 17 00:00:00 2001 From: dickens7 Date: Wed, 28 Jul 2021 11:09:37 +0800 Subject: [PATCH 35/35] fix: have default values, set optional --- apisix/plugins/request-id.lua | 3 +-- docs/en/latest/plugins/request-id.md | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua index bd5892cd976b..f496fda155d5 100644 --- a/apisix/plugins/request-id.lua +++ b/apisix/plugins/request-id.lua @@ -56,8 +56,7 @@ local attr_schema = { delta_offset = {type = "integer", default = 1, enum = {1, 10, 100, 1000}}, data_machine_ttl = {type = "integer", minimum = 1, default = 30}, data_machine_interval = {type = "integer", minimum = 1, default = 10} - }, - required = {"enable", "snowflake_epoc"} + } } } } diff --git a/docs/en/latest/plugins/request-id.md b/docs/en/latest/plugins/request-id.md index e9cdcc303088..871c542b5938 100644 --- a/docs/en/latest/plugins/request-id.md +++ b/docs/en/latest/plugins/request-id.md @@ -96,8 +96,8 @@ plugin_attr: | Name | Type | Requirement | Default | Valid | Description | | ------------------- | ------- | ------------- | -------------- | ------- | ------------------------------ | -| enable | boolean | required | false | | When set it to true, enable the snowflake algorithm. | -| snowflake_epoc | integer | required | 1609459200000 | | Start timestamp (in milliseconds) | +| enable | boolean | optional | false | | When set it to true, enable the snowflake algorithm. | +| snowflake_epoc | integer | optional | 1609459200000 | | Start timestamp (in milliseconds) | | data_machine_bits | integer | optional | 12 | | Maximum number of supported machines (processes) `1 << data_machine_bits` | | sequence_bits | integer | optional | 10 | | Maximum number of generated ID per millisecond per node `1 << sequence_bits` | | data_machine_ttl | integer | optional | 30 | | Valid time of registration of 'data_machine' in 'etcd' (unit: seconds) |