diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua index d63f713dbc46..b578ec27ffd5 100644 --- a/apisix/cli/ngx_tpl.lua +++ b/apisix/cli/ngx_tpl.lua @@ -75,12 +75,26 @@ http { .. [=[{*lua_cpath*};"; {% if enabled_stream_plugins["prometheus"] then %} + + init_by_lua_block { + require "resty.core" + local process = require("ngx.process") + local ok, err = process.enable_privileged_agent() + if not ok then + ngx.log(ngx.ERR, "failed to enable privileged_agent: ", err) + end + } + init_worker_by_lua_block { require("apisix.plugins.prometheus.exporter").http_init(true) } server { - listen {* prometheus_server_addr *}; + {% if use_apisix_openresty then %} + listen {* prometheus_server_addr *} enable_process=privileged_agent; + {% else %} + listen {* prometheus_server_addr *}; + {% end %} access_log off; @@ -469,7 +483,11 @@ http { {% if enabled_plugins["prometheus"] and prometheus_server_addr then %} server { - listen {* prometheus_server_addr *}; + {% if use_apisix_openresty then %} + listen {* prometheus_server_addr *} enable_process=privileged_agent; + {% else %} + listen {* prometheus_server_addr *}; + {% end %} access_log off; diff --git a/docs/en/latest/plugins/prometheus.md b/docs/en/latest/plugins/prometheus.md index aaf526b42c2c..4b6e41d8ead7 100644 --- a/docs/en/latest/plugins/prometheus.md +++ b/docs/en/latest/plugins/prometheus.md @@ -102,6 +102,15 @@ plugin_attr: You can then expose it by using the [public-api](public-api.md) Plugin. +:::info IMPORTANT + +If the Prometheus plugin collects too many metrics, it will take CPU resources to calculate the metric data when getting the metrics via URI, which may affect APISIX to process normal requests. To solve this problem, APISIX exposes the URI and calculates the metrics in the [privileged agent](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent). +If the URI is exposed using the public-api plugin, then APISIX will calculate the metric data in a normal worker process, which may still affect APISIX processing of normal requests. + +This feature requires APISIX to run on [APISIX-Base](../FAQ.md#how-do-i-build-the-apisix-base-environment). + +::: + ## Enabling the Plugin The `prometheus` Plugin can be enabled with an empty table. diff --git a/docs/zh/latest/plugins/prometheus.md b/docs/zh/latest/plugins/prometheus.md index 5ff15ca499a5..ce59b87ec11b 100644 --- a/docs/zh/latest/plugins/prometheus.md +++ b/docs/zh/latest/plugins/prometheus.md @@ -85,6 +85,15 @@ plugin_attr: 你可以使用 [public-api](../../../en/latest/plugins/public-api.md) 插件来暴露该 URI。 +:::info IMPORTANT + +如果 Prometheus 插件收集的指标数量过多,在通过 URI 获取指标时,会占用 CPU 资源来计算指标数据,可能会影响 APISIX 处理正常请求。为解决此问题,APISIX 在 [privileged agent](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent) 中暴露 URI 并且计算指标。 +如果使用 public-api 插件暴露该 URI,那么 APISIX 将在普通的 worker 进程中计算指标数据,这仍可能会影响 APISIX 处理正常请求。 + +该特性要求 APISIX 运行在 [APISIX-Base](../FAQ.md#如何构建-apisix-base-环境) 上。 + +::: + ## 启用插件 `prometheus` 插件可以使用空表 `{}` 开启。 diff --git a/t/cli/test_prometheus.sh b/t/cli/test_prometheus.sh index 15f54f9114ee..2f2382980fb3 100755 --- a/t/cli/test_prometheus.sh +++ b/t/cli/test_prometheus.sh @@ -21,6 +21,8 @@ git checkout conf/config.yaml +sleep 1 + make run code=$(curl -v -k -i -m 20 -o /dev/null -s -w %{http_code} http://127.0.0.1:9080/apisix/prometheus/metrics) diff --git a/t/cli/test_prometheus_run_in_privileged.sh b/t/cli/test_prometheus_run_in_privileged.sh new file mode 100755 index 000000000000..7f8a3e2ec5ff --- /dev/null +++ b/t/cli/test_prometheus_run_in_privileged.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +# +# 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. +# + +. ./t/cli/common.sh + +git checkout conf/config.yaml + +exit_if_not_customed_nginx + +# prometheus run in privileged works when only http is enabled +sleep 0.5 +rm logs/error.log || true + +echo ' +apisix: + extra_lua_path: "\$prefix/t/lib/?.lua" +nginx_config: + error_log_level: info +' > conf/config.yaml + +make run +sleep 0.1 + +curl -s -o /dev/null http://127.0.0.1:9091/apisix/prometheus/metrics + +if ! grep -E "process type: privileged agent" logs/error.log; then + echo "failed: prometheus run in privileged can't work when only http is enabled" + exit 1 +fi + +make stop + +echo "prometheus run in privileged agent successfully when only http is enabled" + + +# prometheus run in privileged works when both http & stream are enabled +sleep 0.5 +rm logs/error.log || true + +echo " +apisix: + extra_lua_path: "\$prefix/t/lib/?.lua" + enable_admin: true + stream_proxy: + tcp: + - addr: 9100 +stream_plugins: + - prometheus +nginx_config: + error_log_level: info +" > conf/config.yaml + +make run +sleep 0.1 + +curl -s -o /dev/null http://127.0.0.1:9091/apisix/prometheus/metrics + +if ! grep -E " process type: privileged agent" logs/error.log; then + echo "failed: prometheus run in privileged can't work when both http & stream are enabled" + exit 1 +fi + +echo "passed: prometheus run in privileged agent successfully when both http & stream are enabled" + +make stop + + +# prometheus run in privileged works when only stream is enabled +sleep 0.5 +rm logs/error.log || true + +echo " +apisix: + extra_lua_path: "\$prefix/t/lib/?.lua" + enable_admin: false + stream_proxy: + tcp: + - addr: 9100 +stream_plugins: + - prometheus +nginx_config: + error_log_level: info +" > conf/config.yaml + +make run +sleep 0.1 + +curl -s -o /dev/null http://127.0.0.1:9091/apisix/prometheus/metrics + +if ! grep -E " process type: privileged agent" logs/error.log; then + echo "failed: prometheus run in privileged can't work when only stream is enabled" + exit 1 +fi + +echo "passed: prometheus run in privileged agent successfully when only stream is enabled" diff --git a/t/lib/apisix/plugins/prometheus/exporter.lua b/t/lib/apisix/plugins/prometheus/exporter.lua new file mode 100644 index 000000000000..c9c71f606dd1 --- /dev/null +++ b/t/lib/apisix/plugins/prometheus/exporter.lua @@ -0,0 +1,39 @@ +-- +-- 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 core = require("apisix.core") +local _M = {} + + +function _M.http_init() + return true +end + + +function _M.stream_init() + return true +end + + +function _M.export_metrics() + local process_type = require("ngx.process").type() + core.log.info("process type: ", process_type) + return core.response.exit(200) +end + + +return _M