lua-resty-dymetrics

重新編譯 OpenResty

動態指標模組需要給 Nginx 核心打補丁,因此需要重新編譯 OpenResty。 這個補丁我們會透過郵件的方式進行交付。

下面的指令碼用於給 OpenResty 1.19.9.1 版本的 Nginx 核心打補丁。 打完補丁後,使用者可以根據原來的打包流程進行打包。

set -e
pkg=openresty-1.19.9.1
ngx=nginx-1.19.9

wget https://openresty.org/download/$pkg.tar.gz
tar -xf $pkg.tar.gz

cd $pkg/bundle/$ngx/
patch -p1 < ../../../nginx-1.19.9-proc_exit_handler.patch
cd ../../..

tar -czf $pkg.tar.gz  $pkg

配置二進位制安裝包倉庫

首先我們需要配置二進位制安裝包的倉庫,按照以下命令進行配置。(命令中的 CLIENT_TOKEN 需要替換成訂閱郵件中的有效 Token)

curl -o get-xray-priv-lib-repo.sh https://pkg2.openresty.com.cn/scripts/get-xray-priv-lib-repo.sh

sudo bash get-xray-priv-lib-repo.sh -l lua-resty-dymetrics-(customer-name) -t CLIENT_TOKEN

sudo bash get-xray-priv-lib-repo.sh -l dymetrics-nginx-module -t CLIENT_TOKEN

sudo bash get-xray-priv-lib-repo.sh -l openresty-priv-comm -t CLIENT_TOKEN

安裝軟體包

動態指標需要安裝如下四個元件

  1. openresty-yajl
  2. openresty-yajl-devel
  3. dymetrics-nginx-module
  4. lua-resty-dymetrics-(customer-name)

其中,lua-resty-dymetrics-(customer-name) 這個元件可以根據客戶定製, 因此不同的客戶需要根據自己的名稱安裝響應的元件。下面命令中的 customer-name 需要根據實際情況進行替換。

使用 yum 包管理器的作業系統,執行以下命令進行私有庫的安裝。

sudo yum install -y dymetrics-nginx-module-1.19.9 openresty-yajl openresty-yajl-devel
sudo yum install -y lua-resty-dymetrics-(customer-name)

使用 dnf 包管理器的作業系統,執行以下命令進行私有庫的安裝。

sudo dnf install -y dymetrics-nginx-module-1.19.9 openresty-yajl openresty-yajl-devel
sudo dnf install -y lua-resty-dymetrics-(customer-name)

使用 apt 包管理器的作業系統,執行以下命令進行私有庫的安裝。

sudo apt-get install -y dymetrics-nginx-module-1.19.9 openresty-yajl openresty-yajl-dev
sudo apt-get install -y lua-resty-dymetrics-(customer-name)

使用

在使用前需要在配置檔案 nginx.conf 中需要新增以下這些配置項。

  1. load_module 指令用於載入 ngx_http_lua_dymetrics_module 這個動態模組。
  2. lua_package_path 和 lua_package_cpath 指令 指定 lua 檔案和 lua 載入的二進位制共享庫搜尋路徑。
  3. lua_shared_dymetrics 這個指令定義一個動態指標使用的共享記憶體區。
    load_module /usr/local/openresty/nginx/lib/ngx_http_lua_dymetrics_module.so;

    http {
        lua_package_path   "/usr/local/openresty/site/?.ljbc;;";
        lua_package_cpath  "/usr/local/openresty-yajl/lib/?.so;/usr/local/openresty/site/?.so;;";
        lua_shared_dymetrics  dymetrics 120M;
    }

    server {
        listen       80;
        server_name  localhost;
        set $app_uid "test.openresty.com";

        log_by_lua_block {
            if ngx.ctx.no_dymetrics_log then
                return
            end

            local ts = ngx.time()
            ts = ts - (ts % 60)

            local request_log = require "resty.dymetrics_http_reqs".request_log
            local conn_log= require "resty.dymetrics_http_conns".request_log
            local lua_vars = {}
            local app_id = 0

            request_log(ts, app_id, lua_vars)
            conn_log(ts, app_id, lua_vars)
        }

        location /metrics {
            allow 127.0.0.1;
            allow 18.140.243.108; # just an example
            deny all;

            content_by_lua_block {
                ngx.ctx.no_dymetrics_log = true
                local report_req_data = require "resty.dymetrics_http_reqs".report_data_prometheus
                local report_conn_data = require "resty.dymetrics_http_conns".report_data_prometheus
                local ts = ngx.time()
                ts = ts - 60 - (ts % 60)

                local data, err = report_req_data(ts, 0, "")
                if err ~= nil then
                   ngx.log(ngx.ERR, "prometheus: failed to get http request data:", err)
                else
                    ngx.say(data)
                end

                local data, err = report_conn_data(ts, 0, "")
                if err ~= nil then
                   ngx.log(ngx.ERR, "prometheus: failed to get http connection data:", err)
                else
                    ngx.say(data)
                end
            }
        }

        location / {
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

Lua APIs

dymetrics_http_reqs module

request_log

syntax: ok, err = reqs.request_log(time_key, app_id, lua_variables)

context: log_by_lua*

Calling this interface will add the current request to the statistics. If there is an error, it will return nil and the corresponding error message.

The value of time_key is the starting value of the statistics cycle. For example, if 60s is a statistics cycle, then “time_key” can be obtained as follows: time_key = ngx.time() - ngx.time() % 60. app_id is a key for Prometheus output. If app_id is not distinguished, pass value 0. lua_variables is an extension variable that is currently not used and requires passing an empty Lua table.

Here is an example:

log_by_lua_block {
    local ts = ngx.time()
    ts = ts - (ts % 60)

    local request_log = require "resty.dymetrics_http_reqs".request_log
    local lua_vars = {}
    local app_id = 0

    request_log(ts, app_id, lua_vars)
}

report_data

syntax: ok, err = reqs. report_data(time_key, node_id, partition_id, gateway_id)

context: content_by_lua_block*,ngx.timer.*

Get the dynamic indicators for the statistics cycle that starts with time_key. This time_key is for the previous statistics cycle, not the current one, because the current statistics cycle has not yet ended, and new requests will still be added to it. node_id represents the current machine’s ID. If it does not exist, it should be passed as 0. partition_id is a string representing the current partition’s ID. If it does not exist, it can be passed as nil. gateway_id is the ID of the gateway that the current node belongs to. If it does not exist, it can be passed as nil.

Here is an example:

content_by_lua_block {
    local report_req_data = require "resty.dymetrics_http_reqs".report_data
    local ts = ngx.time()
    ts = ts - 60 - (ts % 60)

    local data, err = report_req_data(ts, 0, "")
    if err ~= nil then
       ngx.log(ngx.ERR, "prometheus: failed to get http request data:", err)
    else
        ngx.say(data)
    end
}

report_data_prometheus

syntax: ok, err = reqs.report_data_prometheus(time_key, node_id, partition_id, gateway_id)

context: content_by_lua_block*,ngx.timer.*

Get the dynamic indicators for the statistics cycle that starts with time_key. This time_key is for the previous statistics cycle, not the current one, because the current statistics cycle has not yet ended, and new requests will still be added to it. node_id represents the current machine’s ID. If it does not exist, it should be passed as 0. partition_id is a string representing the current partition’s ID. If it does not exist, it can be passed as nil. gateway_id is the ID of the gateway that the current node belongs to. If it does not exist, it can be passed as nil.

Here is an example:

content_by_lua_block {
    local report_req_data = require "resty.dymetrics_http_reqs".report_data_prometheus
    local ts = ngx.time()
    ts = ts - 60 - (ts % 60)

    local data, err = report_req_data(ts, 0, "")
    if err ~= nil then
       ngx.log(ngx.ERR, "prometheus: failed to get http request data:", err)
    else
        ngx.say(data)
    end
}

dymetrics_http_conns module

request_log

syntax: ok, err = conns.request_log(time_key, app_id, lua_variables)

context: log_by_lua*

Calling this interface will add the current request to the statistics. If there is an error, it will return nil and the corresponding error message.

The value of time_key is the starting value of the statistics cycle. For example, if 60s is a statistics cycle, then “time_key” can be obtained as follows: time_key = ngx.time() - ngx.time() % 60. app_id is a key for Prometheus output. If app_id is not distinguished, pass value 0. lua_variables is an extension variable that is currently not used and requires passing an empty Lua table.

Here is an example:

log_by_lua_block {
    local ts = ngx.time()
    ts = ts - (ts % 60)

    local conn_log = require "resty.dymetrics_http_conns".request_log
    local lua_vars = {}
    local app_id = 0

    request_log(ts, app_id, lua_vars)
}

report_data

syntax: ok, err = conns.report_data(time_key, node_id, partition_id, gateway_id)

context: content_by_lua_block*,ngx.timer.*

Get the dynamic indicators for the statistics cycle that starts with time_key. This time_key is for the previous statistics cycle, not the current one, because the current statistics cycle has not yet ended, and new requests will still be added to it. node_id represents the current machine’s ID. If it does not exist, it should be passed as 0. partition_id is a string representing the current partition’s ID. If it does not exist, it can be passed as nil. gateway_id is the ID of the gateway that the current node belongs to. If it does not exist, it can be passed as nil.

Here is an example:

content_by_lua_block {
    local report_req_data = require "resty.dymetrics_http_conns".report_data
    local ts = ngx.time()
    ts = ts - 60 - (ts % 60)

    local data, err = report_req_data(ts, 0, "")
    if err ~= nil then
       ngx.log(ngx.ERR, "prometheus: failed to get http request data:", err)
    else
        ngx.say(data)
    end
}

report_data_prometheus

syntax: ok, err = conns.report_data_prometheus(time_key, node_id, partition_id, gateway_id)

context: content_by_lua_block*,ngx.timer.*

Get the dynamic indicators for the statistics cycle that starts with time_key. This time_key is for the previous statistics cycle, not the current one, because the current statistics cycle has not yet ended, and new requests will still be added to it. node_id represents the current machine’s ID. If it does not exist, it should be passed as 0. partition_id is a string representing the current partition’s ID. If it does not exist, it can be passed as nil. gateway_id is the ID of the gateway that the current node belongs to. If it does not exist, it can be passed as nil.

Here is an example:

content_by_lua_block {
    local report_req_data = require "resty.dymetrics_http_conns".report_data_prometheus
    local ts = ngx.time()
    ts = ts - 60 - (ts % 60)

    local data, err = report_req_data(ts, 0, "")
    if err ~= nil then
       ngx.log(ngx.ERR, "prometheus: failed to get http request data:", err)
    else
        ngx.say(data)
    end
}