Metric#
Added in version 1.12.0.
ngx_stream_metric_module 模块允许为 stream(TCP 和 UDP)流量创建任意的实时计算指标。这些指标值存储在共享内存中,并在 /status/stream/metric_zones/ API 分支中实时显示。支持多种数据聚合类型(计数器、直方图、移动平均等),并可按任意键进行分组。
有关响应模式,请参见 Stream 指标区域 API 参考。 按客户端地址统计连接数: 如果向端口 计算指定共享内存区域 name 的指标值。 参数: 最大长度为 255 字节;更长的键会被截断。在 API 输出中,Angie 会为每个 255 字节的键(包括原始长度恰好为 255 字节的键)附加 如果省略,默认为 如果为 如果为 如果为 使用示例: 备注 具有空键或无效 这对于 备注 请记住,变量在不同阶段进行求值。例如,无法将 定义一个 复合指标 — 一组具有独立模式的指标。
块体中的每一行定义一个 子指标名称、一个 模式 以及可选的模式 参数。
区域大小必须至少为八个系统内存页。 使用示例: 在 API 树中,这样的复合指标模板如下所示: 创建一个指定 size 大小和给定 name 名称的共享内存区域来存储指标。该区域名称作为 参数: 如果为 如果为 mode — 数据处理算法(参见 操作模式 部分); parameters — 所选模式的附加设置(例如, 使用示例: 在 API 树中,共享内存区域模板如下所示: 备注 在 1 MB 区域中,键大小为 39 字节且单一指标模式时,大约可以存储 8,000 个唯一键条目。 可用指标操作模式列表: 以下示例使用配置示例中的 无论提供什么值,每次指标更新都会将计数器增加 默认值 — 示例: 更新指标: API 中的预期指标值: gauge 根据传入数字的符号增加或减少其值。正值增加计数器,负值减少计数器。值为 默认值 — 示例: 更新指标: API 中的预期指标值: 进一步更新: API 中的预期指标值: 存储最后接收到的值,不进行任何聚合。如果省略 value,则使用 示例: 更新指标: API 中的预期指标值: 进一步更新: API 中的预期指标值: 保存两个值中的最小值 — 当前存储的值和新值。 示例: 更新指标: API 中的预期指标值: 保存两个值中的最大值 — 当前存储的值和新值。 示例: 更新指标: API 中的预期指标值: 使用 指数平滑 算法计算平均值。 接受可选参数 系数越高,新值的权重越大。如果指定 示例: 更新指标: API 中的预期指标值: 计算算术平均值。接受可选参数 备注 例如, 示例: 更新指标: API 中的预期指标值: 如果从最后一次更新起等待 5 秒,预期值将为: 创建一组"桶",如果新值不超过桶的阈值,则递增相关计数器。参数以数值阈值列表的形式提供。对于分析分布(如会话持续时间)很有用。 必需参数是 numbers — 桶的阈值,通常按升序列出。 备注 桶值 示例: 更新指标: API 中的预期指标值: 进一步更新: API 中的预期指标值: 进一步更新: API 中的预期指标值: 为每个指标创建以下变量: 对于复合指标,会添加额外的变量: 与 metric 指令类似, 该设置器接受一个键,并可带有可选的 使用示例: 在向端口 备注 回读 此外,存储在 备注 对于复合指标, 使用示例: 使用此配置,先向端口 向端口 备注 如果将空字符串赋值给 仅在 在这种情况下,存储在 对于复合指标,可以使用 使用示例: 使用此配置,向端口 响应: 响应: 响应: Angie 包含一个 内置模块,用于以 Prometheus 格式 显示指标,该模块支持自定义指标,包括在 stream 侧收集的指标。由于 Prometheus 暴露是仅 HTTP 的功能,因此 prometheus_template 和 prometheus 指令在 作为集成示例,请考虑以下配置: 在向端口 指标值将为: 以 Prometheus 格式,该指标可在 配置示例#
stream {
metric_zone connections:1m count;
server {
listen 12345;
metric connections $remote_addr on=connect;
}
}
http {
server {
listen 80;
location /status/ {
allow 127.0.0.1;
deny all;
api /status/;
}
}
}
12345 发起连接:$ nc 127.0.0.1 12345 </dev/null
connections 指标会实时更新:{
"stream": {
"metric_zones": {
"connections": {
"discarded": 0,
"metrics": {
"127.0.0.1": 1
}
}
}
}
}
指令#
metric#
...。键本身可以包含 = 字符 — 只有 最后一个 = 之后的文本才被视为值,因此它之前的所有内容(包括任何嵌入的 =)都成为键;0。如果参数无法转换为数字,则默认为 1;on — 可选参数,指定在会话处理的哪个阶段计算指标:on=connect,计算发生在 Pre-access 阶段,即在从客户端读取任何数据之前;on=preread,每个会话计算一次,即当来自上游侧的第一批数据 — 从使用 proxy_pass 代理到的服务器接收,或由 return 生成 — 被发送给客户端时;此时,proxy_protocol、ssl_preread、mqtt_preread 等模块已经处理了客户端的初始数据;on=end(默认),计算发生在 Log 阶段,即会话结束时。metric sessions $remote_addr=$session_time on=end;
key=value 对的指标将被忽略。
省略的 value 被视为 0:metric foo $bar; # 等同于 $bar=0
count 模式很有用,该模式忽略数值,只对指标被更新这一事实做出反应。$upstream_bytes_sent(发送到上游的字节数)与 on=connect(在连接被代理到任何地方之前)一起使用。metric_complex_zone#
metric_complex_zone sessions:1m expire=on discard_key="old" {
# 子指标名称 模式 参数
min_time min;
avg_time average exp factor=60;
max_time max;
total count;
}
{
"discarded": 3,
"metrics": {
"key1": {
"min_time": 20,
"avg_time": 50,
"max_time": 80,
"total": 2
},
"old": {
"min_time": 3,
"avg_time": 40,
"max_time": 152,
"total": 80
}
}
}
metric_zone#
/status/stream/metric_zones/ 分支中的节点。区域大小必须至少为八个系统内存页。expire=<on|off> — 区域满时的行为:on,则丢弃最旧的指标(按更新时间)以释放内存供新指标使用;off(默认)— 丢弃新传入的指标,保留现有条目。discard_key=<name> — 定义一个键为 name 的指标,用于累积被丢弃指标的值。默认情况下不创建此类指标。保留键不能手动更新。average exp 的 factor)。metric_zone session_time:1m max;
{
"discarded": 0,
"metrics": {
"key1": 123,
"key2": 10.5
}
}
操作模式#
count — 计数器;gauge — 仪表(增加/减少);last — 最后接收到的值;min — 最小值;max — 最大值;average exp — 指数移动平均(EMA)(参数 factor);average mean — 窗口内的平均值(参数 window 和 count);histogram — 跨"桶"的分布(阈值列表)。/status/ 端点。每个结果都可在 /status/stream/metric_zones/<zone>/metrics/ 下获取。count#
1。0。metric_zone count:1m count;
# 作为复合指标的一部分:
#
# metric_complex_zone count:1m {
# some_metric_name count;
# }
server {
listen 12345;
metric count KEY;
}
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
{
"KEY": 4
}
gauge#
0 时不改变计数器。0。metric_zone gauge:1m gauge;
# 作为复合指标的一部分:
#
# metric_complex_zone gauge:1m {
# some_metric_name gauge;
# }
server {
listen 12351;
metric gauge KEY;
}
server {
listen 12352;
metric gauge KEY=5;
}
server {
listen 12353;
metric gauge KEY=-5;
}
server {
listen 12354;
metric gauge KEY=8;
}
$ nc 127.0.0.1 12351 </dev/null
{
"KEY": 0
}
$ nc 127.0.0.1 12352 </dev/null
$ nc 127.0.0.1 12353 </dev/null
$ nc 127.0.0.1 12354 </dev/null
{
"KEY": 8
}
last#
0。metric_zone last:1m last;
# 作为复合指标的一部分:
#
# metric_complex_zone last:1m {
# some_metric_name last;
# }
server {
listen 12361;
metric last KEY;
}
server {
listen 12362;
metric last KEY=8000;
}
server {
listen 12363;
metric last KEY=37;
}
server {
listen 12364;
metric last KEY=-3.5;
}
$ nc 127.0.0.1 12361 </dev/null
{
"KEY": 0
}
$ nc 127.0.0.1 12362 </dev/null
$ nc 127.0.0.1 12363 </dev/null
$ nc 127.0.0.1 12364 </dev/null
{
"KEY": -3.5
}
min#
metric_zone min:1m min;
# 作为复合指标的一部分:
#
# metric_complex_zone min:1m {
# some_metric_name min;
# }
server {
listen 12371;
metric min KEY=42.999;
}
server {
listen 12372;
metric min KEY=-512;
}
server {
listen 12373;
metric min KEY=1;
}
$ nc 127.0.0.1 12371 </dev/null
$ nc 127.0.0.1 12372 </dev/null
$ nc 127.0.0.1 12373 </dev/null
{
"KEY": -512
}
max#
metric_zone max:1m max;
# 作为复合指标的一部分:
#
# metric_complex_zone max:1m {
# some_metric_name max;
# }
server {
listen 12381;
metric max KEY=42.999;
}
server {
listen 12382;
metric max KEY=-512;
}
server {
listen 12383;
metric max KEY=1;
}
$ nc 127.0.0.1 12381 </dev/null
$ nc 127.0.0.1 12382 </dev/null
$ nc 127.0.0.1 12383 </dev/null
{
"KEY": 42.999
}
average exp#
factor=<number> — 决定新值对平均值影响程度的系数。允许的整数值范围为 0 到 99。默认值为 90。90,结果将是新值的 90% 加上先前平均值的 10%。metric_zone avg_exp:1m average exp factor=60;
# 作为复合指标的一部分:
#
# metric_complex_zone avg_exp:1m {
# some_metric_name average exp factor=60;
# }
server {
listen 12391;
metric avg_exp KEY=100;
}
server {
listen 12392;
metric avg_exp KEY=200;
}
server {
listen 12393;
metric avg_exp KEY=0;
}
server {
listen 12394;
metric avg_exp KEY=8;
}
server {
listen 12395;
metric avg_exp KEY=30;
}
$ nc 127.0.0.1 12391 </dev/null
$ nc 127.0.0.1 12392 </dev/null
$ nc 127.0.0.1 12393 </dev/null
$ nc 127.0.0.1 12394 </dev/null
$ nc 127.0.0.1 12395 </dev/null
{
"KEY": 30.16
}
average mean#
window=<off|time> 和 count=<number>,分别定义用于平均的时间间隔和样本大小。默认为 window=off(使用整个样本)和 count=10。window=5s 将仅考虑最近 5 秒内的事件。window 参数不能为 0。count=number 参数控制样本大小(缓存值),以实现更平滑的平均值计算。metric_zone avg_mean:1m average mean window=5s count=8;
# 作为复合指标的一部分:
#
# metric_complex_zone avg_mean:1m {
# some_metric_name average mean window=5s count=8;
# }
server {
listen 12401;
metric avg_mean KEY=0.1;
}
server {
listen 12402;
metric avg_mean KEY=0.4;
}
server {
listen 12403;
metric avg_mean KEY=10;
}
server {
listen 12404;
metric avg_mean KEY=1;
}
$ nc 127.0.0.1 12401 </dev/null
$ nc 127.0.0.1 12401 </dev/null
$ nc 127.0.0.1 12402 </dev/null
$ nc 127.0.0.1 12403 </dev/null
$ nc 127.0.0.1 12404 </dev/null
$ nc 127.0.0.1 12404 </dev/null
{
"KEY": 2.1
}
{
"KEY": 0
}
histogram#
inf 或 +Inf 可用于捕获所有超过最高指定桶的值。metric_zone hist:1m histogram 0.1 0.2 0.5 1 2 inf;
# 作为复合指标的一部分:
#
# metric_complex_zone hist:1m {
# some_metric_name histogram 0.1 0.2 0.5 1 2 inf;
# }
server {
listen 12411;
metric hist KEY=0.25;
}
server {
listen 12412;
metric hist KEY=2;
}
server {
listen 12413;
metric hist KEY=1000;
}
$ nc 127.0.0.1 12411 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 1,
"inf": 1
}
}
$ nc 127.0.0.1 12412 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 2
}
}
$ nc 127.0.0.1 12413 </dev/null
{
"KEY": {
"0.1": 0,
"0.2": 0,
"0.5": 1,
"1": 1,
"2": 2,
"inf": 3
}
}
内置变量#
$metric_<name>$metric_<name>_key$metric_<name>_value$metric_<name>_value_<metric>$metric_<name>#$metric_<name> 变量设置器可用于更新指标。计算发生在设置该变量时 — 例如,通过 set 指令(该指令在 Pre-access 阶段求值,与 on=connect 处于同一阶段),或以编程方式从 njs 模块(例如在 js_access 处理程序中)进行。=value 后缀。最后一个 = 将键与值分开;如果没有该后缀,值为 0。键和值可以包含文本、变量或两者的组合。这些解析规则与 metric 的相同。stream {
metric_zone hits:1m count;
# 此时添加了 $metric_hits 变量
server {
listen 12345;
metric hits client=1 on=connect;
}
server {
listen 12346;
set $metric_hits client=1;
return "$metric_hits\n";
}
}
12345 发起三次连接并向端口 12346 发起一次连接后:$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12346 </dev/null
client=4
$metric_<name> 会以 key=value 形式返回该键以及指标当前的 计算后 值 — 而不是所赋的字面字符串。在上面的示例中,连接赋予的字面值为 client=1,但由于 count 模式忽略所赋的值并在每次更新时简单地递增,因此随后回读 $metric_hits 会返回 client=4 — 即计数器的新总数,其中已经包含了来自端口 12345 的三次先前更新。$metric_<name>_key 变量中的值会更改为指定的键。$metric_<name>_key 和 $metric_<name>_value#$metric_<name>_key 和 $metric_<name>_value 变量分别定义键和值。当设置 $metric_<name>_value 时会发生指标更新,前提是 $metric_<name>_key 中的键已经定义。$metric_<name>_value 变量中的子指标值使用 ", " 分隔符连接。stream {
metric_zone level:1m gauge;
# 此处添加了变量 $metric_level、$metric_level_key 和 $metric_level_value。
metric_complex_zone stats:1m {
count count;
min min;
avg average exp;
}
# 此处添加了 $metric_stats、$metric_stats_key 和 $metric_stats_value。
server {
listen 12345;
metric level sensor=10 on=connect;
}
server {
listen 12346;
set $metric_level_key "sensor";
set $metric_level_value 5;
# 或者:set $metric_level sensor=5;
return "Updated with '$metric_level'\nValue='$metric_level_value'\n";
}
server {
listen 12347;
set $metric_stats_key bar;
set $metric_stats_value 9;
# 或者:set $metric_stats bar=9;
return "Updated with '$metric_stats'\nValues='$metric_stats_value'\n";
}
}
12345(将 gauge 的起始值设置为 10)发起连接,然后向端口 12346 发起连接,产生:$ nc 127.0.0.1 12345 </dev/null
$ nc 127.0.0.1 12346 </dev/null
Updated with 'sensor=15'
Value='15'
12347 发起连接,产生:$ nc 127.0.0.1 12347 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
$metric_<name>_value,该值将被识别为 0。如果字符串由无法转换为数字的字符组成,则被识别为 1。$metric_<name>_key 和 $metric_<name>_value 都已设置后才会进行计算。$metric_<name> 中的值将等于新的 计算后 key=value 对,而不是刚刚赋予的字面值。$metric_<name>_key 中的值表示通过变量指定的最后一个键。$metric_<name>_value 中的值表示为 $metric_<name>_key 中设置的键计算的最后一个值。$metric_<name>_value_<metric>#$metric_<name>_value_<metric> 变量获取特定子指标的值,其中 <metric> 是子指标的名称。stream {
metric_complex_zone foo:1m {
count count;
min min;
avg average exp;
}
# 添加 $metric_foo、$metric_foo_key、$metric_foo_value,
# 以及 $metric_foo_value_count、$metric_foo_value_min、$metric_foo_value_avg。
server {
listen 12345;
set $metric_foo_key bar;
set $metric_foo_value 9;
# 或者:set $metric_foo bar=9;
return "Updated with '$metric_foo'\nValues='$metric_foo_value'\nCount='$metric_foo_value_count'\n";
}
}
12345 发起连接,产生:$ nc 127.0.0.1 12345 </dev/null
Updated with 'bar=1, 9, 9'
Values='1, 9, 9'
Count='1'
其他示例#
按协议监控连接#
metric_zone protocols:1m count;
server {
listen 12345;
listen 12346 udp;
metric protocols $protocol;
}
{
"TCP": 340,
"UDP": 58
}
上游会话时间分布#
metric_zone upstream_time:10m expire=on histogram
0.05 0.1 0.3 0.5 1 2 5 10 inf;
server {
listen 12345;
proxy_pass backend;
metric upstream_time $upstream_addr=$upstream_session_time on=end;
}
{
"discarded": 0,
"metrics": {
"backend1:8080": {
"0.05": 12,
"0.1": 28,
"0.3": 56,
"0.5": 78,
"1": 92,
"2": 97,
"5": 99,
"10": 100,
"inf": 100
}
}
}
活动连接数#
stream {
metric_zone active_connections:2m gauge;
server {
listen 12345;
metric active_connections service_a=1 on=connect;
metric active_connections service_a=-1 on=end;
}
server {
listen 12346;
metric active_connections service_b=1 on=connect;
metric active_connections service_b=-1 on=end;
}
}
http {
server {
listen 8080;
location /connections/ {
allow 127.0.0.1;
deny all;
api /status/stream/metric_zones/active_connections/metrics/;
}
}
}
{
"service_a": 42,
"service_b": 17
}
Prometheus 支持#
http 块中配置,并通过同一个统一的 /status/ API 树引用 stream 指标区域。stream {
# 创建 "upload" 指标
metric_complex_zone upload:1m discard_key="other" {
stats histogram 64 256 1024 4096 16384 +Inf;
sum gauge;
count count;
avg_size average exp;
}
upstream backend {
server 127.0.0.1:15001;
}
server {
listen 12345;
# 在会话结束时,使用从客户端接收到的
# 字节总数更新该指标
proxy_pass backend;
metric upload angie=$bytes_received on=end;
}
}
http {
# 描述 "upload" 指标的 Prometheus 模板
prometheus_template upload_metric {
'stats{le="$1"}' $p8s_value
path=~^/stream/metric_zones/upload/metrics/angie/stats/(.+)$
type=histogram;
'stats_sum' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/sum;
'stats_count' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/count;
'avg_size' $p8s_value
path=/stream/metric_zones/upload/metrics/angie/avg_size;
}
server {
listen 80;
# 指标抓取目标
location /prometheus/upload_metric/ {
prometheus upload_metric;
}
}
}
12345 发起五次连接,分别发送 16384、64448、64、1028 和 1028 字节的负载后:$ head -c 16384 /dev/urandom | nc 127.0.0.1 12345
$ head -c 64448 /dev/urandom | nc 127.0.0.1 12345
$ head -c 64 /dev/urandom | nc 127.0.0.1 12345
$ head -c 1028 /dev/urandom | nc 127.0.0.1 12345
$ head -c 1028 /dev/urandom | nc 127.0.0.1 12345
{
"stats": {
"64": 1,
"256": 1,
"1024": 1,
"4096": 3,
"16384": 4,
"+Inf": 5
},
"sum": 82952,
"count": 5,
"avg_size": 1077.9376
}
/prometheus/upload_metric/ 获取:# Angie Prometheus template "upload_metric"
# TYPE stats histogram
stats{le="64"} 1
stats{le="256"} 1
stats{le="1024"} 1
stats{le="4096"} 3
stats{le="16384"} 4
stats{le="+Inf"} 5
stats_sum 82952
stats_count 5
avg_size 1077.9376