Riemann 0.3.12 配置参数详解
Riemann 0.3.12 配置篇:riemann.config DSL 全部入口参数默认值(tcp/udp/ws/sse/graphite/opentsdb/index/periodically-expire/instrumentation/logging/include/async-queue)逐项详解,streams 组合器语义与 changed/expired/coalesce/stable/top/rate 实测回显、SIGHUP 热加载、生产配置模板与 FAQ。
Riemann 0.3.12 配置参数详解
目标:逐项讲清 Riemann 0.3.12 配置文件
/etc/riemann/riemann.config(Clojure DSL)的全部参数入口与默认值——传输监听(tcp/udp/ws/sse/graphite/opentsdb)、索引与过期(index/periodically-expire)、自监控(instrumentation)、日志(logging)、模块化(include/depend/async-queue)以及 streams 组合器(where/changed/expired/coalesce/stable/top/rate 等)的语义与实测行为。全部参数默认值取自 0.3.12 官方源码(riemann.config / riemann.streams 命名空间),全部命令与回显均已在 Ubuntu 22.04.5 + Riemann 0.3.12 服务器环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(Jammy,x86_64)
- Riemann 版本:0.3.12(官方最新稳定版,2025-05-26 发布,查询日期 2026-11-01)
- Java 运行时:OpenJDK 11.0.32.1
- 配置文件:
/etc/riemann/riemann.config(Clojure DSL,本文实测配置见第七章模板) - 模块化 include 文件:
/etc/riemann/c1-include.clj - JVM 参数文件:
/etc/default/riemann(EXTRA_JAVA_OPTS="-Xms256m -Xmx512m") - 日志文件:
/var/log/riemann/riemann.log - 监听端口:5555/TCP+UDP(protobuf 事件)、5556/TCP(WebSocket/HTTP)、5557/TCP(SSE/HTTP 查询)、2003/TCP(Graphite 明文)、4242/TCP(OpenTSDB telnet)
- 服务主机名:
riemann-srv
安装过程(deb 包安装、systemd 托管、JVM 堆限)见 《Ubuntu 22.04 安装 Riemann 0.3.12 指南》,本文从配置层展开。
二、前置条件
Riemann 服务已按安装篇部署并处于运行状态,配置文件为 /etc/riemann/riemann.config(本文实测配置见第七章模板,另含 include 文件 /etc/riemann/c1-include.clj):
systemctl is-active riemann
active
事件注入与查询通道可用(本文所有实测均通过 5556 的 HTTP NDJSON 注入、5557 的 SSE 查询取证):
echo '{"host":"web1","service":"cpu","state":"ok","metric":10}' | \
curl -s -X POST --data-binary @- http://127.0.0.1:5556/events
{}
{} 即摄入成功回执。查询 DSL 的语法细节与 CLI 工具用法见《Riemann 0.3.12 常用 CLI 命令与工具详解》。
三、参数查看与修改方式
3.1 配置文件即 Clojure 程序
Riemann 没有 ini/yaml 式参数文件——/etc/riemann/riemann.config 是一段 Clojure 源码,服务启动时在 riemann.config 命名空间里求值。因此「参数」的形态是 (函数 选项map) 调用,官方 riemann.config 命名空间提供全部入口函数(tcp-server、index、streams、include 等),riemann.streams 命名空间提供全部组合器(where、changed、rate 等)。查看当前生效配置直接看文件即可,无独立 dump 命令。
修改方式:编辑 /etc/riemann/riemann.config → 语法校验(3.2)→ 热加载(3.3)。
3.2 语法校验(不抢端口)
riemann test /etc/riemann/riemann.config
INFO [2026-11-01 10:31:06,286] main - riemann.bin - Loading /etc/riemann/riemann.config
Testing clojure.core
Ran 0 tests containing 0 assertions.
0 failures, 0 errors.
test 模式加载配置并执行 riemann.test 用例,不占用监听端口,可与在线服务并存,用于上线前验证语法(launcher 完整说明见《Riemann 0.3.12 常用 CLI 命令与工具详解》)。
3.3 SIGHUP 热加载
改完配置无需重启,systemctl reload riemann(init 脚本发 SIGHUP)全量重载:
systemctl reload riemann
tail -3 /var/log/riemann/riemann.log
INFO [2026-11-01 10:28:21,734] SIGHUP handler - riemann.bin - Caught SIGHUP, reloading
INFO [2026-11-01 10:28:21,735] SIGHUP handler - riemann.pubsub - Sweeping transient subscriptions.
INFO [2026-11-01 10:28:21,779] SIGHUP handler - riemann.core - Hyperspace core online
Caught SIGHUP, reloading → Hyperspace core online 即重载完成;进程 PID 不变、索引保留(若新旧配置等价则沿用旧索引)。
四、参数总览
riemann.config 命名空间全部入口函数与默认值(0.3.12 源码实测口径):
| 入口函数 | 作用 | 关键默认值 |
|---|---|---|
(tcp-server opts) | protobuf/TCP 事件摄入 | :host "127.0.0.1"、:port 5555(TLS 时 5554)、:so-backlog 50 |
(udp-server opts) | protobuf/UDP 事件摄入 | :host "127.0.0.1"、:port 5555、:max-size 16384 |
(ws-server opts) | WebSocket/HTTP 接口 | :host "127.0.0.1"、:port 5556 |
(sse-server opts) | SSE/HTTP 查询接口 | :host "127.0.0.1"、:port 5558(发行版配置常显式 5557) |
(graphite-server opts) | Graphite 明文监听 | :host "127.0.0.1"、:port 2003、:protocol :tcp、:tags false |
(opentsdb-server opts) | OpenTSDB telnet 监听 | :host "127.0.0.1"、:port 4242 |
(index) | 核心索引 | NonBlockingHashMap,键 [host service],default-ttl 60 |
(periodically-expire interval opts) | 过期清扫线程 | interval 默认 10 秒;:keep-keys [:host :service] |
(instrumentation opts) | 自监控事件 | :interval 10、:enabled? true、ttl=2×interval、tag riemann |
(streams & things) | 追加处理流 | — |
(include path) | 加载其他配置/目录 | 目录递归收 *.clj/*.config |
(logging/init opts) / (logging/set-level ...) | 日志 | :rotate-count 10、:layout :riemann |
(async-queue! name pool-opts & children) | 异步队列流 | :core-pool-size 1、:max-pool-size 128、:keep-alive-time 10ms、:queue-size 1000 |
(publish channel) / (subscribe channel f) | 核心内 pubsub | — |
(delete-from-index) | 按字段删索引 | — |
(reinject) | 事件回流当前核心 | 警告:易死循环 |
(service! svc) / (clear!) / (apply!) / (start!) / (stop!) | 手动核心过渡 | 配合 depend/REPL |
(depend plugin artifact version opts) | pomegranate 拉依赖 | :exit-on-failure true、仓库默认 clojars |
(local-repo path) | Maven 本地仓库 | — |
(repl-server opts) | nREPL 远程调试 | — |
(update-index ...) | 已废弃,index 本身即流 | — |
⚠️ 注意:deb 默认配置只写
tcp-server/udp-server/ws-server且绑127.0.0.1,默认未启用sse-server/graphite-server/opentsdb-server——远程摄入与 HTTP 查询都需显式加配置并热加载。
五、核心参数分类详解
本章所有默认值均对照 0.3.12 源码核实,实测回显来自本文第七章配置(已部署生效)。
5.1 tcp-server:protobuf/TCP 摄入
(tcp-server {:host "0.0.0.0" :port 5555})
:host默认"127.0.0.1",生产需改"0.0.0.0"才能收远程 agent;:port默认 5555;开启 TLS 时默认 5554;:so-backlog默认 50(ss -ltn回显中 Recv-Q 列的 50 即此值);- TLS:
:tls? true且必须同时给:key(PKCS8 私钥)、:cert、:ca-cert三项,缺一 assert 报错。
5.2 udp-server:protobuf/UDP 摄入
(udp-server {:host "0.0.0.0" :port 5555})
:host/:port默认同 TCP;:max-size数据报上限默认 16384 字节,超限的包直接丢弃(protobuf parse error,不报错给客户端)——大批量事件应走 TCP 或减小单批条数;:so-rcvbuf可调接收缓冲。
5.3 ws-server 与 sse-server:HTTP/WebSocket 接口
(ws-server {:host "0.0.0.0" :port 5556})
(sse-server {:host "0.0.0.0" :port 5557})
ws-server默认 5556:WebSocket 订阅 + HTTPPOST /events(NDJSON,每行一个 JSON 对象,不是数组);sse-server代码默认端口 5558,本文与 deb 常见配置显式改为 5557:纯 HTTPGET /index?query=...返回 SSE 流(data:行);:headers可附加响应头,默认已含Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keepalive。
实测注入与查询闭环(5556 进、5557 出):
echo '{"host":"web1","service":"cpu","state":"ok","metric":10}' | \
curl -s -X POST --data-binary @- http://127.0.0.1:5556/events
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=service%20%3D%20%22cpu%22"
{}
data: {"host":"web1","service":"cpu","state":"ok","metric":0,"time":"2026-11-01T10:27:20.438Z"}
(此处回显为第七章 rate 流覆盖索引后的最终态,见 6.7。)
5.4 graphite-server:收 Graphite 明文
(graphite-server {:host "0.0.0.0" :port 2003})
- 默认
:host "127.0.0.1"、:port 2003、:protocol :tcp(可:udp);:parser-fn自定义解析;:tags把 Graphite tag 转事件属性,默认false。
实测:向 2003 写一行 Graphite 明文(metric.path value timestamp),即时查询:
ts=$(date +%s)
exec 3<>/dev/tcp/127.0.0.1/2003; printf "c1.graphite.value2 42 %s\n" "$ts" >&3; exec 3<&- 3>&-
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=service%20%3D%20%22c1.graphite.value2%22"
data: {"host":null,"service":"c1.graphite.value2","state":null,"description":null,"metric":42.0,"tags":["c1"],"time":"2026-11-01T10:29:00.000Z","ttl":60}
两个实测要点:
host为null——Graphite 明文行只有 path/value/ts,没有主机信息,事件不带 host;索引键[nil service],查询按 host 过滤会漏(见第八章 8.4)。service保留点分原名(c1.graphite.value2),不是空格分隔;用service = "c1 graphite value2"查询恒为空。
5.5 opentsdb-server:收 OpenTSDB telnet
(opentsdb-server {:host "0.0.0.0" :port 4242})
实测 put 命令(带 host= 标签)注入与查询:
ts=$(date +%s)
exec 4<>/dev/tcp/127.0.0.1/4242; printf "put c1.opentsdb.value2 %s 7.5 host=web1\n" "$ts" >&4; exec 4<&- 4>&-
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=service%20%3D%20%22c1.opentsdb.value2%22"
data: {"host":"web1","service":"c1.opentsdb.value2","state":null,"description":"c1.opentsdb.value2","metric":7.5,"tags":["c1"],"time":"2026-11-01T10:29:00.000Z","ttl":60}
与 graphite 的差异:OpenTSDB 行协议自带标签,put ... host=web1 的 host 标签会成为事件 host;description 回填为 metric 全名。:parser-fn 可自定义行解析。
5.6 index 与 periodically-expire:瞬态状态与过期
(index)
(periodically-expire 5 {:keep-keys [:host :service :tags]})
index返回核心索引流(NonBlockingHashMap),键[host service],同键新事件覆盖旧事件;default-ttl 60——事件无ttl且流里未补时按 60 秒存活;periodically-expire是清扫线程:默认每 10 秒扫一轮(本文显式 5 秒),把age > ttl的事件置state="expired"流回 streams 并发布到"index"pubsub 通道,随后从索引删除;:keep-keys默认[:host :service]——过期合成事件只保留这两个字段,加:tags可保留标签;:all保留全部字段;- 0.3.12 无
:jitter选项(较新代码才有,配置里写了不报错但无抖动效果)。
💡 技术拓展:内存态索引的淘汰策略常见对比——
策略 机制 代表 TTL 过期(本文所用) 每键存最新值,age>ttl 即删 Riemann index LRU 按最近访问淘汰 Redis allkeys-lru、本地缓存LFU 按访问频率淘汰 Redis allkeys-lfu容量上限+拒绝 满后拒写/驱逐 各类 ring buffer Riemann 选 TTL 过期,因为「当前状态」的语义就是「最近 ttl 秒内报告过才算活着」,agent 停止上报 = 状态消失,无需容量调参。
实测短命事件(ttl 2)的完整生命周期——注入后约 5 秒(清扫周期 5s)过期:
echo '{"host":"web1","service":"shortlived","state":"ok","metric":1,"ttl":2}' | \
curl -s -X POST --data-binary @- http://127.0.0.1:5556/events
sleep 6
grep shortlived /var/log/riemann/riemann.log | tail -2
INFO [2026-11-01 10:27:06,849] riemann task 3 - riemann.config - C1-CHANGED shortlived expired
INFO [2026-11-01 10:27:06,863] riemann task 3 - riemann.config - C1-EXPIRED shortlived
再查索引即消失:
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=service%20%3D%20%22shortlived%22"
(无输出——expired 事件已从索引删除)
5.7 instrumentation:自监控
(instrumentation {:interval 10})
:interval默认 10 秒;:enabled?默认 true(false 则不发自身健康事件);事件 ttl 默认 2×interval;tagriemann;- 采样内核与传输层服务:index size、streams rate/latency、各 server 的 in latency / conns / threads active / queue size 等,service 前缀
"riemann ",rate/latency 后缀(如riemann streams latency 0.99)。
实测(配置里给全流打了 c1 标签后按标签查询,节选):
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=tagged%20%22c1%22" | grep 'riemann-srv' | head -3
data: {"host":"riemann-srv","service":"riemann server udp 0.0.0.0:5555 in latency 0.95","state":"ok","description":null,"metric":null,"tags":["c1","riemann"],"time":"2026-11-01T10:28:10.421Z","ttl":20}
data: {"host":"riemann-srv","service":"riemann server tcp 0.0.0.0:2003 conns","state":"ok","description":null,"metric":1,"tags":["c1","riemann"],"time":"2026-11-01T10:28:10.421Z","ttl":20}
data: {"host":"riemann-srv","service":"riemann streams latency 0.99","state":null,"description":null,"metric":0.6470349999999999,"tags":["c1","riemann"],"time":"2026-11-01T10:28:10.420Z","ttl":20}
⚠️ 注意:源码注释称 instrumentation 事件
host=localhost,0.3.12 实测 host 是服务器主机名(riemann-srv)。按host = "localhost"查询自监控事件恒为空(见第八章 8.2)。
5.8 logging:日志参数
(logging/init {:file "/var/log/riemann/riemann.log"})
:file单文件日志;:files多文件各配 layout;:console?/:console-layout控制台输出;:layout取:riemann(默认)或:json;:logsize-rotate给定字节数则按大小轮转,否则按时间轮转;:rotate-count默认 10;- JVM 属性
-Dlogback.configurationFile优先于此处的配置; - 运行时调级:
(logging/set-level :warn)。
配置内 (info ...) 写入的自定义日志(本文实测各组合器取证即靠它):
INFO [2026-11-01 10:27:02,762] worker-3 - riemann.config - C1-INCLUDE include-test
5.9 include:模块化拆分
(include "/etc/riemann/c1-include.clj")
- 加载其他配置文件或目录(目录递归收集
*.clj/*.config);相对路径基于当前*config-file*所在目录; - include 文件在
riemann.config命名空间求值,可直接调streams/where等。
实测 include 文件 /etc/riemann/c1-include.clj:
; C1 include 验证:被主配置 (include ...) 加载
(streams
(where (service "include-test")
(fn [e] (info "C1-INCLUDE" (:service e)))))
注入匹配事件后日志回显:
echo '{"host":"web1","service":"include-test","state":"ok","metric":1}' | \
curl -s -X POST --data-binary @- http://127.0.0.1:5556/events
grep C1-INCLUDE /var/log/riemann/riemann.log | tail -1
INFO [2026-11-01 10:27:02,762] worker-3 - riemann.config - C1-INCLUDE include-test
5.10 其余入口参数速查
(async-queue! name pool-opts & children):为子流建独立线程池异步队列,防慢下游阻塞摄入。:core-pool-size默认 1、:max-pool-size默认 128、:keep-alive-time默认 10 毫秒、:queue-size默认 1000;每个调用创建一个 threadpool-service,滥用会线程膨胀。(publish channel)/(subscribe channel f):核心内 pubsub 总线,periodically-expire即向"index"通道发布过期事件。(delete-from-index):([] [host service])删指定键;([fields])按字段删。(reinject):事件回流当前核心——配置不当会形成死循环,慎用。(service! svc):热加载时复用服务实例不打断连接;(clear!)/(apply!)/(start!)/(stop!)手动核心过渡,配合depend或 REPL。(depend plugin artifact version opts)+(local-repo path):pomegranate 运行时拉依赖并load-plugin;:exit-on-failure默认 true(拉不到直接退出),仓库默认仅 clojars(HTTPS)。(repl-server opts):开 nREPL 端口远程调试配置。(update-index ...):已废弃,index本身即流,直接写进streams即可。
六、streams 组合器详解
riemann.streams 命名空间的组合器是配置的灵魂。本章逐个讲语义,并给出 0.3.12 实测回显(测试流均落在 (fn [e] (info "C1-..." ...)) 写日志的探针上)。
6.1 where:谓词过滤(0.3.12 无 when)
(where (service "cpu") ...) ; 等值
(where (host #"^web") ...) ; 正则
(where (or (service "cpu") (service "mem")) ...)
(where (not (tagged "batch")) ...) ; 反义过滤
(where (service "cpu") ... (else ...)) ; else 子句兜底
- 谓词符号可重写:
host/service/state/metric/metric_f/time/ttl/description/tags/tagged/tagged-all/tagged-any;(metric 1 2 3)表任一相等;(service #{...})集合成员。 - 0.3.12 没有
when——网上旧文档/博客里的(when ...)写法在本版本直接报Unable to resolve symbol: when,反义过滤一律用(where (not expr))(见第八章 8.3)。
6.2 changed:状态变化才放行
(changed :state (fn [e] (info "C1-CHANGED" (:service e) (:state e))))
- 默认按
[host service]记忆上一值,字段变化才放行;:init设初值,:pairs? true时子流收到[旧 新]向量;(changed-state)是(changed :state)的别名。
实测回显(cpu 从 ok 翻 critical、flap 三连翻转、graphite 首见、shortlived 过期翻转,全部只输出「变化」时刻):
INFO [2026-11-01 10:27:02,749] worker-1 - riemann.config - C1-CHANGED cpu critical
INFO [2026-11-01 10:27:02,756] worker-2 - riemann.config - C1-CHANGED shortlived ok
INFO [2026-11-01 10:27:03,797] worker-3 - riemann.config - C1-CHANGED flap critical
INFO [2026-11-01 10:27:04,804] worker-4 - riemann.config - C1-CHANGED flap ok
INFO [2026-11-01 10:27:04,822] defaultEventExecutorGroup-2-4 - riemann.config - C1-CHANGED c1.graphite.value nil
INFO [2026-11-01 10:27:06,849] riemann task 3 - riemann.config - C1-CHANGED shortlived expired
注意 cpu 事件先注入两条 ok(重复值被吞、无日志),第三条 critical 才打出——这就是 changed 的去重语义;graphite 事件 state 为 nil,首见即「变化」。
6.3 expired / not-expired:过期事件流
(expired (fn [e] (info "C1-EXPIRED" (:service e))))
expired?判据:state == "expired"或 age 超过 ttl(ttl 缺省用 index 的default-ttl 60)。
实测(5.6 的 shortlived 事件过期时):
INFO [2026-11-01 10:27:06,863] riemann task 3 - riemann.config - C1-EXPIRED shortlived
6.4 coalesce:时间窗合并
(where (service "coalesce-test")
(coalesce 5 (fn [es] (info "C1-COALESCE" (count es)))))
- 每 5 秒把窗口内事件合并成一个事件向量交给子流一次(子流收
es向量而非单事件)。
实测:注入 h1/h2/h3 三条 coalesce-test 后,日志每 5 秒输出一轮(窗口内剩余条数递减,空窗输出 0 条向量被探针 count 显示):
INFO [2026-11-01 10:27:02,784] riemann task 1 - riemann.config - C1-COALESCE 3
INFO [2026-11-01 10:27:07,783] riemann task 3 - riemann.config - C1-COALESCE 3
INFO [2026-11-01 10:27:12,783] riemann task 2 - riemann.config - C1-COALESCE 3
INFO [2026-11-01 10:27:17,783] riemann task 1 - riemann.config - C1-COALESCE 3
6.5 stable:持续稳定才放行(防抖)
(where (service "flap")
(stable 5 :state (fn [e] (info "C1-STABLE" (:state e)))))
- 字段值连续 5 秒不变才放行,期间缓冲;用于过滤抖动(flapping)。
实测:flap 事件 1 秒内 ok→critical→ok 三连翻转,6.2 的 changed 流每条都打,而 stable 流全程静默;直到第 9 秒连续 ok 超窗才放行,之后每轮稳定重复输出:
INFO [2026-11-01 10:27:09,803] riemann task 0 - riemann.config - C1-STABLE ok
INFO [2026-11-01 10:27:13,814] worker-1 - riemann.config - C1-STABLE ok
6.6 top:前 K 名打标(惰性降级)
(where (tagged "rank")
(top 2 :metric
(tag "top" index)
index))
(top k f top-stream [bottom-stream [demote?]]):按f排序前 k 名进 top-stream,其余进 bottom-stream(内部由dual实现,排名变化时惰性降级)。
实测:注入 ranker 的 r1=1 / r2=5 / r3=9 后查询——r3、r2 带上了 top 标签,r1 只有 rank:
data: {"host":"ranker","service":"r3","state":"ok","metric":9,"tags":["top","rank"],"time":"2026-11-01T10:27:02.773Z"}
data: {"host":"ranker","service":"r2","state":"ok","metric":5,"tags":["top","rank"],"time":"2026-11-01T10:27:02.773Z"}
data: {"host":"ranker","service":"r1","state":"ok","metric":1,"tags":["rank"],"time":"2026-11-01T10:27:02.772Z"}
按标签反查 tagged "top" 命中 r2/r3 两条;host = "ranker" and not tagged "top" 在 ttl 60 过期后查询为空:
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=host%20%3D%20%22ranker%22%20and%20not%20tagged%20%22top%22"
(无输出——ttl 60 已过期被清扫)
6.7 rate:事件速率流
(where (service "cpu")
(by :host
(rate 5 index)))
(rate interval & children):每interval秒把窗口内 metric 求和 ÷ interval 合成一个 rate 事件,模板取窗口内最近一个带 metric 的事件,ttl 随窗口递减。- 关键陷阱:rate 事件与原始事件
[host service]键相同,写入同一 index 后互相覆盖——索引里看到的是 rate 值而非原始 metric(实测取证见《Riemann 0.3.12 常用 CLI 命令与工具详解》,轮询序列 10→10→6→6→6→0→0→0,6.0=30/5)。
实测:向 web2 注入 3 条 cpu metric 10,6 秒后查询(rate 窗口已过、空窗归零):
printf '{"host":"web2","service":"cpu","state":"ok","metric":10}\n{"host":"web2","service":"cpu","state":"ok","metric":10}\n{"host":"web2","service":"cpu","state":"ok","metric":10}\n' | \
curl -s -X POST --data-binary @- http://127.0.0.1:5556/events
sleep 6
curl -s --max-time 2 "http://127.0.0.1:5557/index?query=host%20%3D%20%22web2%22%20and%20service%20%3D%20%22cpu%22"
{}
{}
{}
data: {"host":"web2","service":"cpu","state":"ok","metric":0,"time":"2026-11-01T10:29:10.810Z"}
6.8 tag / with / default / adjust / scale:字段改写
(tag "c1" index) ; 加标签(distinct,实测全流事件均带 ["c1"])
(untag "c1" ...) ; 去标签
(with :state "critical" ...) ; 强制改字段(nil=删字段),仅子流可见
(default :ttl 60 ...) ; 仅当字段为 nil 才填(第七章模板主链即用它)
(adjust [:metric (* 2)] ...) ; 基于当前值改;smap 别名
(scale 1000 ...) ; metric 乘系数
事件不可变:with/default/adjust 只影响子流收到的副本,上游与其他并行流不受影响——这是理解 Riemann 流「分支各改各的」的关键。
6.9 其余组合器速查(0.3.12 源码实际存在清单)
| 组合器 | 语义 | 备注 |
|---|---|---|
(match f value & children) | 自定义谓词匹配 | riemann.common/match |
(split / split* / splitp) | 首个匹配谓词分流 | 奇数形式带默认流 |
(by fields & children) | 按字段值分叉子流 | 字段可为一元函数;无 GC,无界值会泄漏 |
(by-builder [sym field] forms) | fork 时按值构造子流 | — |
(runs len field & children) | 连续 n 个事件字段全同才放行 | 防抖另一形态 |
(throttle n dt) | dt 秒最多放行 n 条 | 立即丢弃余量、零延迟 |
(rollup n dt) | dt 秒最多调用子流 n 次 | 传事件向量、溢出滚存 |
(batch n dt) | 满 n 条或 dt 秒成批 | 传向量 |
(moving-event-window n) / (window n) / (fixed-event-window n) / (moving-time-window n) / (fixed-time-window n) / (fixed-offset-time-window n) | 事件向量窗口 | — |
(fold / fold-all) | 对窗口 metrics 聚合 | mean/median/mode(s)/sum/product/minimum/maximum/std-dev/count/sorted-sample |
(percentiles interval points & children) | 分位数 | service 追加 " 0.95" 等后缀 |
(ewma-timeless r) / (ewma halflife) | 指数加权移动平均 | — |
(counter [init]) | metric 累加计数 | tag reset 重置 |
(ddt [n] & children) | metric 对时间求导 | — |
(fill-in interval) / (fill-in-last interval update) / (interpolate-constant interval) | 空洞补发 / 固定间隔重发 | — |
(fold-interval interval event-key folder & children) | 窗口聚合回写字段 | — |
(periodically-until-expired [interval [delay] f]) | 事件驱动周期任务,ttl 到期停 | — |
(part-time-fast / part-time-simple interval ...) | 时间分箱基础件 | percentiles 的底层 |
(execute-on executor & children) | 线程池执行子流 | 配 service!/threadpool-service |
(exception-stream ex & children) | 子流异常转事件送 ex | 默认仅 warn 日志 |
(bit-bucket) | 丢弃 | — |
(dual pred t f) | 镜像双流 | 另一边收 expire;top 的实现 |
(append ref) / (register ref) | 收集到 atom | 测试用 |
(forward client) | 经 riemann.client 转发 | — |
(project fields & children) | 只保留指定字段 | — |
(apdex) / (clock-skew dt f) / (predict-linear ...) | APDEX / 时钟偏移 / 线性预测 | — |
(smap f) / (smap* f) / (smapcat) / (sflatten) / (sreduce f [val]) / (sdo) | 函数式组合 | nil 丢弃/透传有别 |
(sum-over-time) / (mean-over-time) | 已废弃 | 用 counter/ewma-timeless |
(synchronize) / (convert-strings) / (retry) / (timeout) / (tsv) / (partition) / (concat) / (average) / (percentile) | 0.3.12 不存在 | 勿照旧文档抄写 |
测试辅助(riemann.test):(deftest name body) 全新时间上下文+清索引、(tests & body)、(inject! events)、(run-stream / test-stream / lookup)、(tap name & children) 记录到 *results*、(io & children) 测试期抑制副作用——配合 riemann test 子命令做配置回归测试。
七、生产配置模板
适用场景:4 核 8GB 内存、50GB SSD 的单机 Riemann,监控约 1000 台主机、峰值约 5 万事件/分钟,需要收编 Graphite 明文与 OpenTSDB 上报、事件入索引供 SSE 查询、异常事件经邮件/PagerDuty 告警(告警出站函数需按环境配 SMTP/PagerDuty 凭据,模板中以注释标注)。模板即本文实测部署的 /etc/riemann/riemann.config(探针日志行可按需替换为真实告警流):
; -*- mode: clojure; -*-
; vim: filetype=clojure
; 生产模板:4C8G 单机 / ~1000 主机 / ~5万事件每分钟(实测于 0.3.12)
(logging/init {:file "/var/log/riemann/riemann.log"})
; 摄入面:TCP/UDP 5555, WS/HTTP 5556, SSE/HTTP 5557, Graphite 2003, OpenTSDB 4242
; 内存预算:JVM 堆 256-512MB(/etc/default/riemann),索引仅存最新态,磁盘占用主要是日志
(let [host "0.0.0.0"]
(tcp-server {:host host :port 5555})
(udp-server {:host host :port 5555})
(ws-server {:host host :port 5556})
(sse-server {:host host :port 5557})
(graphite-server {:host host :port 2003})
(opentsdb-server {:host host :port 4242}))
; 过期清扫:5 秒一轮;过期事件保留 tags 便于按标签告警路由
(periodically-expire 5 {:keep-keys [:host :service :tags]})
; 业务流按团队拆分到独立文件,目录可整体 include
(include "/etc/riemann/c1-include.clj")
(let [index (index)]
(streams
; 1. 主链:补 ttl + 打标 + 全量入索引
(default :ttl 60
(tag "prod" index))
; 2. 状态翻转告警(changed 去重,避免每事件一封邮件)
(changed :state
(where (tagged "critical-ok")
(fn [e] (info "ALERT" (:service e) (:state e)))))
; 3. 过期事件:agent 停报即告警(生产替换为 email/pagerduty 流)
(expired
(fn [e] (info "EXPIRED" (:host e) (:service e))))
; 4. CPU 速率:按 host 分叉,5 秒窗口(注意 rate 覆盖索引原值,见 6.7)
(where (service "cpu")
(by :host
(rate 5 index)))
; 5. Top-2 热点服务打标(惰性降级,见 6.6)
(where (tagged "rank")
(top 2 :metric
(tag "top" index)
index))
; 6. 高频事件合并输出(5 秒一批,防告警风暴,见 6.4)
(where (tagged "batch")
(coalesce 5
(fn [es] (info "BATCH" (count es)))))
; 7. 抖动过滤:稳定 5 秒才告恢复(防 flap 刷屏,见 6.5)
(where (tagged "flap")
(stable 5 :state
(fn [e] (info "RECOVERED" (:state e)))))))
逐项要点::ttl 60 主链兜底 agent 漏报 ttl;keep-keys 加 :tags 让过期事件仍可被 tagged 谓词路由;rate/top/coalesce/stable 四条治理流分别对应「速率、热点、合并、防抖」四类生产刚需;出站告警(email/pagerduty/graphite 转发)在对应 (where (tagged ...)) 子树里挂接,凭据类参数走环境变量注入,不落配置文件明文。
八、常见问题(FAQ)
8.1 刚注入的事件查不到了?
Q: 事件明明发过,几分钟后 GET /index 查不到?
A: 正常行为——Riemann 索引是瞬态状态,age > ttl 即被 periodically-expire 清扫(本文实测:shortlived ttl 2 秒后过期、graphite/opentsdb 事件 ttl 60 秒后查询为空)。查历史请外接 Graphite/时序库;要事件「活着」就保证 agent 上报间隔小于 ttl,或显式加大 ttl。
8.2 查不到 Riemann 自监控事件?
Q: host = "localhost" and service = "riemann streams rate" 返回空?
A: 0.3.12 实测 instrumentation 事件 host 是服务器主机名(本文环境为 riemann-srv),不是源码注释里的 localhost。改用 host = "riemann-srv" 或直接 tagged "riemann" 查询。
8.3 配置里写 (when ...) 报错?
Q: 照博客示例写 (when (service "cpu") ...),加载报 Unable to resolve symbol: when?
A: 0.3.12 的 riemann.streams 没有 when,只有 where。需要「不满足条件时走另一支」用 (where expr ... (else ...)),需要反义过滤用 (where (not expr) ...)。
8.4 Graphite 转发进来的事件按 host 查不到?
Q: (graphite-server) 收上来的数据,host = "web1" 恒为空?
A: Graphite 明文行只有 path value ts,事件 host 为 null(实测回显见 5.4)。按 service 查,或在转发链上游用 (with :host "web1" ...) 补;OpenTSDB 通道则用 put ... host=web1 标签带上。
8.5 旧文档里的组合器/选项不生效?
Q: (synchronize)、(percentile ...)、(periodically-expire 10 {:jitter 2}) 报错或无效果?
A: 0.3.12 源码清单里没有 synchronize/convert-strings/retry/timeout/tsv/partition/concat/average/percentile(单数)这些函数;periodically-expire 无 :jitter 选项。以 6.9 速查表为准,写前先 riemann test 校验。
8.6 热加载后端口没变/连接断了?
Q: 改了 :port reload 后旧端口还在监听?
A: reload 是全量过渡:旧 server shut down、新 server online(安装篇 8.3 实测日志)。若新配置求值失败,核心保持旧配置运行——看 /var/log/riemann/riemann.log 是否有 Hyperspace core online 收尾;等价配置热加载会保留旧索引,(service!) 复用可避免连接打断。
九、参考链接
- Riemann 配置源码(riemann.config / riemann.streams 命名空间):https://github.com/riemann/riemann/tree/master/src/riemann
- Riemann 官方文档:https://riemann.io/
- Riemann 0.3.12 Releases:https://github.com/riemann/riemann/releases/tag/0.3.12
- 安装与 systemd/JVM 托管:《Ubuntu 22.04 安装 Riemann 0.3.12 指南》
- CLI 工具与接口操作:《Riemann 0.3.12 常用 CLI 命令与工具详解》
- 选型背景:《Riemann 介绍与选型指南》