TairRoaring は、Alibaba Cloud Tair が実装した Roaring ビットマップデータ構造です。この実装では、以下の 3 つの最適化を組み合わせることで、低メモリ使用量を実現しつつ高いクエリスループットを提供します。
2 段階インデックスおよび動的コンテナ — 広範なデータ分布にわたって、パフォーマンスと空間計算量のバランスを最適化します。
単一命令複数データ (SIMD)、ベクトル化、およびポップカウントアルゴリズム — 時間計算量および空間計算量の両方における計算効率を向上させます。
Tair のストレージエンジン — 実稼働ワークロードに求められる計算性能および安定性を提供します。
コマンドの完全なリファレンスについては、「TairRoaring」をご参照ください。
テスト環境
本ドキュメント内のすべてのベンチマークは、16 GB Tair (Enterprise Edition) DRAM ベースのインスタンスに対して実行されます。クライアントとインスタンス間のネットワーク遅延は 0.1 ms 未満です。
クラスターアーキテクチャのテストでは、DRAM ベースのクラスターインスタンスを 4 台使用し、各シャードのサイズは 4 GB です。
| インスタンス | シャード数 |
|---|---|
| 8 GB | 2 |
| 16 GB | 4 |
| 32 GB | 8 |
| 64 GB | 16 |
クライアントは、インスタンスと同じゾーンに配置され、プロキシエンドポイント経由で接続されます。すべてのインスタンスは、テスト中のネットワーク飽和を防ぐため、最大帯域幅を 2,048 Mbit/s に設定されています。
本ドキュメント全体で示す QPS 値は、特定のテスト条件で測定された参考値です。実際のパフォーマンスは、ご利用のインスタンス仕様、データ分布、キー数、ネットワーク環境、およびコマンドの混合比率によって異なります。
テストツール
ダウンロード先:redis-benchmark.tar.gz
このツールは Go 言語で記述されており、redis-benchmark ユーティリティと同様の設計を採用しています。使いやすく、カスタマイズも容易です。各リクエストごとに 2 つの独立したランダム値(__RAND__ および __RAND2__)を生成し、結果をヒストグラム形式で出力します。
パラメーター:
| パラメーター | デフォルト値 | 説明 |
|---|---|---|
-h | 127.0.0.1 | インスタンスエンドポイント |
-port | 6379 | インスタンスポート |
-a | — | <user>:<password> 形式のパスワード |
-d | 30 | テスト持続時間(秒) |
-c | — | リクエスト総数。設定すると -d をオーバーライドします。 |
-p | 4 | 同時接続数 |
-r | 100000000 | __RAND__ |
-r2 | 100000000 | __RAND2__ |
-command | TR.GETBIT foo-__RAND__ | 実行するコマンド。コマンドまたはパラメーターの末尾に __RAND__ または __RAND2__ を付加することで、ランダム値を生成できます。 |
-batching | — | パイプラインのバッチサイズ。コマンドを MULTI/EXEC でラップします。 |
例:
# TR.SETBIT を 20 の同時接続で 30 秒間実行します。
# キー:foo-0 ~ foo-99999、ビットオフセット:0 ~ 9999999。
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.SETBIT foo-__RAND__ bar-__RAND2__" \
-p 20 \
-c 1標準アーキテクチャのベンチマーク
このセクションのすべてのテストは、単一の 16 GB 標準アーキテクチャインスタンスを使用します。
単一キーのテスト
読み取りコマンド
各テストは、事前にデータが挿入済みの単一キーに対して 20 の同時接続で実行されます。
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.GETBIT foo-__RAND__ bar-__RAND2__" \
-p 20 \
-c 1結果:
| コマンド | リクエストあたりのレコード数 | パラメーター範囲 | QPS | 平均レイテンシー(ms) |
|---|---|---|---|---|
| TR.GETBIT | 1 | 1–10000000 | 255,000 | 0.21 |
| TR.GETBITS | 100 | 1–10000000 | 54,000 | 0.97 |
| TR.RANK | 1 | 1–10000000 | 161,000 | 0.24 |
| TR.RANGE | 100 | 0–100 | 129,000 | 0.46 |
| TR.SCAN | 100 | 1–10000000 | 130,000 | 0.38 |
コマンドの記述
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.SETBIT foo-__RAND__ bar-__RAND2__" \
-p 20 \
-c 1結果:
| コマンド | リクエストあたりのレコード数 | パラメーター範囲 | QPS | 平均レイテンシー(ms) |
|---|---|---|---|---|
| TR.SETBIT | 1 | 1–10000000 | 145,000 | 0.37 |
| TR.SETBITS | 100 | 1–10000000 | 22,000 | 0.71 |
| TR.SETBITS(順序付き) | 100(最大オフセット 2^32) | 1–6000 | 28,000 | 0.66 |
| TR.APPENDBITARRAY | 1000(半分のビットが 1) | 1–10000000 | 10,000 | 0.38 |
| TR.SETRANGE | — | 1000 | 130,000 | 0.30 |
| TR.FLIPRANGE | — | 1–10000000 | 100,000 | 0.46 |
パイプラインテスト
パイプラインモードでは、MULTI と EXEC の間に複数のコマンドをグループ化することで、1 リクエストあたりのレイテンシーが増加する代わりにスループットを向上させます。
TR.SETBIT パイプライン
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 10000000 \
-command "TR.SETBIT foo-__RAND__ 1" \
-batching 10 \
-p 20 \
-c 1| 同時接続数 | バッチサイズ | ビット/秒 | 平均レイテンシー(ms) |
|---|---|---|---|
| 20 | 10 | 460,000 | 0.42 |
| 10 | 50 | 665,000 | 0.72 |
| 6 | 100 | 660,000 | 0.85 |
| 3 | 200 | 680,000 | 0.79 |
| 3 | 500 | 681,500 | 1.96 |
| 2 | 100 | 658,000 | 2.60 |

TR.GETBIT パイプライン
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.GETBIT foo-__RAND__ __RAND2__" \
-batching 10 \
-p 20 \
-c 1foo-__RAND__ キーが存在しない場合、空のキーとして扱われます。このテストを実行する前に、キーを事前に登録してください。| 同時接続数 | バッチサイズ | ビット/秒 | 平均レイテンシー(ms) |
|---|---|---|---|
| 20 | 10 | 572,700 | 0.34 |
| 10 | 50 | 725,900 | 0.65 |
| 7 | 100 | 772,000 | 0.85 |
| 7 | 200 | 788,800 | 1.67 |
| 5 | 500 | 746,000 | 3.10 |
| 2 | 100 | 770,000 | 2.10 |

メモリ使用量
キーのコンテナ分布を確認するには、TR.STAT foo JSON を実行します。TairRoaring では、配列コンテナ、ビットセットコンテナ、RLE(ランレングスエンコーディング)コンテナの 3 種類のコンテナにデータを格納し、データ分布に基づいて最も省スペースなタイプを選択します。
配列コンテナは、要素数が 4,096 を超えると自動的にビットセットコンテナに変換されます。
疎なデータ(ビット密度 < 6.25%)
疎なキーは主に配列コンテナを使用します。メモリ使用量は線形に増加し、キー容量 = カーディナリティ × 2 バイト となります。
| カーディナリティ | RLE コンテナ | 配列コンテナ | ビットセットコンテナ | ヒープメモリ(バイト) |
|---|---|---|---|---|
| 37,700,484 | — | 65,536 | — | 75,400,968 |
| 75,011,384 | — | 65,536 | — | 150,022,768 |
| 100,403,264 | — | 65,536 | — | 200,806,528 |
| 163,090,592 | — | 65,536 | — | 326,181,184 |
ランダムなデータ
カーディナリティが増加すると、配列コンテナはビットセットコンテナに変換されます。すべてのコンテナがビットセットコンテナとなった時点で、ヒープメモリは 536,870,912 バイトで安定します。
| カーディナリティ | RLE コンテナ | 配列コンテナ | ビットセットコンテナ | ヒープメモリ(バイト) |
|---|---|---|---|---|
| 253,104,088 | — | 65,534 | 2 | 506,208,102 |
| 261,169,659 | — | 63,273 | 2,263 | 522,227,634 |
| 267,974,804 | — | 35,932 | 29,604 | 533,159,296 |
| 273,694,253 | — | 6,607 | 58,929 | 536,491,922 |
| 343,504,134 | — | 0 | 65,536 | 536,870,912 |
| 535,589,835 | — | 0 | 65,536 | 536,870,912 |
連続するビット
連続するビットの分布におけるメモリ使用量は、特定のビットパターンに強く依存し、ばらつきが大きくなります。これらの結果は、一般的な計画目的には代表的ではありません。
複数キーのテスト
書き込みおよび読み取りコマンド
TR.SETBITS は 1 回の呼び出しで 100 個のランダムビットを書き込みます。各テストは、100,000 個の異なるキーに対して 20 の同時接続で実行されます。
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 10000000 \
-r2 100000 \
-command "TR.SETBITS foo-__RAND2__ __RAND__ __RAND__ ...(100 回)" \
-p 20| コマンド | リクエストあたりのレコード数 | QPS | 平均レイテンシー(ms) |
|---|---|---|---|
| TR.SETBIT | 1 | 91,003 | 0.43 |
| TR.SETBITS | 100 | 15,127 | 0.96 |
| TR.GETBIT | 1 | 154,941 | 0.32 |
| TR.GETBITS | 100 | 40,166 | 1.08 |
| TR.SCAN | 100 | 104,637 | 0.47 |
| TR.RANK | — | 151,161 | 0.32 |

ビットごとの演算
TR.BITOP
TR.BITOP は、複数のキーに対してビットごとの演算を実行し、その結果を新しいキーに保存します。サポートされる演算は、AND、OR、NOT、DIFF、XOR です。
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.BITOP dest-__RAND__ AND foo-__RAND__ foo-__RAND__" \
-p 3 \
-c 1| 操作 | 同時接続数 | QPS | 平均レイテンシー(ms) |
|---|---|---|---|
| AND | 3 | 940 | 3.18 |
| OR | 2 | 595 | 3.45 |
| XOR | 2 | 551 | 3.61 |
| DIFF | 3 | 3,577 | 0.83 |
| NOT | 1 | 1,281 | 0.77 |

TR.BITOPCARD
TR.BITOPCARD は、複数のキーに対してビットごとの演算を実行し、結果のキーを保存せずに、ビットが 1 に設定されている数を返します。サポートされる演算は、AND、OR、NOT、DIFF、XOR です。
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.BITOPCARD AND foo-__RAND__ foo-__RAND__" \
-p 2 \
-c 1| 操作 | 同時接続数 | QPS | 平均レイテンシー(ms) |
|---|---|---|---|
| AND | 2 | 971 | 2.05 |
| OR | 2 | 609 | 3.27 |
| XOR | 2 | 572 | 3.48 |
| DIFF | 2 | 4,290 | 0.46 |
| NOT | 2 | 3,577 | 0.55 |

クラスタアーキテクチャのベンチマーク
これらのテストは、4 台の DRAM ベースクラスターインスタンスにわたる水平スケーリングを測定します。各テストは、20 の同時接続で単一キーのコマンドを実行します。対象となるコマンドは、TR.GETBIT、TR.GETBITS、TR.SETBIT、および TR.SETBITS です。
サンプルコマンド:
./redis -h r-**********0d7f.redis.zhangbei.rds.aliyuncs.com \
-a user:password \
-d 30 \
-r 100000 \
-r2 10000000 \
-command "TR.SETBIT foo-__RAND__ bar-__RAND2__" \
-p 20 \
-c 1結果:
| コマンド | 2 シャード(8 GB) | 4 シャード(16 GB) | 8 シャード(32 GB) | 16 シャード(64 GB) |
|---|---|---|---|---|
| TR.GETBIT | 590,742 | 567,738 | 569,610 | 555,178 |
| TR.GETBITS | 53,900 | 91,991 | 172,969 | 229,214 |
| TR.SETBIT | 316,753 | 530,367 | 577,406 | 558,301 |
| TR.SETBITS | 31,917 | 57,843 | 116,614 | 160,891 |

TR.GETBIT の QPS は、シャード数にかかわらずほぼ一定です。これは、単一ビットの読み取り操作が 2 シャード時点で既にシャード単位の処理能力を飽和させるためです。一方、TR.GETBITS および TR.SETBITS は、マルチレコードリクエストがプロキシを介してシャード間で処理を分散するため、シャード数にほぼ比例してスケールします。