Bamboo Pipe Engine (BPE)
用 Rust 编写的高性能、可嵌入的流式规则引擎:基于 SQL 的查询接口 + LLVM JIT 编译
BPE 面向风控与告警场景:高吞吐预过滤、时间窗口聚合、per-key 分组、维表关联——热路径
延迟纳秒级。
特性总览
| 能力 | 说明 |
|---|---|
| JIT 过滤 | WHERE 条件经 LLVM-19 编译为原生机器码 |
| 多规则 | 同一记录可注册多个 mapper,逐条评估 |
| 标量函数 | 15+ 个(_abs _pow _sqrt _greatest _to_double …),SELECT 与 WHERE 均可用 |
| 聚合函数 | _suml/_count/_avg/_minl/_maxl/_firstl/_lastl(含 Double 变体)、_stddev/_variance(总体/样本) |
| 时间窗口 | 固定窗口(Tumbling)与滑动窗口(Sliding),事件时间或处理时间 |
| Watermark | 事件时间乱序容忍(lag_ms),数据驱动提前触发 + wall-clock 兜底 |
| Per-key 分组 | def_keyed_window_aggregate:窗口结果按 key 列分组 |
| 维表关联 | 黑名单/限额等 keyed 查询表,SQL _dim_has(dim_id, key) / _dim_get(dim_id, key) |
| 低开销 | 无锁单线程热路径;无窗口路径零额外开销 |
快速开始(Rust)
[dependencies] |
use bpe::{def_incoming, def_mapper, new_data, start, stop, Column, U8Bytes}; |
时间窗口(风控/告警场景)
use bpe::{def_window_aggregate, def_keyed_window_aggregate, Window}; |
语义说明:
- 事件时间:
ts_field指定 Long(毫秒)列;窗口按事件时间对齐;lag_ms为乱序容忍,
早于 watermark(max_seen_ts - lag_ms)的记录被丢弃。 - 处理时间:
ts_field = None,窗口按到达时间对齐。 - 触发:窗口满足
end < watermark(事件时间推进)或end + lag_ms <= now
(wall-clock 兜底,数据停止时窗口仍上报)即触发。 - 空窗口也会触发(
size()==0,返回聚合初值)。 - 回调在引擎定时器线程执行,需线程安全(Send)且不宜阻塞。
维表关联
use bpe::{def_dimension, update_dimension, def_mapper}; |
SQL 函数参考
函数以 _ 前缀调用:_name(args)。
标量(SELECT 字段与 WHERE 条件均可用)
| 函数 | 说明 | 函数 | 说明 | |
|---|---|---|---|---|
_add/_sub/_mul/_div/_mod(a,b) |
算术 | _sign(x) |
符号(-1/0/1) | |
_abs(x) |
绝对值 | _trunc(x) |
截断小数 | |
_ceil/_floor/_round(x) |
取整 | _to_long(x) |
转 i64 | |
_sqrt(x) |
平方根 → f64 | _to_double(x) |
转 f64 | |
_exp(x) |
e^x → f64 | _pow(a,b) |
幂 → f64 | |
_ln(x) |
自然对数 → f64 | _greatest/_least(a,b) |
取大/取小 | |
_log10(x) |
常用对数 → f64 | _dim_has/_dim_get(dim_id,key) |
维表查询 |
聚合(窗口 / 聚合 SQL)
| 函数 | 说明 | 函数 | 说明 | |
|---|---|---|---|---|
_suml/_sumd(x) |
求和 | _avg(x) |
均值(f64) | |
_count(x) |
计数(任意列类型) | _firstl/_firstd(x) |
首值 | |
_minl/_minl(x) / _maxl/_maxd(x) |
最小/最大 | _lastl/_lastd(x) |
末值 | |
_stddev(x) |
总体标准差(f64) | _stddev_samp(x) |
样本标准差(f64) | |
_variance(x) |
总体方差(f64) | _var_samp(x) |
样本方差(f64) |
配置
cfg/config.toml(根目录由 BPE_HOME 环境变量指定):
dev_mode = true # true: 控制台+文件日志;false: 仅文件日志 |
构建
RUSTFLAGS="-lLLVM-19" cargo build --release |
依赖:Rust 2021、LLVM-19
性能
criterion 全链路测量(new_data → 入环形缓冲 → 窗口扫描 → JIT 过滤 → 字段提取 → 回调),release 构建:
| 场景 | 中位数 | 单核吞吐(约) |
|---|---|---|
| new_data + 过滤(4 字段,LIMIT 10) | ~0.44 µs/op | ~230 万条/秒 |
| new_data + 过滤 + 聚合(JIT 内核) | ~0.46 µs/op | ~220 万条/秒 |
全链路分解(perf_diff:6 条件 WHERE + 5 计算字段 SELECT,窗口满)
| 阶段 | 成本 | 占比 |
|---|---|---|
| insert(512B memcpy) | ~14 ns | 4.5% |
| 过滤 + 位图扫描 | ~106 ns | 34% |
| 字段提取 + 回调(10 条 × 5 字段) | ~194 ns | 62% |
| 合计 | ~314 ns/op | — |
纯聚合路径(bind def_aggregate,5 字段 × LIMIT 10):78 ns/op(1300 万条/秒)。
优化历程(perf_diff 场景,8.4 µs/op → 0.31 µs/op,约 27 倍)
- 增量命中位图:JIT 过滤在插入时每条记录仅执行一次(而非每次窗口扫描),结果按 slot 1 bit 存储
- 64 位块扫描:跳过零字 + TZCNT/LZCNT 定位置位(SIMD 友好的位运算)
- 预解析字段读取计划:SELECT 字段编译为 (offset, type) 直读 / 扁平化表达式树
- 聚合 JIT 内核:整批聚合编译为单个 LLVM 循环(直读 + 内联算术 + phi 累加器)——绑定/def_aggregate 路径从 ~82µs/op 降至 ~78ns/op(超 1000 倍)
热路径无锁、Rust 侧零分配:连续环形缓冲内存、预计算列偏移、JIT 编译过滤、
回调缓冲复用。无窗口路径不触碰窗口锁,纯过滤性能不受窗口功能影响。
本机复测记录(2026-09-25)
直接运行 examples/ 复测(非 criterion);release 构建,环境 Intel Core Ultra 9 285H
(16 线程,单 NUMA,实测 CPU scaling 约 49%);单消费者线程;各示例重复 3 次,波动约 ±3~5%。
| 示例 | 场景 | ns/op | 约 events/s |
|---|---|---|---|
perf_rsize |
入站(512B / 64B 记录) | 147.9 / 147.6 | ~680 万 |
perf_aligned |
过滤 6 条件 + 1 字段 | ~149 | ~670 万 |
perf_aligned2 |
过滤 1 条件 + 5 计算字段(LIMIT 1) | 50.0 | ~2000 万 |
perf_agg |
过滤 + 聚合(bind 路径,解释执行) | 68.1 | ~1470 万 |
perf_diff |
入站 + 过滤 + fetch + 回调 | 368~399 | |
sample |
入站 → mapper(过滤)→ aggregate,逐事件回调 | 983 | ~100 万 |
perf_diff 分解(复测):insert 15.8 ns;filter+scan ~118121 ns;fetch+callback 236260 ns。
要点:
- debug 与 release 差距显著:
sampledebug 约 3460 ns/op,release 约 983 ns/op(约 3.5×)。性能须以 release 为准。 - 瓶颈在管道投递,不在 SQL/JIT 求值:
fetch+callback(队列投递 + 回调派发)为最大单项;
6 条件过滤仅 ~118 ns,聚合内核 ~68 ns。 - 记录大小无影响:64B 与 512B 均为 ~148 ns/op,此规模下由每记录固定开销主导。
- 以上数字与上文 criterion / Esper 小节存在小幅差异(机器、测量方式、版本不同),此处仅作记录。
对标 Esper(特化内核基准,同规则同数据,单核)
| 场景 | BPE | Esper 7.1 | 优势 |
|---|---|---|---|
| 纯过滤(6 条件) | 133 ns | 240 ns | 1.8× |
| 过滤 + 5 计算字段 | 49 ns | 222 ns | 4.5× |
| 窗口聚合(len 10) | 78 ns | 172 ns | 2.2× |
边界声明:这是特化单表规则评估内核与通用 CEP 平台的对比,优势源于
特化——BPE 只做单表过滤/计算/窗口聚合;Esper 完整支持 CEP 模式匹配、多流
关联、状态持久化、exactly-once、watermark、分布式、内置接入、JMX 运维等。
BPE 不是 Esper 的通用替代:复杂规则/有状态模式用 Esper/Flink;
高频嵌入式预筛用 BPE(或级联 BPE 预筛 → Esper 复杂处理)。
方法学与复现见docs/benchmark/esper-comparison-20260815.md。
测试
RUSTFLAGS='-lLLVM-19' cargo test |
42 个测试二进制:单元测试、SQL 解析、过滤/聚合正确性、窗口语义(固定/滑动/
处理时间/watermark)、per-key 分组、维表查询,以及带断言的回归测试。
文档索引
docs/design.md— 架构说明docs/deconstruct/— 设计解构(类图/数据流图、算法、内存分析)docs/review/— 代码审查报告docs/detect/— 问题侦测与评分docs/refactor/— 重构方案与执行状态docs/code-part-modification/task-*— 各任务变更记录
依赖
- LLVM 19(经 inkwell 的 JIT)、sql-parse(SQL 方言)、log4rs(日志)、
hashbrown、core_affinity、strum、config