Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Pawoo(Mastodon)が動く仕組み
Search
abcang
September 26, 2017
Technology
0
1.7k
Pawoo(Mastodon)が動く仕組み
pixiv SUMMER BOOT CAMP 2017 講義資料
abcang
September 26, 2017
Tweet
Share
More Decks by abcang
See All by abcang
カスタマイズしたMastodonを本家に追従するときのコツ
abcang
0
1.4k
Other Decks in Technology
See All in Technology
新規事業におけるGORM+SQLx併用アーキテクチャ
hacomono
PRO
0
430
Introduction to Bill One Development Engineer
sansan33
PRO
0
300
20251014_Pythonを実務で徹底的に使いこなした話
ippei0923
0
220
なぜAWSを活かしきれないのか?技術と組織への処方箋
nrinetcom
PRO
5
1k
FinOps について (ちょっと) 本気出して考えてみた
skmkzyk
0
170
ソフトウェアエンジニアの生成AI活用と、これから
lycorptech_jp
PRO
0
570
Digitization部 紹介資料
sansan33
PRO
1
5.6k
Node.js 2025: What's new and what's next
ruyadorno
0
640
OpenTelemetry が拡げる Gemini CLI の可観測性
phaya72
2
530
これがLambdaレス時代のChatOpsだ!実例で学ぶAmazon Q Developerカスタムアクション活用法
iwamot
PRO
8
1.1k
Liquid AI Hackathon Tokyo プレゼン資料
aratako
0
110
「改善」ってこれでいいんだっけ?
ukigmo_hiro
0
370
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
A Modern Web Designer's Workflow
chriscoyier
697
190k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
115
20k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Leading Effective Engineering Teams in the AI Era
addyosmani
7
500
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
22k
How to train your dragon (web standard)
notwaldorf
97
6.3k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.1k
Why You Should Never Use an ORM
jnunemaker
PRO
59
9.6k
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
Transcript
Pawoo(Mastodon)が 動く仕組み @abcang
自己紹介 • abcang(@abcang1015) ◦ 「あべちゃん」と呼ばれている • 17年度新卒 • Pawooの開発に携わってる •
Mastodonのコントリビュートもしてる
今日話すこと • MastodonとPawoo • Masotodonの構成 ◦ ディレクトリ構成や役割 ◦ Mastodonで使われているプロトコル •
実際にどうやってインスタンス間で通信しているか ◦ フォローしたときの流れ ◦ トゥートしたときの流れ
MastodonとPawoo • Mastodon ◦ 自由でオープンソースなソーシャルネットワーク ▪ Twitterと同じマイクロブログ ◦ 誰でもMastodonインスタンスを立てることができる •
Pawoo ◦ Mastodonインスタンスの一つ ◦ Mastodonをベースにして拡張している ▪ pixiv連携や自動消滅トゥート、メディアタイムラインなどなど
Mastodonの構成 nginx Rails Node.js Sidekiq Mastodonの本体部分 (APIの提供など) トゥートや通知の ストリーミング配信 トゥートの配信処理
などの非同期処理 PostgreSQL Redis リバースプロキシ
サーバサイド(Ruby on Rails) • webpackerを導入している ◦ ReactなどのJavaScriptのパッケージも使用している • 非同期処理が非常に多い ◦
インスタンス内の処理 ▪ トゥートをTLに反映、通知の送信、メールの送信、ストリーミング配信 ◦ インスタンス間の処理 ▪ トゥートの送受信、フォロー、通知の送信
ディレクトリ構造 通常のJavaScriptファイルapp/assets/javascriptsに配置するが、 webpackerでバンドルするファイルは app/javascriptに配置する ワーカークラス(約50ファイル) Sidekiqを使用した非同期処理を記述 サービスクラス(約50ファイル) 複数のモデルの操作や外部との通信などの複雑な処理を記述
サーバサイド(Node.js) • トゥートや通知のストリーミングAPIを提供 ◦ /api/v1/streaming/ • 500行ぐらいの1つのファイルで構成されている ◦ streaming/index.js •
やっていること ◦ リクエスト時に付与されたtokenを使って認証処理 ◦ redisのチャンネルを購読して、受け取ったデータを返す
Mastodonのフロントエンド • タイムラインのページはSPA ◦ ReactとReduxが使われている • webpackerを使ってファイルをバンドル ◦ JavaScriptだけでなくscssや画像もバンドル ◦
mastodon: JavaScriptのモジュール ▪ ReactやReduxでよくある構成になってる ◦ packs: エントリーポイント ▪ ビルドの起点となるファイルがある ▪ mastodonディレクトリのファイルをimport
app/javascript/mastodon コンポーネントを機能単位でまとめている。 機能ごとのディレクトリがあり、 それぞれの中にcomponentやcontainersがある。 翻訳ファイル ReactやReduxを使用したときの 一般的なディレクトリ構成
Mastodonで使われているプロトコル • OStatus ◦ 分散SNSを実現するためのプロトコル ▪ インスタンス間のフォローや投稿の配信の方法を決めている ◦ PubSubHubbub、Activity Streams、Webfinger、Salmonなどの
プロトコルを組み合わせて実現している • ActivityPub ◦ 分散SNSを実現するためのプロトコル ◦ データの形式にActivity Streamsを採用している ◦ Mastodon v1.6.0から対応 ◦ (今回は話しません)
OStatusで使用されているプロトコル • PubSubHubbub ◦ リアルタイムに更新通知を配信するためのプロトコル • Activity Streams ◦ フォローや投稿を表現できるようにAtomを拡張したフォーマット
• Webfinger ◦ アカウントの情報を検出するプロトコル • Salmon ◦ 発信元のサーバーに返信を反映させるためのプロトコル
実際にどうやって インスタンス間で通信しているか
フォローしたときの流れ 1. /api/v1/accounts/:id/follow にリクエストを送る 2. Api::V1::FollowsController#createが実行 ◦ FollowService.new.call(current_user.account, target_uri) 3.
FollowServiceでフォロー処理を行う
FollowService 1. アカウントの情報を取得 ◦ ResolveRemoteAccountService ◦ リモートのユーザーの場合はWebFingerを使って取得 2. フォロー情報を作成 ◦
account.follow!(target_account) 3. リモートユーザーかつ購読していない場合は購読を開始 ◦ Pubsubhubbub::SubscribeWorkerを実行 4. フォローを通知(NotifyService または NotificationWorker) 5. フォローした人のトゥートをホームTLに反映 ◦ MergeWorkerを実行
PubSubHubbubによる購読 • Pubsubhubbub::SubscribeWorker ◦ SubscribeServiceを実行 ◦ 自分のインスタンスの情報を相手のインスタンスに伝える インスタンスA インスタンスB インスタンスBの
Xさんを購読したい インスタンスAにインスタンスBのXさんのアカウントを作成しました トゥートしたら/api/subscriptions/1に送ってください POST /api/push
トゥートしたときの流れ nginx Rails Node.js Sidekiq /api/v1/statuses { in_reply_to_id: null, //
リプライ先のid media_ids: [], // 添付するメディアのid sensitive: false, // NSFWの設定 spoiler_text: "", // Content Warningの設定 status: "ぱうー", // トゥート内容 visibility: "public", // 公開範囲 } PostgreSQL Redis トゥート! Api::V1::StatusesController#create が呼び出される PostStatusServiceを呼び出して トゥートの送信処理を行う
PostStatusServiceの処理 nginx Rails Node.js Sidekiq PostgreSQL Redis 1. トゥートの作成 2.
メディアの紐付け 3. ハッシュタグの紐付け(ProcessHashtagsService) 4. メンションの生成(ProcessMentionsService) 5. PreviewCardの作成(LinkCrawlWorker) 6. トゥートの配信(DistributionWorker) 7. トゥートを他のインスタンスに配信 (Pubsubhubbub::DistributionWorker) 1,2,3,4でDBに書き込み 5,6,7でSidekiqのジョブを Redisに積む
PreviewCardの作成(LinkCrawlWorker) • PreviewCard ◦ OGPやOEmbedを展開する機能 • LinkCrawlWorker ◦ FetchLinkCardServiceを実行 •
FetchLinkCardService ◦ トゥート内に含まれるURLにアクセスして情報を取得 ◦ 非同期で実行される
トゥートの配信(DistributionWorker) • DistributionWorker ◦ FanOutOnWriteServiceを実行するだけ • FanOutOnWriteService ◦ フォローワーの数だけFeedInsertWorkerを実行 ▪
トゥートをフォローワーのホームTLに挿入 ▪ トゥートをフォローワーにストリーミング配信する ▪ (Pawooでは何件かまとめて処理するように改良している) ◦ ローカルTL、連合TL、ハッシュタグTLにストリーミング配信する
• Redisのpub/subを利用 ◦ Sidekiqからストリーミングに流すデータをpublish ◦ Node.js側でsubscribeして、受け取ったデータをWebSocketで流す ストリーミング配信 nginx Rails Node.js
Sidekiq PostgreSQL Redis Redis.current.publish('timeline:public', @payload) redisClient.on('message', (channel, message) => { log.silly(`New message on channel ${channel}`); });
トゥートを他のインスタンスに配信 • Pubsubhubbub::DistributionWorker ◦ トゥートをActivityStreamsの形式に変換 ◦ 購読しているアカウントに配信 ▪ 実際の送信処理はPubsubhubbub::DeliveryWorkerで行う •
Pubsubhubbub::DeliveryWorker ◦ 実際にAtomを送信する ▪ /api/subscriptions/:id に送る ◦ 配信に失敗すると3回までリトライする ▪ インスタンスが落ちていた間のトゥートは、インスタンスが復活したあとに 再送信されない
トゥートの受信 • Api::SubscriptionsController#update ◦ トゥート(Atom)が送られてくると呼ばれる ◦ 署名を確認して問題なければProcessingWorkerを実行 • ProcessingWorker ◦
Atomを読み込んで、自身のインスタンスにトゥートを作成する ◦ 実際はProcessFeedServiceが処理する
ProcessFeedService • Atomを読んで、ActivityStreamsの種類を確認する ◦ 種類に応じてトゥートの作成や削除を行う • トゥートの作成はPostStatusServiceとほぼ同じ流れ 1. トゥートの作成 2.
メディアの紐付け 3. ハッシュタグの紐付け(ProcessHashtagsService) 4. メンションの生成 5. PreviewCardの作成(LinkCrawlWorker) 6. トゥートの配信(DistributionWorker)
まとめ • Mastodonの構成 ◦ RailsやNode.jsを使用している ◦ フロントはReactやReduxを使用している • トゥートしたときの流れ ◦
トゥートの作成は同期実行、トゥートの配信は非同期実行 ◦ Worker内でさらにWorkerを実行するため非同期処理が非常に多い
おまけ • Mastodonにコントリビュートするには ◦ トゥートの配信の仕組みをよく知らなくても大丈夫 ◦ 実際に自分で使っていると挙動がおかしいことに気づくことがある ▪ 特にJavaScript周りは正しく動かなくなっていることが多い •
質問があればどうぞ!