2023/11/04
目次
はじめに
昔、Rustの勉強も兼ねて、Redis風のKVSをサーバで実装していました。その実装を紹介します。
実装コードはGitHubで公開し、記事執筆以降もExample自体は書き換える可能性があります。 その際にコードの実態と記事上のコードがズレる可能性があります、ご了承ください。 そのような場合では、リポジトリのほうが整備されている状態と見てください。
↓記事執筆時点でのパーマリンク
https://github.com/ysuzuki19/rust-examples/tree/f04005ea64867430a9f491fc8491c83546c17f1ekvs
Sample for ...
本サンプルによって得られそうなことリスト
- tokioによる非同期処理
- tokioでTCPストリームを扱う
- RwLockによる排他制御
- 値を持つenum
- enumのFromStr/ToStr実装による変換
- enumのTryFromを用いた、失敗する可能性のある返還
- enumのパターンマッチ
- VecをArrayに変換しつつ要素数によるバリデーション
- strへ新規メソッドの実装
- thiserrorによるカスタムエラー定義
- unitテスト
設計
KVSとして基本的な機能を以下のように定義し、実装対象とした。
- TCPサーバとして動作
- パフォーマンスやセキュリティを求めず、単にTCP接続でメッセージをそのまま送信する。
- メッセージのやり取りによってKVSを利用する
- 同時に複数のクライアントが接続可能
- リクエストメッセージ
- 全てスペース区切りを基本とする
- 保存する値は文字列
- メソッドはシンプルな2つで、
GET
,SET
- GETは引数一つ
- SETは引数二つ
リクエストメッセージの設計
基本的には、
<method> <..args>
という形式をとる。
<..args>
の個数はメソッドごとに固定で、条件を満たさないとエラーとして処理をせずにレスポンスする。多くても少なくてもエラーとする。
例)
- ok
GET x
SET x 10
- er
GET
,GET x 10
SET
,SET x
レスポンスメッセージの設計
RustのResult型にインスパイアされたルールでメッセージを返す。リクエストが成功した場合には Ok ...
, 失敗した場合には Er ...
とする。
Okの場合はそのレスポンスのBody(取得対象の値や単なるメッセージ)を続け、Erの場合はその原因を人間が読みやすい形式で返す。
GET <key>
で <key>
というキーがセットされていない場合はそのエラーを返す。
クライアント向けSDKを開発する場合は、エラーコードだけで返すだけでいいと考えられるが、ここでの開発ではその辺りは目的としていないのでそこまではパフォーマンスを追い求めなかった。
例)
- ok
SET x 1
→Ok Succeed to insert
GET x
→Ok 10
- er
SET x
→Er method must to have 2 payloads
GET x 10
→Er method must to have 1 payloads
GET ashdf
→Er key not found: "ashdf"
(セットされていないキーはエラー)
内部で扱われるコマンドの設計
ここで実装対象とする GET
, SET
はどちらも直感的で、そのイメージ通りに
GET
: 引数一つで、引数をキーとする値を取得SET
: 引数二つで、引数1をキーとする値を引数2に上書き
と言った挙動を実現するものとする。
Cargo.toml
プロジェクト設定はこちら
[package]
name = "kvs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1.21.0", features = ["full"] }
thiserror = "1.0"
コード全容
src/
├── error.rs
├── handlers
│ ├── get.rs
│ ├── mod.rs
│ └── set.rs
├── kvs
│ ├── mod.rs
│ ├── response.rs
│ └── stream.rs
├── main.rs
├── query
│ ├── args.rs
│ ├── method.rs
│ ├── mod.rs
│ └── str_ssv_array.rs
└── types.rs
おわりに
当時の自分目線で、
この開発によって、排他制御のバリエーションを学ぶことができた。
参考
かなり前に開発したものの紹介なので、読んだ記事が抜けていると思います。スミマセン。
記事書く際に見たものをリストします。