Statsd 0.10.2 常用 CLI 命令与工具详解

Statsd 参考实现运维命令全实测:nc 手工发送行协议四类指标(counter@采样/timer多行/gauge增减94/set去重/坏行)、TCP 8126 管理口逐条命令(stats/counters/gauges/timers/config/health/delcounters/quit/ERROR)、systemd 生命周期与 Final Flush、proxy.js 集群代理(status/哈希转发到 statsd02:18125)、utils 三脚本(check_statsd.pl OK/WARNING、check_statsd_health 挂起坑、timer-metric-counts),含速查表与排障实录。

StatsdStatsd自托管监控2026/11/01

Statsd 0.10.2 常用 CLI 命令与工具详解

目标:把 StatsD 参考实现(statsd/statsd)日常运维要敲的命令一次讲完——启动/停止入口命令、用 nc 手工发送行协议、TCP 8126 管理口逐条命令实测(stats/counters/gauges/timers/config/health/delcounters/quit)、集群代理 proxy.js 实测,以及 utils/ 目录三个 Nagios 检查脚本的用法与坑。全部回显为 2026-11-01 在 Ubuntu 24.04.5 服务器(statsd01,源码 v0.10.2,systemd 主实例监听 UDP 8125 / TCP 8126;statsd02,npm 0.9.0 实例监听 18125/18126)上的实测记录。前置:安装见 《Ubuntu 24.04 安装 Statsd 0.10.2 指南》,参数含义见 《Statsd 0.10.2 配置参数详解》,架构背景见 《Statsd 介绍与选型指南》。

一、进程入口与生命周期命令

StatsD 没有功能型子命令(无 --version/status 之类 CLI),CLI 面就是"入口脚本 + 配置文件":

node stats.js /etc/statsd/config.js     # 源码通道守护进程(npm 通道等价命令:statsd /etc/statsd/config.js)
node proxy.js /tmp/proxyConfig.js       # 集群代理(独立入口,见第五节)

生产上由 systemd 托管(单元文件与启用过程见安装篇第四节),日常生命周期命令实测:

root@statsd01:~# systemctl status statsd     # active (running),Main PID 7726 "statsd /etc/statsd/config.js"
root@statsd01:~# systemctl stop statsd
root@statsd01:~# journalctl -u statsd --no-pager | grep -E "Final Flush|Stopped|Stopping" | tail -4
Nov 01 10:35:02 statsd01 systemd[1]: Stopping statsd.service - StatsD metrics aggregation daemon...
Nov 01 10:35:02 statsd01 node[7726]: 1 Nov 10:35:02 - Starting Final Flush
Nov 01 10:35:02 statsd01 systemd[1]: Stopped statsd.service - StatsD metrics aggregation daemon.
root@statsd01:~# systemctl start statsd
root@statsd01:~# systemctl is-active statsd
active

要点:SIGTERM 会触发 Final Flush(未满一个周期的窗口数据先刷给后端再退出),所以停止务必走 systemctl stop/kill(默认 SIGTERM),不要 kill -9——那会丢掉整个内存窗口。手工前台实例同样验证过:kill $PID 后日志尾部再次打印完整聚合 JSON 才退出。

二、行协议:用 nc 手工发送指标

协议一行一条:<name>:<value>|<type>[@sample_rate][#tag:v]。对主实例 8125 的实测发送序列:

root@statsd01:~# echo "d1c:1|c" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo "d1s:5|c|@0.1" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# printf 'd1t:240|ms\nd1t:320|ms\n' | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo "d1g:100|g" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo "d1g:-10|g" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo "d1g:+4|g" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# printf 'd1u:uid1|s\nd1u:uid2|s\nd1u:uid1|s\n' | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo "d1bad-not-valid" | nc -u -w0 127.0.0.1 8125

四类指标语义在回显里各自得到验证:

  • counter:d1c:1|c 计 1 次;d1s:5|c|@0.1 带 10% 采样率,服务端按 5/0.1=50 还原(README 经典示例 gorets:1|c|@0.1 在 graphite 抓包里同样还原为 stats_counts.gorets 50);
  • timer:一个 UDP 包用 \n 携带两条 d1t 样本,聚合出全套分位统计;
  • gauge:带符号值做增减(100→-10→+4),管理口 gauges 实测结果:
root@statsd01:~# echo gauges | nc -w1 127.0.0.1 8126
{ 'statsd.timestamp_lag': 0, d1g: 94 }
END
  • set:uid1/uid2/uid1 三个成员去重为 2;graphite 抓包对应 stats.sets.uniques.count 1(README 示例实测);
  • 坏行:d1bad-not-valid 无 |type,被计入 statsd.bad_lines_seen(管理口 stats 的 messages.bad_lines_seen 随之 +1,见下节 A1 对比)。

💡 技术拓展:nc -u -w0 发 UDP 是"发完即走",与真实客户端 SDK 行为一致;statsd 对 UDP 没有任何回执,发送侧看不到错误——验证协议是否发对,只能靠管理口 counters 或后端抓包,这也是本节把 nc 与 8126 搭配讲的原因。

三、管理口(TCP 8126)命令逐条实测

memcached 风格纯文本协议,每条命令以 END 结束。无认证,端口必须网络隔离。官方 docs/admin_interface.md 列出的命令与实测结果如下。

3.1 stats——服务自观测

发送协议序列前:

root@statsd01:~# echo stats | nc -w1 127.0.0.1 8126
uptime: 2579
messages.last_msg_seen: 2250
messages.bad_lines_seen: 0
graphite.last_flush: 2239
graphite.last_exception: 1793529103
graphite.flush_time: 0
graphite.flush_length: 832
console.lastFlush: 1793526524
console.lastException: 1793526524
END

发送序列后(注意 bad_lines_seen 0→1、last_msg_seen 归零、last_flush 推进):

uptime: 2580
messages.last_msg_seen: 0
messages.bad_lines_seen: 1
graphite.last_flush: 2240

每个后端还各自发布 graphite.last_flush/last_exception/flush_time/flush_length——判断"statsd 活着但 Graphite 收不到数"就看 last_exception 是否在推进。

3.2 counters / gauges / timers——内存桶快照

root@statsd01:~# echo counters | nc -w1 127.0.0.1 8126
{
  'statsd.bad_lines_seen': 0,
  'statsd.packets_received': 0,
  'statsd.metrics_received': 0,
  bad_key2: 0,
  'tagged;env=prod;host=web01': 0,
  d1c: 0,
  d1s: 0
}
END
root@statsd01:~# echo timers | nc -w1 127.0.0.1 8126
{ d1t: [] }
END

三个 dump 命令输出的是 Node 对象字面量(无 END 之外的格式化保证)。flush 后速率归 0、timer 样本清空,符合"窗口聚合后重置"语义。

3.3 config——生效配置 dump

root@statsd01:~# echo config | nc -w1 127.0.0.1 8126 | head -16

graphitePort: 2003
graphiteHost: 127.0.0.1
port: 8125
backends > 0: ./backends/graphite
backends > 1: ./backends/console
debug: true

输出为"默认值+显式配置"的合并生效值(完整解读见配置篇 1.2)。⚠️ 该命令会把配置全量明文吐出(含后端地址),管理口暴露面等于配置泄露面,隔离要更严。

3.4 health——查/设摘流标志

root@statsd01:~# echo health | nc -w1 127.0.0.1 8126
health: up
root@statsd01:~# echo "health down" | nc -w1 127.0.0.1 8126
root@statsd01:~# echo health | nc -w1 127.0.0.1 8126
health: down
root@statsd01:~# echo "health up" | nc -w1 127.0.0.1 8126
root@statsd01:~# echo health | nc -w1 127.0.0.1 8126
health: up

health [up|down] 单独执行是查询,带参数是设置——给 LB/keepalived 做 statsd 摘流的标准钩子(注意配置篇 8.2:启动参数 healthStatus 实测不影响该命令返回值)。

3.5 delcounters / delgauges / deltimers——删桶

root@statsd01:~# echo "d1tmp:1|c" | nc -u -w0 127.0.0.1 8125
root@statsd01:~# echo counters | nc -w1 127.0.0.1 8126 | grep d1tmp
  d1tmp: 1
root@statsd01:~# echo "delcounters d1tmp" | nc -w1 127.0.0.1 8126
deleted: d1tmp
END
root@statsd01:~# echo counters | nc -w1 127.0.0.1 8126 | grep -c d1tmp
0

支持删单个 key 或通配文件夹(官方文档示例:delcounters sandbox.test.*)。delgauges/deltimers 同族语法。这是运行时清高基数污染桶的直接手段(预防手段是配置 deleteIdleStats)。

3.6 不存在的命令与 quit

root@statsd01:~# echo sets | nc -w1 127.0.0.1 8126 | head -5
ERROR
root@statsd01:~# echo quit | nc -w1 127.0.0.1 8126; echo "nc-exit=$?"
nc-exit=0
root@statsd01:~# echo foobar | nc -w1 127.0.0.1 8126 | head -3
ERROR

实测确认:没有 sets dump 命令(set 数据只能从后端侧看),未知命令一律回 ERROR;quit 由服务端关闭连接(nc 正常退出码 0)。

四、utils/ 监控检查脚本

4.1 check_statsd.pl——Nagios 阈值检查(实测可用)

Perl 版通用检查:连管理口取 stats 里任意指标做阈值判断。实测 OK 与 WARNING 两态:

root@statsd01:~# perl /opt/statsd/utils/check_statsd.pl --host 127.0.0.1 --port 8126 --metric "graphite.last_flush" --warning 15 --crit 30
OK: graphite.last_flush = 8
exit=0

主实例空闲一段时间后再跑(last_flush 距今 309 秒,超过 warning 15):

WARNING: graphite.last_flush value 309 exceeds warning threshold 15
exit=1

退出码遵循 Nagios 约定(0=OK/1=WARNING),--metric 可指任意 stats 输出字段(messages.bad_lines_seen、graphite.last_exception 都是黄金监控项)。

4.2 check_statsd_health——官方 bash 健康检查(有坑)

直接执行会挂住不返回:脚本内部用 nc 连管理口但不带关闭参数,而 8126 是长连接、不会主动断开。实测:

root@statsd01:~# timeout 3 bash /opt/statsd/utils/check_statsd_health
exit=124    # 124 = timeout 强杀,nc 不自动关闭
root@statsd01:~# bash /opt/statsd/utils/check_statsd_health
exit=143    # 后台运行后被 kill

替代方案:要么给脚本里的 nc 补 -w1,要么直接用一行式 echo health | nc -w1 127.0.0.1 8126 | grep -q '^health: up' 做探活。

4.3 statsd-timer-metric-counts.sh——timer 采样调优工具

跑在 Graphite 服务器上的 bash 工具(读 whisper 文件/调 render API),统计各 timer 指标一小时内收到的样本数,用来决策"哪些 key 该加大采样率"。脚本头部注释原文(要点):

# is your statsd machine maxing out cpu? ... unable to pull udp packets out of the buffer
# at a fast enough rate? (see `netstat -su` ) timer metrics are by far the most cpu intensive
# and tuning the sampling of those is key to keeping cpu load under control.
# this tool (to be run on your graphite server) shows for all your timing metric keys how many packets
# it accepted in a given interval like 1hour.

graphite_url=http://<your graphite url>
whisper_dir=/var/lib/carbon/whisper
timers_subdir=stats/timers

配合 statsd 侧的 percentThreshold/calculatedTimerMetrics(配置篇第五节)形成"客户端采样 + 服务端裁剪"的 CPU 治理组合。

五、集群代理 proxy.js 命令实测

多机水平扩展用仓库自带的 proxy.js(按指标名一致性哈希固定路由到后端 statsd 实例,带节点健康探测)。代理配置 /tmp/proxyConfig.js:

{
  nodes: [ { host: 'statsd02', port: 18125, adminport: 18126 } ]
, server: './servers/udp'
, host: '0.0.0.0'
, port: 19151
, mgmt_port: 19152
, checkInterval: 1000
}

启动与日志:

root@statsd01:~# node proxy.js /tmp/proxyConfig.js
1 Nov 09:50:39 - [7854] reading config file: /tmp/proxyConfig.js
1 Nov 09:50:39 - INFO: [7854] server is up
(node:7854) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

代理自己的管理口(19152)只有 status 命令:

root@statsd01:~# echo status | nc -w1 127.0.0.1 19152
uptime: 2
nodes: statsd02:18125 

向代理 19151 发 proxym:2|c 与 proxym2:7|ms,在后端实例 statsd02(18125)的 flush 里收到转发计数:

    proxym: 0.2

以及 timers: { proxym2: [] } / timer_data: { proxym2: { count_ps: 0, count: 0 } }(样本已计入后完成窗口重置)。两点注意(官方 docs/cluster_proxy.md):后端 statsd 实例需配 deleteIdleStats: true(否则哈希路由下"闲置刷 0"会在所有节点扩散);checkInterval 内节点失联会重算哈希环。

六、日常运维命令速查

场景命令
发计数器/计时/仪表/集合echo "k:1|c" | nc -u -w0 HOST 8125(ms/g/s 同理)
带采样率echo "k:5|c|@0.1" | nc -u -w0 HOST 8125
标签指标echo "k:1|c|#env:prod" | nc -u -w0 HOST 8125
看服务健康echo stats | nc -w1 HOST 8126
看桶快照echo counters|gauges|timers | nc -w1 HOST 8126
看生效配置echo config | nc -w1 HOST 8126
摘流/挂回echo "health down|up" | nc -w1 HOST 8126
删污染桶echo "delcounters k.sub.*" | nc -w1 HOST 8126
探活(脚本用)echo health | nc -w1 HOST 8126 | grep -q '^health: up'
Nagios 阈值perl utils/check_statsd.pl --host H --port 8126 --metric graphite.last_flush --warning 15 --crit 30
平滑停止systemctl stop statsd(触发 Final Flush,忌 kill -9)
改配置生效直接编辑 config.js(automaticConfigReload 默认热加载)

七、命令面排障实录

  1. nc 连管理口不带 -w1 会挂死:8126 长连接不主动断开,echo stats | nc HOST 8126 输出完仍等待;官方 check_statsd_health 正是栽在这点(4.2)。脚本化调用统一带 -w1 或发 quit。
  2. sets 命令不存在:想 dump set 桶会得 ERROR(3.6),set 结果只能从后端输出看(stats.sets.<key>.count)。
  3. 坏行静默:协议写错不报错、不回执,唯一痕迹是 messages.bad_lines_seen 推进 + DEBUG 日志 Bad line: …;上线初期用 dumpMessages: true 对照抓包(配置篇 8.3)。
  4. health 与 healthStatus 不一致:配置篇 8.2 实测 healthStatus: "down" 启动后 health 仍回 up——摘流以运行时命令为准。

至此,StatsD 参考实现的四块拼图完整:选型认知 → 安装部署 → 配置参数 → 命令运维。按顺序读前三篇(介绍与选型、安装指南、配置详解)即可从零到生产可用。

Statsd 0.10.2 常用 CLI 命令与工具详解 - Quzuo