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
1.8k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Pawoo(Mastodon)が動く仕組み
pixiv SUMMER BOOT CAMP 2017 講義資料
abcang
September 26, 2017
More Decks by abcang
See All by abcang
カスタマイズしたMastodonを本家に追従するときのコツ
abcang
0
1.4k
Other Decks in Technology
See All in Technology
【CEDEC2026】専門性の高いデフォルメチームが挑んだ人材育成戦略 〜Cygames Academiaの企画から実施まで〜
cygames
PRO
0
610
Contract One Engineering Unit 紹介資料
sansan33
PRO
0
19k
グローバル基準のSREは、運用現場でどう機能したか:成熟度アセスメントの実践 / SRE NEXT 2026
sorawatanabe
0
230
FPGAが実現する遠方宇宙の高空間分解能天体撮影 -大型地上望遠鏡の視力を補正する「補償光学」とは?-
komei_mt
0
240
LanceDB入門
mocobeta
7
510
PLATEAU で バーチャル花火大会
tatsuya1970
0
160
生成 AI の基礎 〜 サンプル実装で学ぶ基本原理
enakai00
7
4.4k
20分でわかるセキュアAPI
nwiizo
2
270
Bill One 開発エンジニア 紹介資料
sansan33
PRO
7
19k
オートロックマンションなのに、各部屋は施錠なし!? 攻撃者が組織内ネットワークで大暴れする理由 / The Front Door Is Locked, but the Rooms Are Wide Open: Why Attackers Move Freely Inside Enterprise Networks
nttcom
1
5.1k
同じWAFが、攻撃の“形”は弾く── 正当な“形”の不正は通す
kuroneko13
0
200
え?フロントエンドエンジニアの ワイがインフラも!?
puku0x
1
580
Featured
See All Featured
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
200
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
200
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
350
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
220
Visualization
eitanlees
152
17k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.3k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
56k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.3k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
460
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
530
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
370
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
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周りは正しく動かなくなっていることが多い •
質問があればどうぞ!