Rabbitのキャッシュ・バッチ化の仕組み
by
Syusui Moyatani
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Rabbit🐰の キャッシュ・バッチ化のしくみ @syusui_s Rabbitのキャッシュ・バッチ化の仕組み © 2023 by Syusui Moyatani is licensed under CC BY-SA 4.0
Slide 2
Slide 2 text
自己紹介 しゅうすい @syusui_s Webエンジニアです。 ● Scrapbox書いてます(仕様や使い方) ● Nostrクライアントを作っています 0:10 +30
Slide 3
Slide 3 text
🐰Rabbit TweetDeck風クライアント https://syusui-s.github.io/rabbit/ ● 軽快な動作 ● マルチカラム ● ショートカット 0:40 +20
Slide 4
Slide 4 text
投稿の表示が大変 外部 サーバの 画像 プロフィール (kind0) リポスト数 (kind 6) リアクション数 (kind 7) 色々な関連情報が必要になる 1:00 +20
Slide 5
Slide 5 text
毎回取得すると遅い 表示のたびに取得するのは遅くて通信量も多い ● プロフィール等の表示が遅くなる ● スマホの通信量を消費してしまう ● サーバの制限に引っかかる ○ 一部リレーは購読数を制限している 1:20 +20
Slide 6
Slide 6 text
通信量・回数を減らす仕組みが欲しい Rabbitでは以下の手法を取り入れています ● キャッシュ ○ データを保存し、しばらくの間再利用する ● バッチ化 ○ 複数のイベントに対する購読をまとめて行う 1:40 +10
Slide 7
Slide 7 text
キャッシュ 1:50 +5
Slide 8
Slide 8 text
キャッシュ データを保存し、しばらく再利用する仕組みのこと ● プロフィール ○ あまり変更されないので、使いまわしても問題が少ない ○ 保存すればアイコンと名前がすぐに見られる ※他にもキャッシュできるものはあるが時間の都合で割愛 フォロー一覧、リポスト数、リポストされた投稿など 1:55 +15
Slide 9
Slide 9 text
TanStack Query 通信向けのキャッシュライブラリ 特徴 ● SWR戦略に基づく ● SolidJSに対応 1:15 +15
Slide 10
Slide 10 text
単純なキャッシュの仕組み 保存したデータはいつかは古くなり、再取得が必要 保存期間を決めておき、時間が経ったら破棄 有効 (データは新しいはず) 破棄 破棄までの期限 保存 1:30 +30 破棄すると、読み込みでユーザを待たせてしまう
Slide 11
Slide 11 text
SWR戦略 (stale-while-revalidate) 期限が切れてもすぐに削除せず一旦持ってるデータを表示 その裏で新しいデータを取得し、画面に表示する 有効 (データは新しいはず) 期限切れ (古いはずだが持っておく) 破棄 有効期限 破棄期限 保存 読み込みでユーザを待たせない 2:00 +30
Slide 12
Slide 12 text
通信の流れ クライアント リレー キャッシュ機構 Aさんのプロフィールがほしい Aさんのプロフィールです Aさんのプロフィールがほしい Aさんのプロフィールです 一旦今あるAさんのデータを返します Aさんのプロフィールがほしい Aさんのは保存してたのがあるよ Aさんのプロフィールがほしい stale Aさんのプロフィールがほしい 新しいAさんのプロフィールです 有効 期限切れ Aさんのプロフィールです 3:00 +60
Slide 13
Slide 13 text
TanStack Queryを使う上での課題 Promise前提 nostr-toolsのコールバックスタイルから変換が必要 4:00 +10
Slide 14
Slide 14 text
イベントのPromise化 まずは単純に一件だけのキャッシュに対応 プロフィール1件、リポストされたイベント1件 など ※nostr-toolsを使っています 4:10 +20
Slide 15
Slide 15 text
複数イベントの場合 更新があるたびにキャッシュを更新 割とゴリ押しな実装… 4:30 +30
Slide 16
Slide 16 text
バッチ化 5:00
Slide 17
Slide 17 text
単純に購読すると クライアント リレー Bさんのプロフィールがほしい Cさんのプロフィールがほしい Aさんのプロフィールがほしい Dさんのプロフィールがほしい Eさんのプロフィールがほしい そんなにリクエストしないで! (イベントEの取得失敗) 5:00 +10
Slide 18
Slide 18 text
動機 一部のリレーは購読数の制限がある (おそらく負荷軽減のため) 制限回避のために 購読数を少なく保ちたい 5:10 +10
Slide 19
Slide 19 text
バッチ化 複数の購読(REQ)を一つの購読にまとめる仕組み kinds: [0] authors: ["8234…e6a2"] kinds: [0] authors: ["3bf0…459d"] kinds: [0] authors: [ "8234…e6a2", "3bf0…459d" ] プロフィールの問い合わせを統合する例 5:20 +20
Slide 20
Slide 20 text
バッチ化 クライアント リレー バッチ化機構 Aさんのプロフィールがほしい Bさんのプロフィールがほしい Cさんのプロフィールがほしい まとめてA,B,Cのプロフィールがほしい Aさんのプロフィールです 3秒 Aさんのプロフィールです Bさんのプロフィールです Cさんのプロフィールです 3つのリクエストを1つにまとめられた Bさんのプロフィールです Cさんのプロフィールです レスポンスの振り分け 5:40 +60
Slide 21
Slide 21 text
レスポンスの振り分け kind: 0 pubkey: "8234…e6a2" content: {"name":"jack"} kind: 0 pubkey: "3bf0…459d" content: {"name":"fiatjaf"} 公開鍵 resolver "8234…e6a2" () => { … } "3bf0…459d" () => { … } Promise Promise ※new Promise((resolve) => …) の resolve関数をMapに保存しておく 公開鍵等のIDに基づいてPromiseをfullfillする 6:40 +60
Slide 22
Slide 22 text
詳しく知りたい人は https://gist.github.com/syusui-s/745a2b507744 073f9009c94222ad78fc 7:40 +10
Slide 23
Slide 23 text
最後に キャッシュとバッチ化で効率よく通信できる 今後の展望 - 楽観的mutation - プロフィール変更、リポスト、リアクションを即座にキャッシュに反映する - タイムラインの情報を拾ってキャッシュに乗せておく - 投機的キャッシュ - 投稿を投機的にキャッシュに乗せて、リポスト等の表示を効率化する - InfiniteQueryによるタイムライン自体のキャッシュ - いつかこの辺に対応したクライアントライブラリを作りたい…
Slide 24
Slide 24 text
おまけ: 発表で話せなかったところ
Slide 25
Slide 25 text
プロフィールのキャッシュ時間の工夫 staleTime: 5分 名前やアイコンがすこし 古くてもあまり問題ない cacheTime: 1日 よくTLに居る人を キャッシュするように 3:00 +30
Slide 26
Slide 26 text
プロフィールのキャッシュ時間の工夫 staleTime: 4時間 投稿は編集できないので 期限切れにしなくてOK cacheTime: 4時間 時間が経ったらリポストは されないので4時間程度で ■■さんがリポスト ●●さんがリポスト