Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(timeline): Optimizing for CDN Caching #834

Merged
merged 12 commits into from
Dec 21, 2024

Conversation

tar-bin
Copy link

@tar-bin tar-bin commented Dec 20, 2024

What

image (1)

こちらの実装を行った。

公開投稿(public, home)について

  • 通常ユーザーについてはchannelのidOnlyフラグをtrueで渡すため以下の動作をする
  • Websocket:note.id と idOnly フラグのみ返し、prependで /notes/:note.json を呼び出す
  • /notes/:note.json:Cache-Control: public を返し、CDNにキャッシュさせる

限定公開投稿(followers)について (※specifiedは基本的にTLに表示されないため今回の主な対象ではない)

  • Websocket:noteの情報をすべて返す(既存の実装と同等)

モデレーター権限をもつユーザーについて

  • モデレーターについてはchannelのidOnlyフラグをfalseで渡すため以下の動作をする
  • Websocket:noteの情報をすべて返す(既存の実装と同等)

Why

いままでWebsocketにてリアルタイムにノートのすべての情報を対象のユーザーすべてにブロードキャストしていた。つまり「ノートの投稿数 * ノートの情報量 * WSで購読しているユーザー数」分の通信量と処理負荷がサーバーにかかっていることになる。

これをIDのみ渡し実体の取得をCDNのキャッシュに委譲することでWebsocketでの通信量およびサーバー負荷を削減する。

TLでリアルタイムに取得する投稿は大部分がパブリックの投稿であるため、それなりの通信、処理負荷の削減が見込まれると考えられる。(サーバーの処理は「ノートの投稿数 * ID情報 * WSで購読しているユーザー数 + CDNにキャッシュされる前の最初の1回のリクエストへの応答)」になる)

ノートの実体についてはCDNでキャッシュすることで本体サーバーの処理をノートごとに1回にする。CDNにキャッシュされたあとは、当然ながらCDNのキャッシュから返却されるようになるため本体サーバーの(通信/処理)負荷にはならない。

上記の問題点として、限定公開投稿の権限管理をサーバー側でしているため限定公開投稿はCDNでキャッシュできないことである。
そちらの対策として、限定公開投稿はWebsocketで受け渡す方式とする(既存実装と同等)。
またCache-Controlを制御することで意図せずCDN側でキャッシュされることを防ぐ対策を行う。

またシステム管理者およびモデレーターに関しては、非公開ロールなどパブリックな投稿に加えて管理者向けの非公開の情報が必要となるケースがあるため、パブリックも含めてすべての投稿を従来通りWebsocketで受け渡す方式とする。

Additional info (optional)

・画像内にある「投稿削除時にCloudflare APIでパスのキャッシュをクリアする」は別トピックであるため本PRには含めない

・Cloudflareのキャッシュルールで以下の設定の追加が必要。
image

データ削減試算(ioのケース)

前提:
・平均的なノートのサイズを 1kB ぐらいと仮定する
・idのみの通信サイズは45 バイトなので、おおよそ20分の1ぐらいになるとする
・現在5000人がオンライン、デッキモードの利用を含め平均2TLを見ているとする。
・1投稿すると両TLにに表示される場合を考える。
・1日あたり30万投稿とする(チャートより)

対策前:
・1投稿がされると、5000人 * 2TL = 10000回Websocketで通信する
・1投稿あたり 1kB * 10000回 = 10MB
・1日あたり 10 MB * 300000投稿 = 3TB
・1か月あたり 3TB * 30 = 90TB

対策後:
・1投稿がされると、5000人 * 2TL = 10000回Websocketで通信する
・1投稿あたり 0.05kB * 10000+ 1kB * Edge ≒ 0.5MB (CDNのキャッシュのための通信量は誤差レベルなので無視する)
・1日あたり 0.5MB * 300000投稿 = 150GB
・1か月あたり 150GB * 30 = 4.5TB

結果:
・1か月あたり85.5TB分サーバー処理の削減(CDNでのキャッシュ活用)が見込めるかも
・平均的なノートのサイズ、オンライン数、一日当たりの投稿数、平均のTL数が増えればもっと増えます

Checklist

  • Read the contribution guide

  • Test working in a local environment

  • (If needed) Add story of storybook

  • (If needed) Update CHANGELOG.md

  • (If possible) Add tests

@tar-bin
Copy link
Author

tar-bin commented Dec 20, 2024

ちょっとテストの結果はコメントに追記します。

@tar-bin
Copy link
Author

tar-bin commented Dec 20, 2024

※Public/Homeについては通常ユーザーのいずれかがcf-cache-status:がHITすることを確認する
※モデレーターの/api/note/showの通信が発生せずWebsocketのみで表示できていることを確認する

通常ユーザー1
・local (HIT)
image
・social (HIT)
image
・global (HIT)
image
・home (HIT)
image
・followers (API通信なし、表示OK)
・channel (HIT)
image

通常ユーザー2
・local (MISS)
image
・social (MISS)
image
・global (MISS)
image
・home (MISS)
image
・followers (API通信なし、表示OK)
・channel (MISS)
image

モデレーター
・local (API通信なし、表示OK)
・home (API通信なし、表示OK)
・social (API通信なし、表示OK)
・global (API通信なし、表示OK)
・followers (API通信なし、表示OK)
・channel (API通信なし、表示OK)

🆗 パブリック投稿は/api/notes/showが呼ばれ、2回目以降はHITしている
🆗 限定投稿はWSでデータ取得できている
🆗 モデレーターはパブリックも限定投稿もWSでデータ取得出来ている

@tar-bin

This comment was marked as outdated.

@tar-bin
Copy link
Author

tar-bin commented Dec 21, 2024

Public/Home -> OK
image
image

Follower -> OK

Admin/Moderator -> OK

大丈夫そうです。

SanMurakami
SanMurakami previously approved these changes Dec 21, 2024
Copy link
Collaborator

@riku6460 riku6460 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WebSocket のメッセージの送信タイミングを適当に散らしてあげないとうまくキャッシュヒットしない予感(あるいは受け取り側で調整するか)

@tar-bin
Copy link
Author

tar-bin commented Dec 21, 2024

@riku6460

WebSocket のメッセージの送信タイミングを適当に散らしてあげないとうまくキャッシュヒットしない予感(あるいは受け取り側で調整するか)

こちらに関しては以前村上さんが検証ツールを作って試しましたが、CF側でいい感じにキャッシュヒットするように遅延してくれるみたいでした。

@riku6460
Copy link
Collaborator

@riku6460

WebSocket のメッセージの送信タイミングを適当に散らしてあげないとうまくキャッシュヒットしない予感(あるいは受け取り側で調整するか)

こちらに関しては以前村上さんが検証ツールを作って試しましたが、CF側でいい感じにキャッシュヒットするように遅延してくれるみたいでした。

一応調べてみましたがここにありましたね これなら問題なさそう
https://developers.cloudflare.com/cache/concepts/revalidation/#example-2

riku6460
riku6460 previously approved these changes Dec 21, 2024
@u1-liquid u1-liquid dismissed stale reviews from riku6460 and SanMurakami via 4a22a2e December 21, 2024 18:08
@u1-liquid u1-liquid changed the title Optimizing for Cloudflare Caching perf(timeline): Optimizing for CDN Caching Dec 21, 2024
@u1-liquid u1-liquid merged commit 4ecfae0 into MisskeyIO:io Dec 21, 2024
18 checks passed
kakkokari-gtyih pushed a commit to kakkokari-gtyih/misskey that referenced this pull request Dec 28, 2024
Co-authored-by: あわわわとーにゅ <17376330+u1-liquid@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants