Область видимости переменной Nginx lua openresty

Вот рабочий пример файла openresty nginx.conf. В этом примере я делаю запрос к Redis несколько раз. Как вы можете видеть, я сначала запрашиваю данные у Redis, чтобы проверить, может ли домен получить SSL, а затем снова, чтобы получить, к какому бэкэнду запрашивать прокси, а затем я добавил прокси-сервер S3, и мне нужно будет снова запросить данные от Redis. Я новичок в OpenResty и Lua, и мне интересно, можно ли получить данные из Redis один раз и использовать их несколько раз в сценарии?

user www-data;
worker_processes  auto;
pid /run/openresty.pid;

events {
    worker_connections  1024;
}

error_log /var/log/openresty/error.log debug;

http {
    resolver 127.0.0.53 ipv6=off;
    lua_shared_dict acme 16m;

    init_by_lua_block {
        require("resty.acme.autossl").init({
            tos_accepted = true,
            staging = true,
            account_key_path = "/etc/openresty/account.key",
            account_email = "[email protected]",
            domain_whitelist_callback = function(domain)
                local redis = require "resty.redis"
                local rds = redis:new()

                local ok, err = rds:connect("127.0.0.1", 6379)
                if not ok then
                    ngx.log(ngx.ERR, "failed to connect to redis: ", err)
                    return ngx.exit(500)
                end

                local res, err = rds:exists(domain)

                if res == 1 then
                    return true
                end
                if res == 0 then
                    return false
                end
            end
        })
    }

    init_worker_by_lua_block {
        require("resty.acme.autossl").init_worker()
    }

    server {
        access_log /var/log/openresty/access.log;

        listen 80;
        listen 443 ssl;
        server_name _;

        location / {
            set $backend '';
            set $tenant '';

            access_by_lua '
                local domain = ngx.req.get_headers()["Host"]
                local key = "site:" .. domain

                if not domain then
                ngx.log(ngx.ERR, "message 404 missing")
                return ngx.exit(404)
                end

                local redis =  require "resty.redis"
                local rds = redis:new()

                local ok, err = rds:connect("127.0.0.1", 6379)
                if not ok then
                    ngx.log(ngx.ERR, "failed to connect to redis: ", err)
                    return ngx.exit(500)
                end

                local all, err = rds:hgetall(key)
                if not all then
                    ngx.log(ngx.ERR, "no komprende: ", err)
                    return ngx.exit(505)
                end

                if all == ngx.null then
                    ngx.log(ngx.ERR, "no host found for key ", key)
                    return ngx.exit(404)
                end

                local result = {}
                    for i = 1, #all, 2 do
                    result[all[i]] = all[i+1]
                end

                ngx.var.backend = result["backend"]
                ngx.var.tenant = result["tenantID"]

                ngx.log(ngx.ERR, "uhm: ", ngx.var.backend)
            ';

            add_header X-TenantID $tenant always;
            proxy_pass http://$backend;

        }

        location ~* ^/static/(.*) {
            resolver               127.0.0.53 valid=300s;
            resolver_timeout       10s;
            set $s3_bucket        'drasha.ams3.digitaloceanspaces.com';
            set $url_full         '$1';
            proxy_http_version     1.1;
            proxy_set_header       Host $s3_bucket;
            proxy_set_header       Authorization '';
            proxy_hide_header      x-amz-id-2;
            proxy_hide_header      x-amz-request-id;
            proxy_hide_header      Set-Cookie;
            proxy_ignore_headers   "Set-Cookie";
            proxy_buffering        off;
            proxy_intercept_errors on;
            proxy_pass             http://$s3_bucket/AYAYA/$url_full;
        }

        lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
        lua_ssl_verify_depth 2;
        ssl_certificate /etc/openresty/default.pem;
        ssl_certificate_key /etc/openresty/default.key;
        ssl_certificate_by_lua_block {
            require("resty.acme.autossl").ssl_certificate()
        }

        location /.well-known {
            content_by_lua_block {
                require("resty.acme.autossl").serve_http_challenge()
            }
        }
    }
}

person toHo    schedule 28.11.2020    source источник


Ответы (1)


OpenResty запускает хуки Lua в песочнице, поэтому нельзя использовать глобальные переменные для обмена данными.

Вы должны использовать обмен данными в Nginx Worker Обычной практикой является кэширование чего-либо на уровне модуля Lua, возможно, с некоторым разумным сроком действия, если данные, хранящиеся в Redis, могут быть изменены.

Кстати, не используйте директивы XXX_by_lua — вы должны позаботиться о правилах экранирования nginx, используйте XXX_by_lua_block.

Дополнительный пример:

local redis = require"resty-redis"

-- the module
local _M = {}

local hgetall_results = {}
_M.hgetall = function(key)
  if hgetall_results[key] then
    return hgetall_results[key]
  end
  local rds = redis:new()
  local ok, err = rds:connect("127.0.0.1", 6379)
  local all, err = rds:hgetall(key)
  local result = {}
  for i = 1, #all, 2 do
     result[all[i]] = all[i+1]
  end
  -- cache 
  hgetall_results[key] = result
  return result
end

return _M

Приведенный выше пример просто иллюстрирует обычный шаблон кэширования модуля. Обработка ошибок осуществляется самостоятельно.

person Alexander Altshuler    schedule 30.11.2020
comment
спасибо за Ваш ответ. Можете ли вы привести пример, как это будет работать в моем случае? Я видел ссылку на документацию, но это статический ресурс. Если я напишу запрос Redis внутри этого модуля и импортирую его во все свои блоки, похоже, что у меня все еще будет несколько вызовов Redis, только внутри модуля, не могли бы вы поделиться минимальным допустимым примером? - person toHo; 01.12.2020