kevy-alloc——可选分配器:它买到什么、代价是什么
kevy 默认使用系统分配器(glibc malloc)。也可以在编译期换上纯 Rust 的 span 分配器 kevy-alloc,作为整个进程的分配器:
cargo build --release -p kevy --features kevy-alloc这是一个编译期选择——分配器压在每一条路径底下,没有运行时开关。默认构建不携带它。
它买到什么
在基准参考机(io_uring、8 shard)上的实测,测量夹具与协议见 bench/REPORT.md:
- 碎片 / RSS:长时间运行的高换手负载下,常驻内存约为活数据的 2.16 倍,对照 glibc 的 2.40 倍——稳态常驻足迹小约 10%,且分配换手越剧烈差距越大。
- 容量余量:更小、更可预测的足迹正是分层容量模型做预算的对象;在容量吃紧的部署里,分配器就是「装得下」与「开始换页」之间的差别。
- 磁盘 / 持久化 / 稳定性:实测零代价——crash、复制、磁盘各门禁在两种构建下表现一致。
代价是什么
在打饱和的集合写角(某个 shard 的 owner 线程被流水线化的 sadd/zadd/hset 流量压满)上,该分配器的快路径每次调用约为 glibc 的 1.7 倍,表现为:
- 这些饱和角上 sadd 约 −10~−16%、zadd 约 −13% 吞吐(hash 写除外——小的 hash 值在 store 里内联存放,只付 −0.2%)。
- 分配不密集的角(GET/SET/INCR/LPUSH、cluster、RESP 兼容)定价在 −2~−6%;未饱和的服务器通常测不出任何差别——空闲余量把每调用成本吸收掉了。
什么时候启用
以下场景启用 kevy-alloc:
- 内存容量是硬约束(缓存机、分层窗口、多租户合并部署),省下约 10% 的 RSS 能换来真实余量。
- 负载以读为主或读写混合——实测的生产形状(R4a 语料)由读和聚合主导,那里分配器是免费的。
- 进程长期运行,凌晨三点把你叫醒的是碎片增长而不是峰值吞吐。
以下场景保持默认:
- 持续的、流水线化的 set/zset 写吞吐是头号指标,且 owner shard 常年饱和。
- 你想要与性能基线记录一致的那个二进制。