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
実践アプリケーション設計 ③ドメイン駆動設計
recruitengineers
PRO
3
210
Android Studio の 新しいAI機能を試してみよう / Try out the new AI features in Android Studio
yanzm
0
270
退屈なことはDevinにやらせよう〜〜Devin APIを使ったVisual Regression Testの自動追加〜
kawamataryo
3
670
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
30k
Yahoo!広告ビジネス基盤におけるバックエンド開発
lycorptech_jp
PRO
1
280
microCMS 最新リリース情報(microCMS Meetup 2025)
microcms
0
110
Understanding Go GC #coefl_go_jp
bengo4com
0
1.1k
JavaScript 研修
recruitengineers
PRO
3
180
ABEMAにおける 生成AI活用の現在地 / The Current Status of Generative AI at ABEMA
dekatotoro
0
660
Devinを使ったモバイルアプリ開発 / Mobile app development with Devin
yanzm
0
190
つくって納得、つかって実感! 大規模言語モデルことはじめ
recruitengineers
PRO
24
6.1k
イオン店舗一覧ページのパフォーマンスチューニング事例 / Performance tuning example for AEON store list page
aeonpeople
2
290
Featured
See All Featured
Designing for Performance
lara
610
69k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
183
54k
Six Lessons from altMBA
skipperchong
28
4k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Building Applications with DynamoDB
mza
96
6.6k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
The Language of Interfaces
destraynor
160
25k
Fireside Chat
paigeccino
39
3.6k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
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周りは正しく動かなくなっていることが多い •
質問があればどうぞ!