Mastodon 源码拆解

一条状态从浏览器进入 Rails,写入 PostgreSQL,经过 Sidekiq 分发到本地 Feed 与远端 Inbox,再由 Redis 推到 WebSocket 和 React UI——这条链路就是读懂 Mastodon 的主线。

这份拆解回答什么

参考 refs/dg-ai-notes 对 Pi-Agent 的写法,本教程每章都按四个问题展开:

  1. 是什么:先建立概念和边界,不急着跳进文件。
  2. 怎么做:沿真实调用链定位 class、service、worker、serializer 和前端 action。
  3. 为什么这样做:解释一致性、吞吐、安全性和联邦兼容之间的取舍。
  4. 从哪里继续读:列出源码入口、实验路径和容易踩坑的位置。

阅读地图

flowchart LR
  A[浏览器 / 第三方客户端] --> B[Rails Web]
  B --> C[(PostgreSQL)]
  B --> D[Sidekiq]
  D --> C
  D --> E[ActivityPub HTTP]
  B --> F[(Redis)]
  D --> F
  F --> G[Node Streaming]
  G --> H[WebSocket / SSE]
  H --> A
  B --> I[React + Redux + Vite]
  I --> A

先建立一张“系统心智模型”

Mastodon 不是一个只返回 JSON 的 Rails API。它是由多个角色共同完成一次用户动作的分布式系统:

角色主要职责关键源码目录
Rails Web页面、REST API、OAuth、入站 ActivityPubapp/controllers, config/routes
Domain Service发帖、关注、通知、删除、联邦处理app/services
PostgreSQL事实数据、关系、约束、迁移app/models, db/migrate
Sidekiq延迟、重试、批量 fan-out、远端投递app/workers, config/initializers/sidekiq.rb
RedisFeed、缓存、锁、Pub/Sub、速率限制app/lib, streaming/redis.js
Streaming将 Redis 事件转成 WebSocket/SSEstreaming/index.js
React时间线、通知、编辑器、管理界面app/javascript/mastodon

重要事实与范围

本文档基于工作区中的 mastodon-main 快照。快照的 docker-compose.yml 使用 v4.6.4 镜像,前端 package.json 要求 Node.js 22+;因此文中的源码路径以该快照为准,不能把所有结论直接当成上游最新 main 的 API 保证。

从规模上看,快照包含约 248 个模型、338 个控制器、99 个 service、118 个 worker 和 531 个数据库迁移文件。数字用于帮助读者理解复杂度,不是运行时指标。

推荐阅读顺序

第一遍:只看主链路

第 1 章第 3 章第 4 章第 6 章。这条路线能解释“点发送之后发生了什么”。

第二遍:理解网络与可靠性

第 2 章第 5 章第 8 章第 9 章。这条路线解释数据为何这样建模、远端为何需要重试、权限为何不能只写在 Controller 中。

第三遍:准备改代码

第 7 章第 10 章,然后回到具体的 service、worker 和对应 spec 做小范围实验。

一次发帖的全景追踪

POST /api/v1/statuses
  └─ Api::V1::StatusesController#create
      └─ PostStatusService#call
          ├─ 校验媒体、敏感标记、可见性、提及和引用
          ├─ 事务写入 Status / Mention / MediaAttachment 关系
          └─ postprocess_status!
              ├─ ProcessHashtagsService
              ├─ LinkCrawlWorker
              ├─ DistributionWorker
              └─ ActivityPub::DistributionWorker

DistributionWorker
  ├─ FanOutOnWriteService → Redis Feed + FeedInsertWorker
  ├─ NotifyService → LocalNotificationWorker / PushUpdateWorker
  └─ ActivityPub::DeliveryWorker → 远端 inbox

Redis Pub/Sub
  └─ streaming/index.js → WebSocket → React timeline reducer

接下来从进程拓扑开始。