話は 2 つあります。Redis から来る場合、プロトコルは同じなので、問うべきは「何の挙動が違うのか」です。リレーショナルデータベースから来る場合、同じものは何ひとつないので、問うべきは「ワークロードのどの部分を移すべきか」です。答えはその一部であり、それがどこなのかを、これから示します。
クライアントは変わりません。kevy は RESP2 と RESP3 を話し、206 個のコマンドに応答します。既存のライブラリの接続先を変えるだけで、コードもそのまま、redis-cli もそのままです。新しく覚える SDK もプロトコルもありません。
だから本当の問題は、何が得られるのかだけです。得られるものは 4 つあります。そのどれにも価値を感じないなら、Redis に留まってください。あれは見事なソフトウェアであり、乗り換えのための乗り換えは 1 週間の浪費です。
バイナリに組み込み、ブラウザのタブに配り、アロケータのない Cortex-M で起動できます。いまはそのひとつひとつに、独自の API を持つ専用のストレージ層が要ります。ここでは同じエンジン、同じコマンドです。クライアント側に 2 つ目のキャッシュを書いた経験があるなら、それが検討する理由です。
セカンダリインデックス、マテリアライズドビュー、ベクトル KNN、BM25 全文検索がエンジンに入っています。モジュールでもサイドカーでもなく、元データからずれていく 2 つ目のコピーでもありません。Redis と検索クラスタを併用しているチームは、多くの場合ひとつにまとめられます。
# look up by a field, not just by the key
IDX.CREATE idx:city ON PREFIX user: FIELD city TYPE str KIND range
IDX.QUERY idx:city EQ osaka
# vectors, in the same engine, over the same keys
IDX.CREATE idx:sem ON PREFIX doc: FIELD vec TYPE vector KIND ann DIM 768 DISTANCE cosine
IDX.QUERY idx:sem KNN "<vector>" LIMIT 10同じマシンで Redis 8.10.1 に対して、GET は 1.33 倍、SET は 2.66 倍、INCR は 2.05 倍です。ただし、当てにする前に表の全体を読んでください——LPUSH と ZADD は 10% と 15% しか上回っておらず、リストやソート済みセットがホットパスなら、これは移る理由になりません。
ストアに RAM 予算を与えると、最もコールドな値はディスク上の使い捨て value log へ退避し、アクセスされたときに戻ります——コールドキーの上でもすべてのコマンドは変わらず、追記専用ログの永続化コントラクトも無変更です。RAM が保持できるキーの数を、ディスクがデータの量を決めます。大きな値やロングテールのために「Redis と別のディスクストア」を並べる構成を、これがひとつにします。正直な限界も述べます。既定ではオフで、v1 で退避するのは文字列とハッシュ(リスト、セット、ストリームはホットのまま)、そして 64 バイト未満の値は決して退避されません——stub が値と同じ大きさになるからです。
# kevy.toml
[tiering]
budget = "70%" # or "4gb", or "auto"クラスタはありません。レプリカはコピーであって、シャードではありません。AUTH も TLS もありません。そしていくつかのコマンドは挙動が違います——知っておくべき筆頭は、シャードをまたぐ RENAME が原子的ではないこと(複数キーの書き込みは shard 単位でのみ原子的)です。どれもバグではなく、すべてコマンドごとに文書化してあります。移ると決めたあとではなく、決める前に読んでください——各コマンドの本当のコストと、本当の差異。
# 1. dump what you want to move. it is a RESP file — readable,
# diffable, and it streams rather than loading into memory.
kevy-cli export -p 6379 --prefix user: dump.resp
-> exported 41023 keys -> dump.resp
# 2. load it. --strict stops on the first error rather than
# limping onward with a half-migrated keyspace.
kevy-cli import -p 6380 --strict dump.resp
-> imported 82046 ok, 0 errors, offset 4108331
# 3. prove they agree, rather than hoping.
kevy-cli digest -p 6379 user:
kevy-cli digest -p 6380 user:
-> 41023 keys 3bca92aa52269300 # the same hash, or you did not migrate
# an interrupted import resumes where it stopped:
kevy-cli import -p 6380 --resume dump.respRedis から export し、kevy に import して、両者が一致することを確かめます。以下のコマンドは、すべて実行したものです。
データベースを移してはいけません。移すのは、そもそもデータベースの問題ではなかった部分です。
セッション。レート制限。フィーチャーフラグ。ジョブキュー。すべてのリクエストが読み、誰も結合しないホットな行。たいていのアプリケーションでこれらは Postgres の中にあり、叩かれ続けているのもそこです。リレーショナルデータベースがそれらを苦手だからではありません。それらが、そもそも問い合わせではなかったからです。ただの参照です。キーは、もう分かっています。
Postgres には、他に並ぶもののない仕事を残してください——結合、アドホックなクエリ、分析、無関係な行にまたがる本物の分離レベルを伴うトランザクション。kevy は配信の経路を引き受け、データベースに夜を返します。
そして、単一テーブルの配信用の読み取りも移せます。TABLE.DECLARE で型付きカラム、セカンダリインデックス、複合 ORDER BY パスを一度だけ宣言する——あるいは手元の PG/MySQL スキーマファイルを kevy-sql でコンパイルする——それだけで、1 つのテーブルの読み取りパス(インデックスされた WHERE、残りのフィルタ、ORDER BY、ページング、COUNT)が kevy のインデックスにコンパイルされます。クエリ時のプランナはありません。kevy-sql はビルド時のコンパイラであって SQL エンジンではありません。join とアドホック SQL は名前つきで拒否され、Postgres に残ります。ほとんどのアプリケーションが ORM に実際に求めているのは、その部分です。
ワークロードごとに。赤い 3 行が、よく間違われるところです。
| ワークロード | 移すべきか | 理由 |
|---|---|---|
| セッション、トークン | *はい | TTL つきの、キーによる参照です。データベースは仕事としてではなく、厚意でやってくれていました。 |
| レート制限、カウンタ | *はい | 期限つきの INCR は原子的で O(1) です。SQL では、最もホットな行に対する行ロックになります。 |
| ジョブキュー | *はい | リストとストリーム。コンシューマグループと、メッセージごとの確認応答があります。キュー用のテーブルは、手数の増えたロックの慣習にすぎません。 |
| フィーチャーフラグ、設定 | *はい | 絶えず読まれ、めったに書かれず、結合されることはありません。 |
| 単一テーブルの読み取り(絞り込み、順序、ページング) | *はい | テーブルのアクセスパスを一度宣言する——あるいはスキーマファイルを kevy-sql でコンパイルする——だけで、インデックスされた WHERE + ORDER BY + LIMIT の読み取りは参照のままです。読みを捌くを参照してください。 |
| 集計(件数や合計) | *多くの場合 | マテリアライズドビューが書き込みの側で最新に保つので、読むたびに計算し直す必要がありません。 |
| 複数テーブルにまたがる結合 | !移すな | kevy に結合はなく、今後も持ちません。それは Postgres の仕事です。 |
| 分析、アドホックなクエリ | !移すな | クエリプランナもオプティマイザもありません。試さないでください。 |
| 無関係な行にまたがるトランザクション | !移すな | MULTI はシャード単位であって、全体ではありません。キースペース全体で直列化可能な分離が要るなら、必要なのはデータベースです。 |
赤い 3 行は、やることリストではありません。拒否です——kevy は結合もオプティマイザも持ちません。どちらも中途半端にやるくらいなら、やらないほうがましだからです。リレーショナルなワークロードのすべてと、ここでの実際のコストを書いてあります。正直な答えが「Postgres に置いたままにしてください」になるものも含めて。
# 1. pick ONE workload. sessions are the usual first, because
# nothing joins against them and losing one is survivable.
# 2. write to both for a week. reads still come from Postgres.
# you are checking that the shapes match, not that it is fast.
# 3. flip reads to kevy. keep the dual write.
redis-cli SET session:$SID "$JSON" EX 3600
# 4. when it has been boring for a fortnight, drop the table.
# then do the next workload. rate limits, then queues, then
# whichever of your read paths a secondary index can answer.一度に切り替えることはしません。ワークロードをひとつ移し、データベースを正としたまま、測ってください。
同じ 3 つのコマンドが、逆向きにも使えます。kevy-cli export はプレーンな RESP ファイルを書き出し、Redis 互換のサーバーなら、どれでもそれを取り込めます。そして digest が、コピーが忠実であることを証明します。移行ガイドは、入ってくる手順と同じ丁寧さで、出ていく手順も扱っています——動けなくなって留まられるより、きれいに出ていってもらうほうが、私たちとしてもずっといいと考えています。