You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/06/28 10:14:49 UTC

[incubator-apisix] branch master updated: optimize: Use lru to avoid resolving IP addresses repeatedly . (#1772)

This is an automated email from the ASF dual-hosted git repository.

membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new ee75338  optimize: Use lru to avoid resolving IP addresses repeatedly . (#1772)
ee75338 is described below

commit ee7533874d3e7068903238eea5f1915cb34cbbcd
Author: YuanSheng Wang <me...@gmail.com>
AuthorDate: Sun Jun 28 18:14:38 2020 +0800

    optimize: Use lru to avoid resolving IP addresses repeatedly . (#1772)
    
    * optimize: Use lru to avoid resolving IP addresses repeatedly .
    Cached the global rules to `ctx` .
    
    * optimzie: used a longer time interval for etcd and flush access log.
    
    * optimize: return upstream node directly if the count is 1 .
    
    * optimize: avoid to cache useless variable.
---
 apisix/balancer.lua                   | 72 +++++++++++++++++++++++------------
 apisix/init.lua                       | 17 +++++----
 apisix/plugin.lua                     |  3 +-
 benchmark/fake-apisix/conf/nginx.conf | 10 +++--
 benchmark/fake-apisix/lua/apisix.lua  |  8 +++-
 bin/apisix                            |  2 +-
 conf/config.yaml                      |  2 +-
 t/admin/balancer.t                    | 46 ++++++++++++++++++++--
 8 files changed, 117 insertions(+), 43 deletions(-)

diff --git a/apisix/balancer.lua b/apisix/balancer.lua
index 8b544fe..1675128 100644
--- a/apisix/balancer.lua
+++ b/apisix/balancer.lua
@@ -39,6 +39,9 @@ local lrucache_server_picker = core.lrucache.new({
 local lrucache_checker = core.lrucache.new({
     ttl = 300, count = 256
 })
+local lrucache_addr = core.lrucache.new({
+    ttl = 300, count = 1024 * 4
+})
 
 
 local _M = {
@@ -143,25 +146,47 @@ local function create_server_picker(upstream, checker)
 end
 
 
+local function parse_addr(addr)
+    local host, port, err = core.utils.parse_addr(addr)
+    return {host = host, port = port}, err
+end
+
+
 local function pick_server(route, ctx)
     core.log.info("route: ", core.json.delay_encode(route, true))
     core.log.info("ctx: ", core.json.delay_encode(ctx, true))
-    local healthcheck_parent = ctx.upstream_healthcheck_parent
     local up_conf = ctx.upstream_conf
-    local version = ctx.upstream_version
-    local key = ctx.upstream_key
-
     if up_conf.service_name then
         if not discovery then
-            return nil, nil, "discovery is uninitialized"
+            return nil, "discovery is uninitialized"
         end
         up_conf.nodes = discovery.nodes(up_conf.service_name)
     end
 
-    if not up_conf.nodes or #up_conf.nodes == 0 then
-        return nil, nil, "no valid upstream node"
+    local nodes_count = up_conf.nodes and #up_conf.nodes or 0
+    if nodes_count == 0 then
+        return nil, "no valid upstream node"
+    end
+
+    if up_conf.timeout then
+        local timeout = up_conf.timeout
+        local ok, err = set_timeouts(timeout.connect, timeout.send,
+                                     timeout.read)
+        if not ok then
+            core.log.error("could not set upstream timeouts: ", err)
+        end
     end
 
+    if nodes_count == 1 then
+        local node = up_conf.nodes[1]
+        ctx.balancer_ip = node.host
+        ctx.balancer_port = node.port
+        return node
+    end
+
+    local healthcheck_parent = ctx.upstream_healthcheck_parent
+    local version = ctx.upstream_version
+    local key = ctx.upstream_key
     local checker = fetch_healthchecker(up_conf, healthcheck_parent, version)
 
     ctx.balancer_try_count = (ctx.balancer_try_count or 0) + 1
@@ -197,28 +222,25 @@ local function pick_server(route, ctx)
     local server_picker = lrucache_server_picker(key, version,
                             create_server_picker, up_conf, checker)
     if not server_picker then
-        return nil, nil, "failed to fetch server picker"
+        return nil, "failed to fetch server picker"
     end
 
     local server, err = server_picker.get(ctx)
     if not server then
         err = err or "no valid upstream node"
-        return nil, nil, "failed to find valid upstream server, " .. err
+        return nil, "failed to find valid upstream server, " .. err
     end
 
-    if up_conf.timeout then
-        local timeout = up_conf.timeout
-        local ok, err = set_timeouts(timeout.connect, timeout.send, timeout.read)
-        if not ok then
-            core.log.error("could not set upstream timeouts: ", err)
-        end
+    local res, err = lrucache_addr(server, nil, parse_addr, server)
+    ctx.balancer_ip = res.host
+    ctx.balancer_port = res.port
+    -- core.log.info("proxy to ", host, ":", port)
+    if err then
+        core.log.error("failed to parse server addr: ", server, " err: ", err)
+        return core.response.exit(502)
     end
 
-    local ip, port, err = core.utils.parse_addr(server)
-    ctx.balancer_ip = ip
-    ctx.balancer_port = port
-    core.log.info("proxy to ", ip, ":", port)
-    return ip, port, err
+    return res
 end
 
 
@@ -227,16 +249,16 @@ _M.pick_server = pick_server
 
 
 function _M.run(route, ctx)
-    local ip, port, err = pick_server(route, ctx)
-    if err then
+    local server, err = pick_server(route, ctx)
+    if not server then
         core.log.error("failed to pick server: ", err)
         return core.response.exit(502)
     end
 
-    local ok, err = balancer.set_current_peer(ip, port)
+    local ok, err = balancer.set_current_peer(server.host, server.port)
     if not ok then
-        core.log.error("failed to set server peer [", ip, ":", port,
-                       "] err: ", err)
+        core.log.error("failed to set server peer [", server.host, ":",
+                       server.port, "] err: ", err)
         return core.response.exit(502)
     end
 
diff --git a/apisix/init.lua b/apisix/init.lua
index 2447165..41295f0 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -112,7 +112,7 @@ local function run_plugin(phase, plugins, api_ctx)
     end
 
     plugins = plugins or api_ctx.plugins
-    if not plugins then
+    if not plugins or #plugins == 0 then
         return api_ctx
     end
 
@@ -262,6 +262,8 @@ function _M.http_access_phase()
         api_ctx.conf_type = nil
         api_ctx.conf_version = nil
         api_ctx.conf_id = nil
+
+        api_ctx.global_rules = router.global_rules
     end
 
     router.router_http.match(api_ctx)
@@ -433,25 +435,24 @@ function _M.grpc_access_phase()
 end
 
 
-local function common_phase(plugin_name)
+local function common_phase(phase_name)
     local api_ctx = ngx.ctx.api_ctx
     if not api_ctx then
         return
     end
 
-    if router.global_rules and router.global_rules.values
-            and #router.global_rules.values > 0
-    then
+    if api_ctx.global_rules then
         local plugins = core.tablepool.fetch("plugins", 32, 0)
-        local values = router.global_rules.values
+        local values = api_ctx.global_rules.values
         for _, global_rule in config_util.iterate_values(values) do
             core.table.clear(plugins)
             plugins = plugin.filter(global_rule, plugins)
-            run_plugin(plugin_name, plugins, api_ctx)
+            run_plugin(phase_name, plugins, api_ctx)
         end
         core.tablepool.release("plugins", plugins)
     end
-    run_plugin(plugin_name, nil, api_ctx)
+
+    run_plugin(phase_name, nil, api_ctx)
     return api_ctx
 end
 
diff --git a/apisix/plugin.lua b/apisix/plugin.lua
index 8186d15..075d058 100644
--- a/apisix/plugin.lua
+++ b/apisix/plugin.lua
@@ -235,7 +235,8 @@ end
 function _M.filter(user_route, plugins)
     plugins = plugins or core.table.new(#local_plugins * 2, 0)
     local user_plugin_conf = user_route.value.plugins
-    if user_plugin_conf == nil then
+    if user_plugin_conf == nil or
+       core.table.nkeys(user_plugin_conf) == 0 then
         if local_conf and local_conf.apisix.enable_debug then
             core.response.set_header("Apisix-Plugins", "no plugin")
         end
diff --git a/benchmark/fake-apisix/conf/nginx.conf b/benchmark/fake-apisix/conf/nginx.conf
index 327169a..8666c29 100644
--- a/benchmark/fake-apisix/conf/nginx.conf
+++ b/benchmark/fake-apisix/conf/nginx.conf
@@ -24,7 +24,6 @@ pid logs/nginx.pid;
 worker_rlimit_nofile 20480;
 
 events {
-    accept_mutex off;
     worker_connections 10620;
 }
 
@@ -33,6 +32,9 @@ worker_shutdown_timeout 3;
 http {
     lua_package_path  "$prefix/lua/?.lua;;";
 
+    log_format main '$remote_addr - $remote_user [$time_local] $http_host "$request" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent" $upstream_addr $upstream_status $upstream_response_time';
+    access_log logs/access.log main buffer=16384 flush=5;
+
     init_by_lua_block {
         require "resty.core"
         apisix = require("apisix")
@@ -60,8 +62,6 @@ http {
 
         listen 9080;
 
-        access_log off;
-
         server_tokens off;
         more_set_headers 'Server: APISIX web server';
 
@@ -106,6 +106,10 @@ http {
                 apisix.http_header_filter_phase()
             }
 
+            body_filter_by_lua_block {
+                apisix.http_body_filter_phase()
+            }
+
             log_by_lua_block {
                 apisix.http_log_phase()
             }
diff --git a/benchmark/fake-apisix/lua/apisix.lua b/benchmark/fake-apisix/lua/apisix.lua
index 30671f7..ea5bf15 100644
--- a/benchmark/fake-apisix/lua/apisix.lua
+++ b/benchmark/fake-apisix/lua/apisix.lua
@@ -25,7 +25,7 @@ end
 
 local function fake_fetch()
     ngx.ctx.ip = "127.0.0.1"
-    ngx.ctx.port = 80
+    ngx.ctx.port = 1980
 end
 
 function _M.http_access_phase()
@@ -42,6 +42,12 @@ function _M.http_header_filter_phase()
     end
 end
 
+function _M.http_body_filter_phase()
+    if ngx.ctx then
+        -- do something
+    end
+end
+
 function _M.http_log_phase()
     if ngx.ctx then
         -- do something
diff --git a/bin/apisix b/bin/apisix
index bdda184..d2d6f90 100755
--- a/bin/apisix
+++ b/bin/apisix
@@ -229,7 +229,7 @@ http {
 
     log_format main '$remote_addr - $remote_user [$time_local] $http_host "$request" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent" $upstream_addr $upstream_status $upstream_response_time';
 
-    access_log {* http.access_log *} main buffer=16384 flush=1;
+    access_log {* http.access_log *} main buffer=16384 flush=3;
     open_file_cache  max=1000 inactive=60;
     client_max_body_size 0;
     keepalive_timeout {* http.keepalive_timeout *};
diff --git a/conf/config.yaml b/conf/config.yaml
index fe7716d..53787a6 100644
--- a/conf/config.yaml
+++ b/conf/config.yaml
@@ -121,7 +121,7 @@ etcd:
   host:                           # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
     - "http://127.0.0.1:2379"     # multiple etcd address
   prefix: "/apisix"               # apisix configurations prefix
-  timeout: 3                      # 3 seconds
+  timeout: 30                     # 3 seconds
   # user: root                     # root username for etcd
   # password: 5tHkHhYkjr6cQY        # root password for etcd
 #eureka:
diff --git a/t/admin/balancer.t b/t/admin/balancer.t
index c3ec573..1afceda 100644
--- a/t/admin/balancer.t
+++ b/t/admin/balancer.t
@@ -33,13 +33,13 @@ add_block_preprocessor(sub {
         local balancer = require("apisix.balancer")
         local res = {}
         for i = 1, count or 12 do
-            local host, port, err = balancer.pick_server(route, ctx)
+            local server, err = balancer.pick_server(route, ctx)
             if err then
                 ngx.say("failed: ", err)
             end
 
-            core.log.warn("host: ", host, " port: ", port)
-            res[host] = (res[host] or 0) + 1
+            core.log.warn("host: ", server.host, " port: ", server.port)
+            res[server.host] = (res[server.host] or 0) + 1
         end
 
         local keys = {}
@@ -144,6 +144,7 @@ host: 39.97.63.217 count: 6
             -- cached by version
             up_conf.nodes = {
                 {host = "39.97.63.218", port = 80, weight = 1},
+                {host = "39.97.63.219", port = 80, weight = 0},
             }
             test(route, ctx)
 
@@ -192,6 +193,7 @@ host: 39.97.63.218 count: 12
             -- cached by version
             up_conf.nodes = {
                 {host = "39.97.63.218", port = 80, weight = 1},
+                {host = "39.97.63.219", port = 80, weight = 0},
             }
             test(route, ctx)
 
@@ -208,3 +210,41 @@ host: 39.97.63.215 count: 12
 host: 39.97.63.218 count: 12
 --- no_error_log
 [error]
+
+
+
+=== TEST 5: return item directly if only have one item in `nodes`
+--- config
+    location /t {
+        content_by_lua_block {
+            local up_conf = {
+                type = "roundrobin",
+                nodes = {
+                    {host = "39.97.63.215", port = 80, weight = 1},
+                    {host = "39.97.63.216", port = 81, weight = 1},
+                    {host = "39.97.63.217", port = 82, weight = 1},
+                }
+            }
+            local ctx = {}
+            ctx.upstream_conf = up_conf
+            ctx.upstream_version = 1
+            ctx.upstream_key = up_conf.type .. "#route_" .. "id"
+
+            test(route, ctx)
+
+            -- one item in nodes, return it directly
+            up_conf.nodes = {
+                {host = "39.97.63.218", port = 80, weight = 1},
+            }
+            test(route, ctx)
+        }
+    }
+--- request
+GET /t
+--- response_body
+host: 39.97.63.215 count: 4
+host: 39.97.63.216 count: 4
+host: 39.97.63.217 count: 4
+host: 39.97.63.218 count: 12
+--- no_error_log
+[error]