perf: enable local cache and use `tablepool` to reuse the temporary table (#49)
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000..6b3ce04
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1,4 @@
+std = "ngx_lua"
+unused_args = false
+redefined = false
+max_line_length = 100
diff --git a/README.md b/README.md
index d3f180a..d8606c3 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,16 @@
metadata_buffer:set('serviceInstanceName', 'User Service Instance Name')
-- type 'boolean', mark the entrySpan include host/domain
metadata_buffer:set('includeHostInEntrySpan', false)
-
+
-- set random seed
require("skywalking.util").set_randomseed()
require("skywalking.client"):startBackendTimer("http://127.0.0.1:8080")
+
+ -- If there is a bug of this `tablepool` implementation, we can
+ -- disable it in this way
+ -- require("skywalking.util").disable_tablepool()
+
+ skywalking_tracer = require("skywalking.tracer")
}
@@ -52,9 +58,9 @@
--
-- Currently, we can not have the upstream real network address
------------------------------------------------------
- require("skywalking.tracer"):start("upstream service")
+ skywalking_tracer:start("upstream service")
-- If you want correlation custom data to the downstream service
- -- require("skywalking.tracer"):start("upstream service", {custom = "custom_value"})
+ -- skywalking_tracer:start("upstream service", {custom = "custom_value"})
}
-- Target upstream service
@@ -62,12 +68,12 @@
body_filter_by_lua_block {
if ngx.arg[2] then
- require("skywalking.tracer"):finish()
+ skywalking_tracer:finish()
end
}
log_by_lua_block {
- require("skywalking.tracer"):prepareForReport()
+ skywalking_tracer:prepareForReport()
}
}
}
diff --git a/examples/nginx.conf b/examples/nginx.conf
index 0039bc8..3c6da29 100644
--- a/examples/nginx.conf
+++ b/examples/nginx.conf
@@ -40,11 +40,19 @@
-- type 'boolean', mark the entrySpan include host/domain
metadata_buffer:set('includeHostInEntrySpan', false)
+ -- set randomseed
require("skywalking.util").set_randomseed()
+
require("skywalking.client"):startBackendTimer("http://127.0.0.1:8080")
-- Any time you want to stop reporting metrics, call `destroyBackendTimer`
-- require("skywalking.client"):destroyBackendTimer()
+
+ -- If there is a bug of this `tablepool` implementation, we can
+ -- disable it in this way
+ -- require("skywalking.util").disable_tablepool()
+
+ skywalking_tracer = require("skywalking.tracer")
}
@@ -62,21 +70,21 @@
--
-- Currently, we can not have the upstream real network address
------------------------------------------------------
- require("skywalking.tracer"):start("upstream service")
+ skywalking_tracer:start("upstream service")
-- If you want correlation custom data to the downstream service
- -- require("skywalking.tracer"):start("upstream service", {custom = "custom_value"})
+ -- skywalking_tracer:start("upstream service", {custom = "custom_value"})
}
proxy_pass http://127.0.0.1:8080/tier2/lb;
body_filter_by_lua_block {
if ngx.arg[2] then
- require("skywalking.tracer"):finish()
+ skywalking_tracer:finish()
end
}
log_by_lua_block {
- require("skywalking.tracer"):prepareForReport()
+ skywalking_tracer:prepareForReport()
}
}
@@ -84,19 +92,19 @@
default_type text/html;
rewrite_by_lua_block {
- require("skywalking.tracer"):start("backend service")
+ skywalking_tracer:start("backend service")
}
proxy_pass http://127.0.0.1:8080/backend;
body_filter_by_lua_block {
if ngx.arg[2] then
- require("skywalking.tracer"):finish()
+ skywalking_tracer:finish()
end
}
log_by_lua_block {
- require("skywalking.tracer"):prepareForReport()
+ skywalking_tracer:prepareForReport()
}
}
diff --git a/lib/skywalking/client.lua b/lib/skywalking/client.lua
index 783cf64..ed22699 100644
--- a/lib/skywalking/client.lua
+++ b/lib/skywalking/client.lua
@@ -17,6 +17,7 @@
local Const = require('skywalking.constants')
+local ngx = ngx
local SEGMENT_BATCH_COUNT = 100
local Client = {
@@ -34,7 +35,6 @@
local check
local log = ngx.log
- local DEBUG = ngx.DEBUG
local ERR = ngx.ERR
check = function(premature)
@@ -118,7 +118,6 @@
-- Ping the backend to update instance heartheat
function Client:ping(metadata_buffer, backend_http_uri)
local log = ngx.log
- local DEBUG = ngx.DEBUG
local ERR = ngx.ERR
local serviceName = metadata_buffer:get('serviceName')
@@ -153,7 +152,6 @@
-- Send segemnts data to backend
local function sendSegments(segmentTransform, backend_http_uri)
local log = ngx.log
- local DEBUG = ngx.DEBUG
local ERR = ngx.ERR
local http = require('resty.http')
@@ -184,7 +182,6 @@
function Client:reportTraces(metadata_buffer, backend_http_uri)
local log = ngx.log
local DEBUG = ngx.DEBUG
- local ERR = ngx.ERR
local queue = ngx.shared.tracing_buffer
local segment = queue:rpop(Const.segment_queue)
diff --git a/lib/skywalking/segment.lua b/lib/skywalking/segment.lua
index 77ccea6..f379103 100644
--- a/lib/skywalking/segment.lua
+++ b/lib/skywalking/segment.lua
@@ -18,6 +18,7 @@
-- Segment represents a finished tracing context
-- Including all information to send to the SkyWalking OAP server.
local Span = require('skywalking.span')
+local Util = require('skywalking.util')
local _M = {}
-- local Segment = {
@@ -42,17 +43,16 @@
-- Return SegmentProtocol
function _M.transform(segment)
- local segmentBuilder = {}
+ local segmentBuilder = Util.tablepool_fetch()
segmentBuilder.traceId = segment.trace_id
segmentBuilder.traceSegmentId = segment.segment_id
segmentBuilder.service = segment.service
segmentBuilder.serviceInstance = segment.service_instance
- segmentBuilder.spans = {}
+ segmentBuilder.spans = Util.tablepool_fetch()
if segment.spans ~= nil and #segment.spans > 0 then
- for i, span in ipairs(segment.spans)
- do
+ for _, span in ipairs(segment.spans) do
segmentBuilder.spans[#segmentBuilder.spans + 1] = Span.transform(span)
end
end
diff --git a/lib/skywalking/span.lua b/lib/skywalking/span.lua
index 3882d6c..ce52b01 100644
--- a/lib/skywalking/span.lua
+++ b/lib/skywalking/span.lua
@@ -18,6 +18,7 @@
local spanLayer = require("skywalking.span_layer")
local Util = require('skywalking.util')
local SegmentRef = require("skywalking.segment_ref")
+local table = table
local CONTEXT_CARRIER_KEY = 'sw8'
@@ -76,7 +77,7 @@
-- If current trace id is generated by the context, in LUA case, mostly are yes
-- use the ref trace id to override it, in order to keep trace id consistently same.
context.internal.addRefIfFirst(context.internal, ref)
- span.refs[#span.refs + 1] = ref
+ table.insert(span.refs, ref)
end
end
end
@@ -143,13 +144,13 @@
end
function _M.newNoOP()
- return {
- layer = spanLayer.NONE,
- is_entry = false,
- is_exit = false,
- error_occurred = false,
- is_noop = true
- }
+ local obj = Util.tablepool_fetch()
+ obj.layer = spanLayer.NONE
+ obj.is_entry = false
+ obj.is_exit = false
+ obj.error_occurred = false
+ obj.is_noop = true
+ return obj
end
---- All belowing are instance methods
@@ -240,28 +241,29 @@
end
if span.logs == nil then
- span.logs = {}
+ span.logs = Util.tablepool_fetch()
end
- local logEntity = {time = timestamp, data = keyValuePairs}
- span.logs[#span.logs + 1] = logEntity
+ local logEntity = Util.tablepool_fetch()
+ logEntity.time = timestamp
+ logEntity.data = keyValuePairs
+ table.insert(span.logs, logEntity)
return span
end
-- Return SpanProtocol
function _M.transform(span)
- local spanBuilder = {}
+ local spanBuilder = Util.tablepool_fetch("sw_spanBuilder", 0, 32)
spanBuilder.spanId = span.span_id
spanBuilder.parentSpanId = span.parent_span_id
spanBuilder.startTime = span.start_time
spanBuilder.endTime = span.end_time
-- Array of RefProtocol
if #span.refs > 0 then
- spanBuilder.refs = {}
- for i, ref in ipairs(span.refs)
- do
- spanBuilder.refs[#spanBuilder.refs + 1] = SegmentRef.transform(ref)
+ spanBuilder.refs = Util.tablepool_fetch("sw_spanBuilder_refs", 4, 0)
+ for _, ref in ipairs(span.refs) do
+ table.insert(spanBuilder.refs, SegmentRef.transform(ref))
end
end
diff --git a/lib/skywalking/span_layer.lua b/lib/skywalking/span_layer.lua
index fcf0baa..6d05411 100644
--- a/lib/skywalking/span_layer.lua
+++ b/lib/skywalking/span_layer.lua
@@ -1,19 +1,19 @@
---
+--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
---
+--
-- http://www.apache.org/licenses/LICENSE-2.0
---
+--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
---
+--
local Layer = {
NONE = {name = "Unknown", value=0},
diff --git a/lib/skywalking/tracer.lua b/lib/skywalking/tracer.lua
index 9e5a3cd..88941b2 100644
--- a/lib/skywalking/tracer.lua
+++ b/lib/skywalking/tracer.lua
@@ -18,7 +18,7 @@
local TC = require('skywalking.tracing_context')
local Layer = require('skywalking.span_layer')
local Segment = require('skywalking.segment')
-local Util = require('skywalking.util')
+local Util = require("skywalking.util")
local Const = require('skywalking.constants')
local json = require('cjson.safe')
@@ -39,16 +39,17 @@
-- Constant pre-defined in SkyWalking main repo
-- 6000 represents Nginx
- local contextCarrier = {}
+ local req_uri = ngx.var.uri
+
+ local contextCarrier = Util.tablepool_fetch("sw_contextCarrier")
contextCarrier["sw8"] = ngx.var.http_sw8
contextCarrier["sw8-correlation"] = ngx.var.http_sw8_correlation
-
local time_now = ngx.now() * 1000
local entrySpan
if (includeHostInEntrySpan) then
- entrySpan = TC.createEntrySpan(tracingContext, ngx.var.host .. ngx.var.uri, nil, contextCarrier)
+ entrySpan = TC.createEntrySpan(tracingContext, ngx.var.host .. req_uri, nil, contextCarrier)
else
- entrySpan = TC.createEntrySpan(tracingContext, ngx.var.uri, nil, contextCarrier)
+ entrySpan = TC.createEntrySpan(tracingContext, req_uri, nil, contextCarrier)
end
Span.start(entrySpan, time_now)
Span.setComponentId(entrySpan, nginxComponentId)
@@ -58,13 +59,12 @@
Span.tag(entrySpan, 'http.params',
ngx.var.scheme .. '://' .. ngx.var.host .. ngx.var.request_uri )
- contextCarrier = {}
+ contextCarrier = Util.tablepool_fetch("sw_contextCarrier")
-- Use the same URI to represent incoming and forwarding requests
-- Change it if you need.
- local upstreamUri = ngx.var.uri
local upstreamServerName = upstream_name
------------------------------------------------------
- local exitSpan = TC.createExitSpan(tracingContext, upstreamUri, entrySpan,
+ local exitSpan = TC.createExitSpan(tracingContext, req_uri, entrySpan,
upstreamServerName, contextCarrier, correlation)
Span.start(exitSpan, time_now)
Span.setComponentId(exitSpan, nginxComponentId)
@@ -117,14 +117,16 @@
ngx.log(ngx.ERR, "failed to encode segment: ", err)
return
end
- ngx.log(ngx.DEBUG, 'segment = ', segmentJson)
+ -- ngx.log(ngx.DEBUG, 'segment = ', segmentJson)
local length, err = metadata_shdict:lpush(Const.segment_queue, segmentJson)
if not length then
ngx.log(ngx.ERR, "failed to push segment: ", err)
return
end
- ngx.log(ngx.DEBUG, 'segment buffer size = ', length)
+ -- ngx.log(ngx.DEBUG, 'segment buffer size = ', length)
+
+ Util.tablepool_release()
end
return Tracer
diff --git a/lib/skywalking/tracing_context.lua b/lib/skywalking/tracing_context.lua
index 3da161a..8e19b63 100644
--- a/lib/skywalking/tracing_context.lua
+++ b/lib/skywalking/tracing_context.lua
@@ -77,13 +77,13 @@
-- Create an internal instance
function Internal.new()
- local internal = {}
+ local internal = Util.tablepool_fetch()
internal.self_generated_trace_id = true
internal.span_id_seq = 0
- internal.active_spans = {}
+ internal.active_spans = Util.tablepool_fetch()
internal.active_count = 0
- internal.finished_spans = {}
+ internal.finished_spans = Util.tablepool_fetch()
internal.addRefIfFirst = addRefIfFirst
internal.addActive = addActive
internal.finishSpan = finishSpan
@@ -112,7 +112,7 @@
return _M.newNoOP()
end
- local tracing_context = {}
+ local tracing_context = Util.tablepool_fetch()
tracing_context.trace_id = Util.newID()
tracing_context.segment_id = tracing_context.trace_id
tracing_context.service = serviceName
@@ -173,7 +173,7 @@
if tracingContext.internal.active_count ~= 0 then
return false, nil
else
- local segment = {}
+ local segment = Util.tablepool_fetch()
segment.trace_id = tracingContext.trace_id
segment.segment_id = tracingContext.segment_id
segment.service = tracingContext.service
diff --git a/lib/skywalking/util.lua b/lib/skywalking/util.lua
index 15eb7eb..942306b 100644
--- a/lib/skywalking/util.lua
+++ b/lib/skywalking/util.lua
@@ -119,4 +119,56 @@
end
+if _M.is_ngx_lua then
+ local tablepool = require("tablepool")
+ local clear_tab = require("table.clear")
+ local insert_tab = table.insert
+ local ngx = ngx
+ _M.tablepool_fetch = function(name, narr, nrec)
+ narr = narr or 8
+ nrec = nrec or 8
+ name = name or "sw_default_tab"
+
+ local sw_tab_pool = ngx.ctx.sw_tab_pool
+ if not sw_tab_pool then
+ sw_tab_pool = tablepool.fetch("sw_tab_pool", 128, 0)
+ insert_tab(sw_tab_pool, "sw_tab_pool")
+ insert_tab(sw_tab_pool, sw_tab_pool)
+
+ ngx.ctx.sw_tab_pool = sw_tab_pool
+ end
+
+ local tab = tablepool.fetch(name, narr, nrec)
+ insert_tab(sw_tab_pool, name)
+ insert_tab(sw_tab_pool, tab)
+ return tab
+ end
+ _M.tablepool_release = function()
+ local sw_tab_pool = ngx.ctx.sw_tab_pool
+ if not sw_tab_pool then
+ return
+ end
+
+ for i = #sw_tab_pool, 1, -2 do
+ local name = sw_tab_pool[i - 1]
+ local tab = sw_tab_pool[i]
+ tablepool.release(name, tab)
+ -- ngx.log(ngx.INFO, "release name: ", name, " ", tostring(tab))
+ end
+ clear_tab(sw_tab_pool)
+
+ ngx.ctx.sw_tab_pool = nil
+ end
+else
+ _M.tablepool_fetch = function () return {} end
+ _M.tablepool_release = function () return true end
+end
+
+
+function _M.disable_tablepool()
+ _M.tablepool_fetch = function () return {} end
+ _M.tablepool_release = function () return true end
+end
+
+
return _M
diff --git a/t/util.t b/t/util.t
index fe80bf2..0b5a027 100644
--- a/t/util.t
+++ b/t/util.t
@@ -74,3 +74,128 @@
done
--- no_error_log
[error]
+
+
+
+=== TEST 3: tablepool, use different name
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('skywalking.util')
+
+ local tab1_name = util.tablepool_fetch("name1", 1, 1)
+ local tab1_name2 = util.tablepool_fetch("name2", 1, 1)
+ util.tablepool_release()
+
+ local tab2_name = util.tablepool_fetch("name1", 1, 1)
+ local tab2_name2 = util.tablepool_fetch("name2", 1, 1)
+ util.tablepool_release()
+
+ if tab1_name == tab2_name then
+ ngx.say("fetch same table by name1")
+ else
+ ngx.say("fetch different table by name1")
+ end
+
+ if tab1_name2 == tab2_name2 then
+ ngx.say("fetch same table by name2")
+ else
+ ngx.say("fetch different table by name2")
+ end
+ }
+ }
+--- request
+GET /t
+--- response_body
+fetch same table by name1
+fetch same table by name2
+--- no_error_log
+[error]
+
+
+
+=== TEST 4: tablepool, use default name
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('skywalking.util')
+
+ local tab1_name = util.tablepool_fetch()
+ local tab1_name2 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ local tab2_name = util.tablepool_fetch()
+ local tab2_name2 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ if tab1_name == tab2_name then
+ ngx.say("fetch same table by default name[1]")
+ else
+ ngx.say("fetch different table by default name[1]")
+ end
+
+ if tab1_name2 == tab2_name2 then
+ ngx.say("fetch same table by default name[2]")
+ else
+ ngx.say("fetch different table by default name[2]")
+ end
+
+ util.tablepool_release()
+ util.tablepool_release()
+ ngx.say("done")
+ }
+ }
+--- request
+GET /t
+--- response_body
+fetch same table by default name[1]
+fetch same table by default name[2]
+done
+--- no_error_log
+[error]
+
+
+
+=== TEST 5: tablepool, call `disable_tablepool` to disable tablepool
+--- http_config eval: $::HttpConfig
+--- config
+ location /t {
+ content_by_lua_block {
+ local util = require('skywalking.util')
+
+ local tab1 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ local tab2 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ if tab1 == tab2 then
+ ngx.say("enabled tablepool: fetched same tables")
+ else
+ ngx.say("enabled tablepool: fetched different tables")
+ end
+
+ util.disable_tablepool()
+
+ local tab1 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ local tab2 = util.tablepool_fetch()
+ util.tablepool_release()
+
+ if tab1 == tab2 then
+ ngx.say("disable tablepool: fetched same tables")
+ else
+ ngx.say("disable tablepool: fetched different tables")
+ end
+ }
+ }
+--- request
+GET /t
+--- response_body
+enabled tablepool: fetched same tables
+disable tablepool: fetched different tables
+--- no_error_log
+[error]
diff --git a/test/e2e/e2e-with-mock-collector/docker/conf.d/nginx.conf b/test/e2e/e2e-with-mock-collector/docker/conf.d/nginx.conf
index cd1e679..be89a69 100644
--- a/test/e2e/e2e-with-mock-collector/docker/conf.d/nginx.conf
+++ b/test/e2e/e2e-with-mock-collector/docker/conf.d/nginx.conf
@@ -40,6 +40,12 @@
require("skywalking.util").set_randomseed()
require("skywalking.client"):startBackendTimer("http://${collector}:12800")
+
+ -- If there is a bug of this `tablepool` implementation, we can
+ -- disable it in this way
+ -- require("skywalking.util").disable_tablepool()
+
+ skywalking_tracer = require("skywalking.tracer")
}
server {
@@ -49,17 +55,17 @@
default_type text/html;
rewrite_by_lua_block {
- require("skywalking.tracer"):start("e2e-test-with-mock-collector:upstream_ip:port")
+ skywalking_tracer:start("e2e-test-with-mock-collector:upstream_ip:port")
}
proxy_pass http://127.0.0.1:8080/tier2/lb;
body_filter_by_lua_block {
- require("skywalking.tracer"):finish()
+ skywalking_tracer:finish()
}
log_by_lua_block {
- require("skywalking.tracer"):prepareForReport()
+ skywalking_tracer:prepareForReport()
}
}
@@ -67,17 +73,17 @@
default_type text/html;
rewrite_by_lua_block {
- require("skywalking.tracer"):start("e2e-test-with-mock-collector:upstream_ip2:port2")
+ skywalking_tracer:start("e2e-test-with-mock-collector:upstream_ip2:port2")
}
proxy_pass http://127.0.0.1:8080/backend;
body_filter_by_lua_block {
- require("skywalking.tracer"):finish()
+ skywalking_tracer:finish()
}
log_by_lua_block {
- require("skywalking.tracer"):prepareForReport()
+ skywalking_tracer:prepareForReport()
}
}