Skip to content

Instantly share code, notes, and snippets.

@chobits
Last active August 14, 2024 07:35
Show Gist options
  • Select an option

  • Save chobits/d21f21d83ca24076377ff31db7ab42c1 to your computer and use it in GitHub Desktop.

Select an option

Save chobits/d21f21d83ca24076377ff31db7ab42c1 to your computer and use it in GitHub Desktop.
perfermance test for kong old and new dns client library
--[[
run it by this command:
$ resty --shdict "kong_dns_cache 10m" --shdict "kong_dns_cache_ipc 10m" ./perf.lua
]]
pcall(require, "luarocks.loader")
require("kong.globalpatches")()
local _writefile = require("pl.utils").writefile
local tmpname = require("pl.path").tmpname
-- hosted in Route53 in the AWS sandbox
local TEST_DOMAIN = "kong-gateway-testing.link"
local TEST_NS = "198.51.100.0:53"
local TEST_NS = "192.168.5.2:53" -- Kong local official env
local TEST_NS = "192.168.1.1:53"
local TEST_NSS = { TEST_NS }
local not_found_answers = { errcode = 3, errstr = "not found" }
local a_answers = {{
address = "127.0.0.1",
class = 1,
ttl = 300,
type = 1
}}
local resolv_path, hosts_path
local function writefile(path, text)
_writefile(path, type(text) == "table" and table.concat(text, "\n") or text)
end
-- create temp resolv.conf and hosts
local resolv_path = tmpname()
local hosts_path = tmpname()
ngx.log(ngx.DEBUG, "create temp resolv.conf:", resolv_path, " hosts:", hosts_path)
-- inject r.query
package.loaded["resty.dns.resolver"] = nil
local resolver = require("resty.dns.resolver")
-- replace this `query_func` upvalue to spy on resolver query calls.
local query_func = function(self, original_query_func, name, options)
return original_query_func(self, name, options)
end
local old_new = resolver.new
resolver.new = function(...)
local r, err = old_new(...)
if not r then
return nil, err
end
local original_query_func = r.query
r.query = function(self, ...)
return query_func(self, original_query_func, ...)
end
return r
end
-- restore its API overlapped by the compatible layer
package.loaded["kong.resty.dns_client"] = nil
local client = require("kong.resty.dns_client")
client.resolve = client._resolve
package.loaded["kong.resty.dns.client"] = nil
local old_client = require("kong.resty.dns.client")
--- TEST apis
local t
local function client_new(opts)
opts = opts or {}
opts.resolv_conf = resolv_path
opts.hosts = hosts_path
return client.new(opts)
end
local n
local new_delta
local old_delta
local function test_new(name, f)
print("[New DNS client]", name)
writefile(resolv_path, {
"nameserver " .. TEST_NS
})
local cli = assert(client_new({ order = { "LAST", "SRV", "A", "AAAA", "CNAME" } }))
t = os.clock()
f(cli)
new_delta = os.clock() - t
print("It consumes: ", new_delta, "s")
end
local function test_old(name, f)
print("[Old DNS client]", name)
assert(old_client.init({
resolvConf = { "nameserver " .. TEST_NS,
order = { "LAST", "SRV", "A", "CNAME" }
}}))
local t = os.clock()
f()
old_delta = os.clock() - t
print("It consumes: ", old_delta, "s")
local improved = (n/new_delta)/(n/old_delta) - 1
print(("Improved: %.2f%%\n"):format(improved * 100))
end
--- run test
print("\n\n\n\n\n--- runing perf test ---\n")
--------------------
n = 1000000
local title = "+ REAL SENARIO: miss the first time, hit 99%"
test_new(title, function (cli)
local answers, err, tries
answers, err, tries = cli:resolve("www.konghq.com")
t = os.clock() -- skip first miss
for i = 1, n do
answers, err, tries = cli:resolve("www.konghq.com")
end
assert(answers[1].name == "www.konghq.com")
end)
test_old(title, function ()
local answers, err, tries
answers, err, tries = old_client.resolve("www.konghq.com")
t = os.clock() -- skip first miss
for i = 1, n do
answers, err, tries = old_client.resolve("www.konghq.com")
end
assert(answers[1].name == "www.konghq.com")
end)
test_new(title .. " qtype=A", function (cli)
local answers, err, tries
answers, err, tries = cli:resolve("www.konghq.com", {qtype=1})
t = os.clock() -- skip first miss
for i = 1, n do
answers, err, tries = cli:resolve("www.konghq.com", {qtype=1})
end
assert(answers[1].name == "www.konghq.com")
end)
test_old(title .. "qtype=A", function ()
local answers, err, tries
answers, err, tries = old_client.resolve("www.konghq.com", {qtype=1})
t = os.clock() -- skip first miss
for i = 1, n do
answers, err, tries = old_client.resolve("www.konghq.com", {qtype=1})
end
assert(answers[1].name == "www.konghq.com")
end)
--------------------
n = 10000
local title = "+ 100% miss, query suceeds (subtracting network I/O time.)"
local count = 0
query_func = function(self, original_query_func, name, options)
count = count + 1
if options.qtype == 33 then
return not_found_answers
end
a_answers[1].name = name
return a_answers
end
test_new(title, function (cli)
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = cli:resolve(i .. ".konghq.com")
end
assert(answers[1].name == n .. ".konghq.com")
assert(count == 2 * n)
end)
test_old(title, function ()
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = old_client.resolve(i .. ".konghq.com")
end
assert(answers[1].name == n .. ".konghq.com")
assert(count == 2 * n)
end)
test_new(title .. " qtype=A", function (cli)
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = cli:resolve(i .. ".konghq.com", {qtype=1})
end
assert(answers[1].name == n .. ".konghq.com")
assert(count == n)
end)
test_old(title .. " qtype=A", function ()
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = old_client.resolve(i .. ".konghq.com", {qtype =1})
end
assert(answers[1].name == n .. ".konghq.com")
assert(count == n)
end)
--------------------
n = 10000
local title = "+ 100% miss, query gets empty record (subtracting network I/O time)."
local count = 0
query_func = function(self, original_query_func, name, options)
-- print(" query: ", name .. options.qtype)
count = count + 1
return not_found_answers
end
test_new(title, function (cli)
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = cli:resolve(i .. ".konghq.com")
end
assert(not answers)
assert(count == 4 * n)
end)
test_old(title, function ()
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = old_client.resolve(i .. ".konghq.com")
end
--assert(not answers)
assert(count == 4 * n)
end)
test_new(title .. " qtype=A", function (cli)
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = cli:resolve(i .. ".konghq.com", {qtype=1})
end
assert(not answers)
assert(count == n)
end)
test_old(title .. " qtype=A", function ()
local answers, err, tries
count = 0
for i = 1, n do
answers, err, tries = old_client.resolve(i .. ".konghq.com", {qtype=1})
end
--assert(not answers)
assert(count == n)
end)
--- end
if resolv_path then
os.remove(resolv_path)
end
if hosts_path then
os.remove(hosts_path)
end
@chobits
Copy link
Author

chobits commented Aug 14, 2024

how to test: link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment