Viceroyを眺める

便利そうなプレスリリースが出て、色々調べてたら開発用ローカルサーバーのコードが見つかったので土曜の夜の暇つぶしに眺めてみる。

開発用ローカルサーバーのコードを読んだところでなんだという感じなのだが....

登場人物

概念

  • downstream request/response: クライアントから飛んできたリクエスト/レスポンス
  • upstream request/response: バックエンド系に飛んでいくリクエスト/レスポンス

ゲスト側

fastly create

Fastly Compute@EdgeSDKリポジトリは非公開のようだがcrate.ioやdocs.rsでホストされており、コード自体は見れる。

fastly-sys

上述のfastly createが呼び出すFFIextern "C"で定義. 要はユーザーの書いたwasmモジュールにimportされる関数のシグニチャを定義しているにすぎない。基本なんでもハンドルを経由して動かす。

ホスト側(Viceroy)

MozillaからFastlyに移籍したWasm/Rust組がIssueとかでよく見かける(当たり前)。

Viceroyrev. 28e4078e時点)

fastly CLIfastly compute serveすると起動する「開発用ローカルサーバー」の実態

今のところ未実装なものが色々あるが、読んで遊ぶには十分。

Fastly社の各種発表を聞くに、商用環境のホスト側はlucetでwasmモジュールAOTコンパイルした上で実行しているらしい。一方、こちらはwasmtimeを使っているのでサーバー起動時にwasmtime::Moduleを生成、各リスエストごとに実行時に環境(後述のSessionとリンクしてwasmtime::Instanceを作って実行する。

アプリケーション自体はhyperを使って書かれているのでいろいろasync/awaitする.

compute-at-edge-abi

witx(初めて知った)で記述されたABI定義。fastly-sysに対応する定義が記載されている。

Viceroyではwiggleの提供するprocedural macroを用いて、viceroy_lib::wiggle_abiとの対応を取る

viceroy_lib::session::viceroy_lib

downstream requestごとに生成される. 上述のcompute-at-edge-abiで定義されたABIもほぼこの上に実装されている.

処理の流れ

作るのがめんどくさいのでシーケンス図は省略

一番美味しいところはExecuteCtx::run_guest()を読めばよい.

各downstream requestに対するゲストコード(wasmコード)は、tokio::task::spawn()される。デスヨネー。

SessiontokioのchannelのSenderを持っているので、downstream responseが打ち返されたら(fastly_sys::fastly_http_resp::send_downstreamが呼び出されたら)、渡ってきたSenderに詰める.

つまり、ゲストコードがfastly::Response::send_to_clientfastly::ResponseHandle::stream_to_client )やfastly::Response::stream_to_clientfastly::ResponseHandle::stream_to_client )を(ユーザーまたは#[fastly::main]によって生成されたコードが)呼び出すことで、処理がホスト側に渡る。

もちろんホスト側ではそれを待ち構えているので、うまいことハンドルして終わり。

感想

小さいしRustで書かれてるので読みやすい。Proxy-Wasmな、Wasmな任意コードを動かす配信サーバーの実装例 + ユーザー向けSDKの作り方としても読める感じだった。

ただFastlyというCDNサービスを使う側の視点としてViceroyを見た場合、あくまでもFastly Compute@Edgeのユーザー用ローカル開発シミュレータ専用に実装されたようにも読めるので、本番との挙動の差異をどうやって埋めていくかが気になるところ。テストスイートとかどうするんだろう?