自建 Mastodon(长毛象)实例最常见的失败方式,不是服务器不够贵,而是把 Mastodon 当成普通 Web 应用去配机和排查。一个典型的误判是这样的:用户反馈「时间线刷不出来」「发出去的帖子对面看不到」,运维第一反应是去看 PostgreSQL 的负载,加内存、加 CPU、上只读副本,折腾一轮,问题纹丝不动。真实原因往往在 Sidekiq 队列里,或者在 Streaming 服务的长连接数量上,也可能只是一个从来没有主动设定过的远端媒体缓存保留天数。这篇文章面向准备在 2026 年自建联邦实例的团队、社区运营方和企业内部社交平台的负责人,把 Mastodon 拆成 Web(Puma)、Streaming、Sidekiq、关系数据库、缓存队列、媒体存储这六段流水线,逐段说明它消耗什么资源、规模变大之后表现为什么症状、以及在什么条件下应该做哪一种扩容动作。文章中的量化判断均基于机制推导与社区运维经验,标注(预估)的数字请以自身实例的监控数据为准。
Mastodon 不是单体服务,它在一台机器上运行着三组职责完全不同的进程。第一组是 Web 层,由 Puma 承载 Ruby on Rails,负责页面渲染、接口响应、授权校验以及绝大部分写操作的入口;它的负载和用户点击节奏相关,白天高夜里低,属于典型的请求驱动型负载。第二组是 Streaming 服务,由 Node.js 进程承载,负责通过 WebSocket 向在线用户的浏览器推送时间线更新、通知和私信;它几乎不消耗 CPU,但每一个在线客户端都会长期占住一条连接和相应的内存结构。第三组是 Sidekiq,负责所有异步作业:收件箱投递处理、外发联邦推送、媒体转码、头像处理、链接预览卡片抓取、通知合并、邮件外发以及定时维护。
这三层的「贵法」不一样:Puma 贵在 Ruby 进程本身的常驻内存和单请求延迟;Streaming 贵在并发连接数乘以每连接开销;Sidekiq 贵在并发线程数乘以作业本身的内存峰值,并且在队列堆积时持续占用队列后端的存储。把三者塞进同一台机器并没有错,很多中小实例就是这样跑的,问题出在「不知道谁在吃哪一份资源」,一旦失速就无从下手。把三类进程的指标分开采集,是自建实例最早应该做的一件事,成本极低,回报极高。
这里给一组可以直接使用的快速判断:页面打开慢但接口响应时间正常,多半是 Streaming 或静态资源的问题;发帖成功却在关注者的时间线里迟迟不出现,或者根本不出现,问题基本不在 Web 层,而在 Sidekiq 的某个队列;只有实时推送失效、手动刷新却能看到新内容,那就是 Streaming 服务本身没起来,或者被反向代理的超时配置切断了连接升级请求。这三种现象在不同机型上可以长得一模一样,但处置动作完全不同,判断错了就是白花钱。
这是 Mastodon 容量规划里被误解最多的一条。注册一万人的实例不一定比注册五百人的实例更耗内存,真正决定 Streaming 服务内存占用的是「同时在线并保持长连接的客户端数」。每一个正在浏览网页版时间线的用户、每一个挂着的第三方客户端、每一个打开了通知推送的移动端,都会在 Streaming 进程里维持一条连接和相应的订阅结构。一个注册一万、日活两三百的实例,和一个注册六百、日活三百的实例,在 Streaming 侧的压力是同一个量级。
同一份开销在缓存侧还会再出现一次。有过 Mastodon 运维经验的人知道,用户的时间线索引存放在 Redis 的有序集合里,按账号维度维护,条目数量有上限(通常为数百条,具体取值以实例版本配置为准)。这意味着这部分数据是随「活跃用户」而非「全部注册用户」增长的,沉默账号几乎不产生成本。把这个机制写进容量模型,内存的估算公式应该写成「活跃数乘以单用户索引」,而不是「注册数乘以单账号均摊」。两种算法在小规模时差别不大,活跃数过了几千就会分道扬镳。
另一个经常被忽略的连接成本来自反向代理和内核参数。长连接是你自己在维持的,反向代理一侧的并发连接上限、文件描述符上限、超时时间,都会直接决定同一台机器能承载多少同时在线用户。超时时间设得太短,用户会遇到「时间线不自动更新」;设得太长,大量已断开却未被回收的连接会占住处理槽位。这里有一个明确取舍:社区型小实例把超时放宽到几分钟量级,可以省掉频繁重连带来的抖动;面向大量浏览器的公开实例则应把超时收紧到数十秒量级,让客户端自己重连,避免连接资源被慢网络占死。
把 Sidekiq 讲清楚,是解决 Mastodon 大部分「玄学故障」的前提。Mastodon 把异步作业分布到多个队列:默认队列负责常规作业与通知周报一类任务;pull 队列专门处理收件箱,即远端实例按协议投递过来的活动内容数据;push 队列专门负责外发联邦推送,即把本实例用户的发帖、点赞、关注、转发投递到其他实例的收件箱;ingress 队列负责入站数据的后续处理;mailers 队列负责邮件外发;scheduler 队列负责周期任务。这六个队列的堆积点和处置方式是完全不同的。
队列一旦堆积,表现极具迷惑性。push 队列积压时,本地用户发帖成功、页面显示正常,但远端实例迟迟收不到,用户的描述会是「我发的帖子别人看不到」;pull 队列积压时,远端的新帖已经写进数据库却来不及处理,本地用户的时间线是一片死寂,描述就变成「关注的人的帖子刷不出来」。这两种描述的共同点是都听起来像数据库慢,实际上数据库可能完全空闲,因为根本没有请求进去。所以排查顺序必须固定:先看各队列长度,再看队列延迟,最后才轮到关系数据库。
Sidekiq 的并发配置有一个常被搞错的地方:进程的内存占用约等于「并发线程数乘以单作业内存峰值」,而不是「进程数乘以常量」。把线程数从五提到二十五,进程内存可能翻几倍,而 CPU 可能远没跑满,因为很多作业大部分时间花在等网络和等磁盘上。反过来,如果 CPU 已经长期在八成以上而队列仍在堆积,继续加线程只会让上下文切换和锁竞争恶化,这时候加核数或者横向加 Sidekiq 节点才是正解。判断依据就一条:看 CPU 是不是真的饱和了。
还有一个隐性陷阱:媒体处理类作业(视频转码、大图压缩)的内存峰值远高于普通任务,耗时可能是秒级到分钟级。如果把它们和普通通知作业混在同一个 Sidekiq 进程里,一个重任务会长期占住线程,轻任务只能在后面排着,表现出来就是「通知突然变慢了」。把默认队列和媒体相关作业拆到不同的 Sidekiq 进程,用不同并发数分别拉起,是中大规模实例的标准做法,代价只是多一份常驻内存,收益是任一类作业失控都不会连带拖垮另一类。
重试机制同样要看清楚。Sidekiq 默认会对失败作业做指数退避重试并带抖动,重试次数有默认上限,超限之后作业进入死信集合,不再自动执行。很多实例从来不看死信集合,于是「投递给某个特定远端实例永远失败」这件事被静默吞掉,用户只会觉得「和那个站互相关注了却互相看不见」。把队列面板挂到内网并定期查看重试集合与死信集合,属于每日巡检级别的基础动作,不是等到出故障才做的事。
联邦宇宙的数据流方向和普通网站相反。普通网站服务好自己的用户就结束了;联邦实例是「你关注的账号所在的每一个远端实例,都会主动往你的收件箱推数据」。协议里有一个对用户很友好的设计:投递给某个远端实例时,会发到该实例的共享收件箱并合并一次投递,所以同一个远端账号的公开帖不会因为你有十个本地用户关注就投递十次。这是减轻负担的一面,而真正造成放大的环节在别处。
第一个放大源是关系图谱的规模。你的实例关注了多少个远端账号、这些账号分布在多少个远端实例上、这些实例本身有多活跃,共同决定了入站写放大的基数。一个只有二十个本地用户但关注了数千个活跃远端账号的实例,收件箱写入量可以轻松超过一个三百人但几乎不与外站互动的团体实例。这里给一句明确结论:不要用本地用户数去估入站吞吐,要用「被关注的远端账号数乘以这些账号的平均发帖频率」去估。这两个数字相乘才是入站压力的真实坐标。
第二个放大源是转发。当本地用户转发一条远端帖子时,实例需要确保本地有这条远端对象的完整副本,若没有则需回源拉取。热门内容被大量账号转发时,拉取动作会重复发生,并连带拉取它的回复链、作者头像和媒体附件。这种读放大发生在默认队列里,表现形式是尖峰式的:平时很闲,某个热点事件一来队列突然拔高几倍,然后慢慢回落。对这类尖峰做容量规划没有意义,正确做法是给队列留出足够的吸收余量,让它在尖峰期慢慢消化而不是立刻压垮。
第三个放大源与相反的方向有关:订阅你账号的远端实例越多,你每发一条公开帖就要向越多的目标实例做一次投递。这条规律虽然直观,但它的运维意义常被低估。它意味着外发队列的长度是「本地发帖频率乘以订阅实例数量」的函数,而远端目标里有相当一部分会处于超时、关站、证书过期或已把你屏蔽的状态。这些无效目标会消耗同样的投递资源,所以定期清理长期失效的目标,是把队列容量还给有效投递的直接手段。
如果说前两个放大源还可以通过控制关注范围缓解,中继站(Relay)则是一个单点就能改变全局的选择。中继站会把参与实例的全部公开帖子向所有订阅方广播,订阅一个中继意味着你的收件箱要接收全联邦相当比例的公开流量,无论你的本地用户是否关心这些账号。这些数据会完整写入你的数据库、占用你的磁盘、消耗你的队列。
这里给出的取舍非常直接:资源有限的社区实例不要订阅任何中继站;确有兴趣和建议只订阅发布量可控、有明确主题过滤的小型中继,并且在订阅后立刻观察配额增长斜率与队列延迟的变化。订阅中继这件事一次点击就能完成,但它的成本是长期且持续的,而且一旦积累了大量历史数据,取消订阅之后的清理工作反而更麻烦。
与之配套的是「限制联邦规模」这一类措施,它们应当被视为常规运维工具而不是极端手段:限制远端媒体的缓存天数、清理长期未被本地用户交互的远端账号数据、对单个账号的关注上限做出引导、以及在必要时用域名黑名单限制对已知失效站点的高频投递。这几项措施分别作用于磁盘、数据库体积、队列入站与队列出站的四个不同位置,组合使用可以在不增加任何硬件的前提下把实例的负载曲线压平。
外发投递是自建实例里最依赖外部环境的一段。你要把自己的帖子推向几百上千个远端实例,每个目标的响应速度、可用性、防护策略都不一样。标准行为是:投递失败后进入退避重试,退避间隔逐步拉长并带抖动,重试次数耗尽后进死信。问题在于,只要有一批远端实例持续不可用,外发队列就会被大量重试作业反复占据,而新产生的帖子投递只能排在后面,于是「面向大部分站点的正常投递」被少数几个坏目标拖慢。
这里最容易自伤的是域名与证书。联邦协议高度依赖 HTTPS 与请求签名:域名解析要稳定,证书要在到期前自动续期,反向代理要正确传递原始的主机名和请求头,否则签名校验会失败。一个常见的故障链条是这样的:证书自动续期失败或代理重载失败,实例在自己的浏览器里看起来正常(浏览器可能缓存了旧的证书链),但远端实例在做 TLS 握手或签名校验时报错,于是外发投递批量失败。这类故障的定位方法很简单却总被跳过:从外部网络探测自己的 HTTPS 端点,而不是在本机上自己访问自己。
反向代理配置也会直接影响投递成功率。WebSocket 路径必须允许协议升级;签名请求体不能被截断或改写;过大的请求体如果触发了代理侧的体积限制,会直接导致投递失败。这些问题都不是靠加机器能解决的,属于配置层的一次性工程,做对了之后长期免维护,做错了则会以「偶尔投递失败」的形式折磨你很久。
运维上的取舍也很明确:如果队列里反复出现针对少数几个域名的投递失败,与其无限期重试,不如接受「对方已经关站或已屏蔽你」这个现实,及时在队列面板里手动清除这批作业,或者通过域名限制减少对失效站点的重试频率,把队列容量留给有效目标。把重试次数调成无限大不是耐心,是浪费,而且浪费的是所有本地用户的发帖体验。
如果说 Sidekiq 是流量的入口,关系数据库是所有数据的终点。增长最快的表通常是帖子表(存放本地发帖以及从远端拉取的全部公开帖)、话题标签关联表、私信会话表、通知记录表,以及关注关系相关的两张表。它们的共同特征是随「入驻到本实例的全部对象」增长,而不是随本地用户增长——那些你从未主动关注、但因为同站别人关注而从远端拉来的帖子,同样占据着这里的每一行。
压力主要来自两类查询。第一类是时间线读取:查询某个用户的主时间线需要做按时间倒序的筛选与联表,涉及被关注账号集合、可见性判断、屏蔽与静默规则的过滤。第二类是通知查询与历史清理:通知表写多读少但清理成本高,长期不清会导致自动清理任务的压力持续累积。在这方面,固态盘的随机读写能力比 CPU 主频重要得多,这也是为什么不建议在机械盘或读写受限的存储上跑中型以上实例——换成 NVMe 带来的提升,往往比把 CPU 换高一档明显得多。
定期清理属于常规运维,不是可选的性能优化项。清理超出保留期的远端帖子、清理长时间未被本地用户交互的远端账号数据、清理过期的链接预览卡片、清理没有被引用的孤立媒体文件,这些维护动作在社区版本里都有标准命令,务必排进定时任务。这里给一个具体的取舍:保留天数应该按磁盘预算倒推,而不是拍脑袋设一个「永久保留」。保留三天、七天、十四天,磁盘占用完全是三个量级,而用户体验的差异往往只在考古时能否看到很久以前的历史帖这一处。
数据库连接是 Mastodon 里最容易「悄悄打满」的资源。每一个 Puma 工作进程的每个线程、每一个 Sidekiq 的每个线程,都可能同时需要一条数据库连接。这个数字必须在配置里写成同一个口径:Web 侧的最大线程数乘以进程数,加上 Sidekiq 的总并发线程数,再加上应用自身保留的连接,最后得到的总量,不能超过数据库侧连接上限所预留的安全余量。
连接池配错的症状非常有辨识度:大量请求在等待可用连接而超时,应用层报的是连接池耗尽,而数据库本身的 CPU 和磁盘都很闲。这种时候加内存、加 CPU、甚至加只读副本都无效,唯一正确的动作是重新对齐并发数与连接池。「连不上比慢更致命」这句话在 Mastodon 上尤其成立:数据库一旦因为连接数打满而拒绝新连接,Sidekiq 会批量失败并进入重试风暴,Web 侧返回错误页,Streaming 侧因为拿不到鉴权数据而掉线,故障面会从一个点迅速扩散到整站。
具体的对齐方法是这样的:先算出 Web 侧的并发上限,即进程数乘以每进程线程数;再算出 Sidekiq 的总并发,即进程数乘以每进程线程数;两者相加后加上一个操作余量,把连接池参数设为不小于这个总和的值,同时确保数据库侧的连接上限高于「连接池参数乘以总进程数」之后再留出管理连接。如果两者差距不够,可以把 Sidekiq 拆成多个低并发进程而不是一个高并发进程——总并发相同,但连接池可以按需分别设置,管理起来更清楚,出问题时也更容易隔离。
媒体存储是自建 Mastodon 磁盘消耗的绝对大头,并且它的构成常常被低估。磁盘上的媒体分两类:第一类是本实例用户自己上传的图片、视频、头像与横幅,这部分增长和用户行为线性相关,可控、可预测,也可以通过调整上传尺寸上限主动压缩;第二类是从远端缓存下来的媒体,即联邦流转过程中,你的实例为了向本地用户展示远端内容,会把远端账号的附件拉到本地保存一份。第二类才是真正的容量变量,它几乎不受你自己的用户行为控制。
这类远端缓存的增长速率取决于前面讲过的入站写放大:你关注了多少远端账号、这些账号发图发视频的频率、有没有订阅中继站、以及你是不是保留了很多高质量的视频内容。一个订阅了中继站又没有设置缓存清理动作的实例,磁盘增长曲线会陡到让人措手不及,很多实例都是等到磁盘逼近上限才第一次认真看一眼占用构成。所以本文要强调的核心参数只有一个:远端媒体缓存的保留天数必须主动设定。这个参数在很多部署里默认是「不清理」,或者根本没有定时任务去执行清理,于是磁盘就一直涨。
清理动作必须做成定时任务而不是人工想起才做:按天数清理远端缓存的媒体、清理没有被任何数据对象引用的孤立文件、清理过期的链接预览卡片。这三件事对应不同的数据表和存储目录,缺任何一个都可能出现「数据库里已经没有这条记录,但文件还躺在磁盘上」的情况。对于日增数十 GB 量级(预估)的中型实例,把这套任务设为每日执行一次并配合磁盘增长斜率的监控,比任何一次临时扩容都划算。
再给一个具体的取舍:如果必须在「降低视频转码质量」和「缩短远端缓存周期」之间选一个来省磁盘,通常优先选后者。转码质量影响的是本地用户自己上传内容的观感,属于可以直接被感知到的体验损耗;而远端缓存周期影响的是很久以后回溯历史内容的完整性,绝大多数活跃用户对三十天以上的远端缓存被清理是没有感知的。换句话说,牺牲看不见的部分,保住看得见的部分。
把媒体从本地磁盘迁到对象存储(兼容 S3 协议的服务或自建的对象存储网关),是 Mastodon 扩容路径上标准的一步,但它不是越早做越好。触发条件应该看三个信号:一是本地磁盘增长斜率已经无法在预算内线性扩容,扩容一次顶不了多久;二是开始需要多台 Web 节点做横向扩展,而多个节点之间无法共享本地媒体目录;三是备份窗口被庞大的媒体目录拖长,导致数据库本身的备份策略被迫让步。三个信号满足任意两个,就值得动这一步了。
迁移之前要明白代价:对象存储解决了容量和多节点共享问题,但引入了每次读写的网络往返与按请求计费的可能(具体计费口径公开渠道差异较大,以实时报价为准),并且需要在对象存储侧额外维护生命周期规则。对于只有一个 Web 节点、媒体总量还在单盘可接受范围内的实例,本地 NVMe 的读写延迟优势非常实在,贸然上对象存储反而得不偿失。这是一个明确的「这种情况先别做」。
迁移执行层面有几个必须注意的点:媒体目录要与数据库里的记录保持一致,迁移过程安排在流量低谷分批进行;如果在前端保留了反向代理层,要考虑对热点媒体加一层缓存,否则对象存储的延迟会被放大到用户可感知的程度;对象存储的桶权限、跨域设置和证书链也要和现有图床行为对齐。迁移完成后的验收标准很朴素:随机抽取老帖子的贴图能否正常加载、新上传能否落盘成功、两种来源的媒体是否在同一套地址规则下保持一致。
Redis 在 Mastodon 里承担双重身份:一方面它是 Rails 的缓存后端与时间线索引存储,另一方面它是 Sidekiq 的队列存储。这两种身份对内存的要求完全不同,把它只当成「缓存」来配内存,是很多实例在生产环境突然失联的原因。缓存部分的内存可以被淘汰策略回收(前提是你配置了合适的上限和策略),但队列作业的内存不能被随意淘汰——队列里的作业一旦被内存淘汰机制清掉,就是永久丢失,不会重来,也不会有任何人收到通知。
队列内存的量级由「队列深度乘以单作业体积」决定。普通作业很小,但涉及推送数据的作业、包含较大结构的作业会明显更大,而联邦推送涉及的目标实例列表越长,单个作业的体积越大。也就是说,队列内存不只是作业个数的问题,同时也是每个作业有多大、以及有多少个目标要投递的问题。估算时应该留出明确的余量,而不是按平时的队列长度来拍脑袋。
还有一个保护动作值得写进运维规范:为缓存队列服务设置明确的内存上限与合适的淘汰策略,并让它运行在不与其他服务争抢内存的环境里。如果它和关系数据库挤在同一台机器上争夺内存,一旦触发系统的内存回收流程,被优先杀掉的很可能是它,随之而来的是队列作业大面积丢失与 Web 侧缓存雪崩。这种情况下数据库有可能还活着,但整个实例已经不可用了——这也是「单机部署要预留足够内存余量」这条建议的真正由来。
把前面的机制串起来,可以给出一份明确的取舍清单。第一种情形,队列在增长但 CPU 没有饱和:优先加 Sidekiq 的线程数或增加进程数,同时检查是不是有重作业阻塞了轻作业,必要时拆分队列进程池。第二种情形,CPU 已经持续饱和且队列仍在增长:优先加核数或横向增加队列处理节点,单纯加线程会加重竞争。第三种情形,作业失败率高且集中在特定域名:这是环境问题,加资源无效,应该检查证书、反向代理与目标可达性,并在必要时清理这批重试。
第二组取舍发生在内存侧。内存吃紧但 CPU 有余,且在线人数多:先限制 Streaming 的并发规模或调低反向代理的长连接超时,再考虑加内存。如果是缓存队列服务吃紧,则要看是队列深度问题(那就回到 Sidekiq 那一层解决),还是时间线索引随活跃用户自然增长(那就按活跃用户重新估算内存)。很多时候「限制规模」比「加机器」更有效,也更省钱,尤其当增长来自订阅了不该订阅的中继站时。
第三组取舍发生在磁盘侧。磁盘吃紧时不要立刻想着扩容存储,正确的顺序是:先设定远端媒体缓存的保留天数,再清理孤立文件与过期预览卡片,最后才评估是否需要迁移到对象存储,这一步要看自身的成本承受力,不应照搬他人做法。再强调一次:保留天数这个参数不设就等于不清理,磁盘一定会涨到让你被动的地步。这一组动作在绝大多数情况下都能在数小时内把磁盘增长斜率降下来,是资源有限时最应该优先尝试的路径。至于「把六段流水线全部塞进一台机器」与「逐步拆分」之间的选择,关键看六者之间是否存在资源争抢,而不是看节点数量好不好看。
单机部署的适用范围比你想象的宽。入门与中等偏小规模的社区实例——活跃用户在数千以内、峰值同时在线数在这个量级之下、本地用户之外的关注图谱有限、没有订阅中继站——在选择了合适的处理器、充裕的内存和本地 NVMe 存储之后,是可以长期平稳运行的。这个阶段把六段流水线放在一台机器上,既减少了内网往返,也免去了分布式带来的额外运维,是完全合理的决策,不必为了架构上的好看而提前拆分。
分界线出现在几个具体信号上:一是关系数据库的读写延迟长期处在高位,且通过清理数据与维护索引已无法改善;二是 Web 与队列作业争抢内存,导致其中一方频繁被系统回收;三是确实需要高可用能力,而单机上的主备并不具备意义;四是需要多台 Web 节点横向扩展,此时数据库、缓存队列、媒体存储必须先完成共享化改造,其中媒体存储要先走到对象存储,否则多节点的媒体一致性无从谈起。
拆分的顺序也有讲究,一般不推荐一步到位拆成多台。合理的路径是先独立数据库(收益最直接、风险最低),再独立缓存队列服务(改动小,但能隔离内存层面的连锁反应),最后才是把 Web 与作业处理拆到不同主机——最后这一步会引入内网延迟,而队列作业对内网的稳定性比较敏感,拆早了反而引入新的故障模式。每一步之间留出足够的观察周期,才能判断下一次到底该拆什么、以及拆完解决了什么。
下面这张表把六段流水线的消耗类型、规模变大后的表现和优先处置动作放在一起,用于排障时快速消除「从哪看起」的犹豫。表格内容为机制归纳与社区运维经验的综合整理,涉及数值的判断均标注为预估或以实际环境为准,请勿直接照搬为自己的容量刻度。
| 组件 | 主要消耗 | 规模变大后的表现 | 优先扩容动作 | 备注 |
|---|---|---|---|---|
| Web(Puma) | 进程常驻内存、单请求处理延迟、数据库连接 | 页面与接口变慢,连接池耗尽时返回错误页 | 先对齐连接池与并发数,再横向增加 Web 节点 | 请求的昼夜波动最明显,适合预留弹性 |
| Streaming | 长连接数量乘以单连接开销 | 在线用户时间线不自动更新,手动刷新才有内容 | 控制并发规模、调整代理超时,必要时再加内存 | 按同时在线数估算,不按注册用户数估算 |
| Sidekiq 队列 | 线程并发乘以作业内存峰值、CPU 或网络等待 | 发帖别人看不到、关注的人刷不出来 | 按队列拆分进程后,再决定加线程还是加核数 | 故障第一现场,排查次序排在数据库之前 |
| PostgreSQL | 随机读写、连接数、帖子与通知表的体量 | 时间线读取变慢,自动清理任务压力累积 | 换更快的本地固态盘,再考虑独立部署 | 定期清理远端过期数据属常规运维动作 |
| Redis | 队列作业内存与时间线索引,含不可淘汰部分 | 作业丢失、缓存雪崩、队列大面积失败 | 设置内存上限与淘汰策略,按队列深度估算内存 | 既是缓存也是队列后端,不能只当缓存配置 |
| 媒体存储 | 远端缓存容量为主,本地上传为辅 | 磁盘增长斜率失控,备份窗口被拖长 | 先设缓存保留天数并清理孤立文件,再考虑对象存储 | 多 Web 节点时必须改造为共享对象存储 |
把机制讲清楚之后,落到配置口径就简单了,这里按谁、在哪里、做什么、为什么、怎么选这五点说明。谁适合自建:有内容自治诉求的企业社区、行业垂直讨论组、品牌对外的内容节点、开源项目与科研团体的自有交流平台,以及要求把用户数据留在自己可控范围内的产品线。在哪里部署:面向中文出海用户又看重国际连通的场景,可选择中国香港节点;面向东南亚用户的场景,可评估邻近区域节点;机房、带宽、地址数量与防护能力均以实时咨询结果为准。
做什么:跑 Mastodon 实例的六段流水线,包含 Web 层、实时推送层、异步作业层、关系数据库、缓存队列与媒体存储。为什么选租用而不是自建机房:联邦实例对公网连通质量、HTTPS 可达性、反向代理可控性的依赖极高,租用环境下的网络出口、地址稳定性与可扩展性是持续的正面因素;同时实例的磁盘增长斜率不可预测,可扩容性与介质可更换能力比一次性买断机型更重要。这两点决定了按租用来规划,比按采购来规划更适合大多数团队。
怎么选:先按活跃在线数估算实时推送与缓存队列的内存,按被关注的远端账号数乘以发帖频率估算队列并发与数据库写入压力,按远端媒体的缓存天数与平均附件体积估算磁盘;这三组数字出来之后再对机型,比按人数猜机型准得多。具体到配置建议:入门规模的社区实例优先选择核心数适中但内存充裕的机型,并把本地存储锁定为固态;中型实例在单机部署阶段就应为可能独立的数据库预留读写余量;规模继续增长时,把队列处理拆分出来,并把媒体迁移到对象存储。
以上是基础取向,具体机型、处理器型号、内存容量、磁盘组成、带宽与防护规格均需询价,不同机房公开渠道差异较大,以实时报价为准。一万网络深耕 19 年(成立于 2007 年),旗下天下数据与 idc10000.net 提供中国大陆周边及海外多区域的服务器租用选项;自建 Mastodon 实例所需的操作系统环境、反向代理配置、证书签发与续期,以及后续的容灾与迁移方案,均可按要求交付。
本文的核对口径分为四组,建议在调整配置之前自行复核一遍。第一组是队列侧:缓存队列中默认队列、投递队列、收件箱队列、入站队列、邮件队列、定时任务队列的长度,以及重试集合与死信集合的内容;队列面板中的已处理数、失败数与忙碌线程数。第二组是数据库侧:慢查询日志里与时间线相关的语句,帖子表、标签关联表、通知表、会话表的行数与占用体积,以及连接池的使用率。
第三组是媒体侧:本实例自己上传的媒体与远端缓存媒体的分别占用体积,注意两者必须分开统计,否则无法判断增长来源;孤立文件数量、链接预览卡片数量、远端媒体缓存天数的当前取值,以及是否配置了定期清理任务。第四组是主机侧:实时推送进程的常驻内存、缓存队列服务的内存占用与淘汰策略、磁盘读写延迟、反向代理的活跃连接数与连接升级失败率。以上字段均可在自有实例上自行采集,本文不对无法验证的第三方数据下确定结论,涉及具体数值的判断已标注为预估或以实际环境为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品