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 トラフィックで張り付いた状態)では、このアロケータの fast path は 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 コーパス)は読み取りと集計が支配的で、そこではアロケータは無料です。
- 長時間稼働のプロセスで、午前 3 時に呼び出されるのはピークスループットではなくフラグメンテーションの増大だというとき。
デフォルトのままにすべき場面:
- 持続的でパイプライン化された set/zset 書き込みスループットが最重要指標で、owner shard が飽和して稼働しているとき。
- パフォーマンスベースラインが記録されたのと同じバイナリを使いたいとき。