引言
维护者倦怠不是个人情绪问题,而是开源生态的结构性风险。npm 上数以万计的包、PyPI 上的关键基础库、Linux 发行版里的底层组件,很大一部分由一到两个无偿志愿者在业余时间维护。一旦这个人累了、病了、或者干脆不干了,依赖它的成千上万个项目不会立刻崩溃,但会在下一次安全事件或兼容性升级时集体踩空——log4j 和 xz 事件都是这样发生的。
工程上真正的难点在于:可持续性没有单一的「正确指标」。加人、给钱、写文档、改治理、砍 scope,每一条都只解决一部分问题,而且措施之间会互相冲突(引入 co-maintainer 能提高 bus factor,也带来信任与协作成本)。更麻烦的是倦怠信号往往是滞后的:当你注意到维护者不再回复 issue 时,项目通常已经进入衰退期好几个月了。
本文从维护者与管理者双重视角出发,按「成因与信号 → 关键人风险 → 负担来源 → 分担轮换 → 资助分配 → 企业回馈 → 继任交接 → 体面归档 → 自评清单」的顺序展开,给出可操作的阈值、资金量级与清单条目。评估项目当前健康程度可以参考 项目健康度度量 ,判断有没有人能接棒则依赖 贡献者漏斗 是否通畅。
目录
- 倦怠的成因与早期信号
- bus factor 与关键人风险
- 维护负担的结构性来源
- 分担与轮换机制
- 资助渠道与资金分配
- 企业如何回馈上游
- 继任与交接
- 项目归档的体面做法
- 可持续性评估清单
- 权衡取舍
- 常见坑清单
- 小结
1. 倦怠的成因与早期信号
1.1 四类结构性成因
倦怠几乎从不来自「工作量大」本身,而来自四种结构错配:
- 无偿且无限责任:没人付钱,但生产环境出问题都来找你,且没有下班时间。
- 权责不对称:要你对质量负责,却不给你拒绝 feature、关闭 issue 的权力。
- 公开攻击:issue 里的人身攻击、社交媒体上的公开指责,把技术分歧升级为人身评价。
- 孤立无援:没有第二个人能替你分担,连请假都请不了——一停摆项目就死。
1.2 量化信号与阈值
关键是要在「人已经消失」之前识别信号。下面这些阈值可以直接量化监控:
| 信号 | 健康 | 预警 | 危险 |
|---|---|---|---|
| 新 issue 首次响应中位数 | < 3 天 | 3~14 天 | > 30 天 |
| 未关闭 issue 数 | 稳定或缓慢增长 | 3 个月翻倍 | > 500 且无人 triage |
| release 间隔 | 稳定 | 比历史中位数拉长 2 倍 | 超过 6 个月无 release |
| top 1 贡献者 commit 占比 | < 50% | 50~80% | > 80% |
| 维护者每月投入时长 | 与报酬匹配 | > 20h 且无报酬 | 明确表达过疲惫 |
| PR 平均合并时长 | < 7 天 | 7~30 天 | > 60 天或长期积压 |
1.3 软信号
硬指标之外还有一类更早的软信号,通常出现在公开互动里:release notes 从详实变成一行「routine release」;PR 评论从技术讨论退化为「LGTM, thanks」;维护者在 issue、博客或会议上说「我不想再维护这个了」。
最后一句是最高优先级信号——它几乎等同于离职预告,应当立即启动继任讨论,而不是等对方真的消失。更系统的健康度指标(响应时长、贡献者留存、发布节奏、bus factor)可对照 项目健康度度量 中的口径。
1.4 自动化采集
不必靠感觉判断,用 GitHub API 就能定期采集核心指标:
gh issue list --repo owner/repo --state open --limit 1000 --json number,createdAt --jq 'length' # 未关闭 issue 数
git log --since="90 days ago" --format='%an' | sort | uniq -c | sort -rn | head # 贡献者集中度
gh release list --repo owner/repo --limit 1 --json publishedAt --jq '.[0].publishedAt' # 最近 release 时间
把这几条跑进每周定时任务,超过阈值就给自己或团队发提醒——把「我是不是累了」变成「指标是不是超线了」,能显著降低自我否认导致的拖延。
2. bus factor 与关键人风险
2.1 三个可操作判据
bus factor(巴士因子)指「多少人被巴士撞了之后项目就瘫痪」。传统定义偏定性,工程上可操作化为三个具体判据:
1. 最近 12 个月的 commit / review 是否由 >= 2 个不同的人完成(且都不是机器人)
2. 是否有 >= 2 人持有 release / 发布凭据(npm token、PyPI token、签名密钥、CI secret)
3. 是否有 >= 2 人拥有 admin 权限(仓库、组织账号、域名、资金账户)
只要有一条是「否」,bus factor 就等于 1。bus factor = 1 的项目,无论代码多优雅,都是高危依赖。
2.2 log4j 的教训
log4j(CVE-2021-44228) 爆发时,log4j 主要由极少数志愿者维护,却被全球海量 Java 服务间接依赖。Log4Shell 让整个行业意识到:关键基础设施的维护者与它的影响力完全不成比例。事件直接推动了后续的基金会资助讨论、以及企业对「关键依赖清单」的盘点。
2.3 xz 的时间线
xz(CVE-2024-3094) 是更值得细读的案例,因为它不是技术漏洞而是治理漏洞:
| 阶段 | 时间 | 行为 |
|---|---|---|
| 潜伏 | 2021 起 | 攻击者 Jia Tan 提交小 patch,建立「热心贡献者」形象 |
| 施压 | 2022~2023 | 用多个马甲账号催促原维护者尽快合并、施压其他贡献者 |
| 索取权限 | 2023 | 逐步获得 commit / maintainer 权限 |
| 植入 | 2024 | 在构建脚本(tarball 内)植入后门,绕过源码审查 |
| 暴露 | 2024-03 | 被 Andres Freund 发现异常 SSH 性能,后门曝光 |
原维护者 Lasse Collin 长期倦怠、公开表达过想找接手人——这种「倦怠 + 渴望交接」的状态,恰恰是恶意接管最容易得手的地方。
2.4 权限提升必须走流程
xz 的教训不是「不要接受贡献者」,而是:权限提升必须走明确的治理流程(谁批准、考察期多长、review 门槛多高),而不能因为「我太累了,有人愿意干就给他吧」而放行。最低限度要求:新 maintainer 的提名需公开讨论、有考察期(如 6~12 个月)、且发布凭据的授予需至少一名现有维护者复核。
3. 维护负担的结构性来源
维护者的时间不是花在写新代码上,而是被四类结构性负担吃掉。
3.1 issue 洪水
一个中等流行的库每周新增 10~50 个 issue,其中大量是「怎么用」「报错看不懂」「求支持」。没有 triage 机制时,这些会直接涌向维护者。粗略估算:
| 每周 issue 数 | 每个平均处理时长 | 每周隐性成本 |
|---|---|---|
| 10 | 15 分钟 | 2.5 小时 |
| 30 | 15 分钟 | 7.5 小时 |
| 50 | 15 分钟 | 12.5 小时 |
单是「读一遍并回复」就能吃掉一个业余维护者大半的可支配时间。
3.2 安全报告
私密披露渠道(GitHub Security Advisory、security@ 邮箱)带来的是有 deadline 的紧急工作:评估、复现、写 patch、协调披露、发 CVE。完整处置流程见 漏洞响应流程
,但哪怕流程再熟,这仍是高压力、不可预期的时间黑洞——你无法「安排」一个 0day 在你有空的那周出现。
3.3 用户预期
免费项目被当成有 SLA 的商业产品:「这是 bug,请今天修」「我生产环境挂了,你负责」。开源许可证(MIT/Apache-2.0 等)并不承诺任何支持,但社会预期并不会读许可证。当项目被企业重度使用时,这种预期落差尤其伤人。
3.4 企业搭便车
大公司把开源当免费基础设施,用出问题时提 issue 催修,却既不回馈代码也不出钱。这种不对称是倦怠最深的来源之一:维护者感受到的不是「社区」,而是「一群不出钱的甲方」。而真正扎心的是——这些企业往往有能力出钱,只是没有把「上游可持续性」纳入成本模型。
4. 分担与轮换机制
对抗倦怠最直接的手段是把「一个人扛」变成「一群人分」,但要先定义清楚角色,否则权限一放就乱。
4.1 角色定义
| 角色 | 权限 | 典型职责 |
|---|---|---|
| Triager | 打标签、关重复 issue、请求补充信息 | 分流 issue 洪水 |
| Reviewer | review PR,不能合并 | 分担代码评审 |
| Committer | 合并 PR、写部分 release | 分担合并与发布 |
| Maintainer | admin、发布凭据、治理决策 | 方向与最终裁决 |
4.2 落地要点
- triage 权限优先下放:GitHub 的
triagerole 不需要写权限就能打标签、关闭 issue,风险最低、收益最大,适合作为新人的第一站。 - CODEOWNERS 明确归属:把目录映射到具体人(
.github/CODEOWNERS),避免「谁都能改 = 谁都不负责」。
* @maintainer-a
/pkg/core/ @maintainer-a @committer-b
/docs/ @docs-team
/.github/workflows/ @maintainer-a @maintainer-c
- 轮值而非永久 on-call:设每周/每两周的「值班维护者」,负责当周 issue 与 PR 分流,其余人可休息。
- 允许休假:明确写出「维护者可以休息 1~3 个月,期间由 X 代班」,并真的执行。很多倦怠源于「不敢停」。
4.3 轮值表示例
周次 值班维护者 备份 负责范围
W1 alice bob issue triage + PR review
W2 bob carol issue triage + PR review
W3 carol alice issue triage + PR review
W4 (全体休息) - 仅处理安全与阻塞性 bug
关键是备份列不能空,且值班范围要写明「只做分流,不承诺修复时间」。
4.4 晋级路径
引入 co-maintainer 本质上是在扩大贡献者漏斗的出口,前提是漏斗本身通畅——从 triager 到 reviewer 到 committer 的晋级路径要写清楚,判据可以是「完成 N 次有效 triage」「review M 个 PR 且无重大遗漏」。具体机制见 贡献者漏斗 与 社区运营 。
5. 资助渠道与资金分配
资金不能消除倦怠,但能买时间。
5.1 渠道对比
| 渠道 | 计费/费率 | 适合场景 | 特点 |
|---|---|---|---|
| GitHub Sponsors | 平台 0 手续费,仅支付通道费 | 个人维护者、小额月捐 | 集成好、可见度高 |
| Open Collective | 通常 6%~10% 平台费 | 需要透明账本的团队 | 财务公开、可报销支出 |
| Tidelift | 订阅分成(平台抽成后分给维护者) | 被企业依赖的库 | 企业付费、给维护者稳定收入 |
| 基金会(Apache/CNCF/LF 等) | 会费 + 捐赠,项目走治理流程 | 需要中立治理与法务的项目 | 提供法务、商标、资金托管 |
| 企业直接赞助 | 合同/一次性,无平台费 | 单一企业重度依赖 | 快,但可能附带条件 |
5.2 资金量级参考
用于校准预期(非承诺):个人维护者通过 Sponsors 常见月入 $50~$2000;一个被广泛依赖的库年收入可能 $5k~$100k;而要让一个人全职投入,通常需要 $100k+/年(含税与社保的地区差异很大)。换言之,靠零散赞助很难养活全职维护者,企业级订阅或基金会资助才是量级匹配的方案。
5.3 资金分配原则
资金应跟着劳动走而非跟着名气走——按 triage、review、发布、答疑的实际工时分配,而不是全给 commit 最多的那个人。否则会激励「刷 commit」而惩罚做脏活(分流 issue、写文档)的人,反而加速倦怠。
| 分配方式 | 效果 |
|---|---|
| 全给 top committer | 激励刷 commit,脏活无人做 |
| 按 commit 数 | 忽视 review / triage / 文档劳动 |
| 按实际工时(含非代码工作) | 公平,但需信任与记录 |
| 混合(基础津贴 + 工时补贴) | 兼顾稳定与公平,推荐 |
5.4 透明账本
若走 Open Collective 一类平台,把支出公开(服务器费、CI 费用、给维护者的津贴)能显著提升外部信任,也降低「钱到哪去了」的质疑。这是把资助从「个人恩惠」变成「可审计项目」的关键一步。
6. 企业如何回馈上游
企业是开源最大受益者,也最有能力改变维护者处境。
6.1 动作清单(按投入从小到大)
- upstream first:内部修复优先提 PR 到上游,而不是维护私有 patch。这是最低成本的善意,也避免私有 fork 越漂越远。
- 给时间:允许员工用工作时间的 10%~20% 做上游维护,并计入绩效,而不是当成「业余爱好」。
- 付费维护:与关键依赖的维护者签维护合同(常见 $10k~$50k/年),换取明确的响应承诺。这比自建替代品便宜得多。
- 直接捐赠:对无商业实体的个人维护者,走 Sponsors/Open Collective 月捐;对有基金会的项目,走基金会定向捐赠。
- 人力投入:指派工程师成为 upstream 的 reviewer/committer,实质提升对方的 bus factor。
6.2 维护合同要点
签付费维护合同时,写清楚这几条能避免后续扯皮:
1. 响应范围:安全漏洞 P0/P1 的响应时限(如 72 小时内确认)
2. 覆盖版本:只覆盖当前大版本还是含 LTS
3. 明确排除:新功能开发、定制化需求通常不在维护范围内
4. 交付形式:优先 patch 上游,而非私有分支
5. 终止条款:不续约时如何平滑过渡,避免维护者收入断崖
6.3 反模式
内部 fork + 长期不合并:企业以为获得了控制力,实际上承担了永久的 rebase 成本,还让上游失去本该得到的修复,最终两边都受损。另一种反模式是「只提 issue 不出人」——把上游当免费外包团队,长期看会加速关键依赖的维护者流失,反噬自身供应链。
7. 继任与交接
继任不是「离职时才想的事」,而是平时就要维护的资产。
7.1 可交接性的四要素
可交接性取决于四样东西是否写下来:
1. 流程文档:CONTRIBUTING.md(如何提交/评审)、RELEASING.md(如何发版)、
GOVERNANCE.md(谁做决策、如何投票、如何增减维护者)
2. 权限清单:仓库 admin、组织 owner、发布 token、签名密钥、CI secret、
域名/DNS、包管理器账号,各自谁持有
3. 上下文:为什么做这些设计决策(ADR / design doc),避免接手人重蹈覆辙
4. 关系:与下游用户、基金会、资助方的联系人
7.2 交接时的具体动作
- 给接班人至少两个持有发布凭据的人;
- 把原维护者标为 emeritus(荣誉退休)而非直接移除,保留其历史贡献的可见性;
- 发布一篇公开的交接公告,说明谁负责什么、从哪天起生效;
- 用一段「冷静期」并行运行:原维护者保留观察权限 1~3 个月,但不主动介入。
7.3 避免单点
避免单点是核心——域名续费、npm token、GPG 签名密钥、CI secret,任何一项只有一个人知道,都是一颗定时炸弹。建议把这些凭据纳入密码管理器或 secrets vault,并每季度做一次「接班人能否独立发版」的演练:让第二个人在不问原维护者的前提下走完一次 release 流程,走不通就说明文档有缺口。
8. 项目归档的体面做法
不是所有项目都该永生。当一个项目确实无人维护、也无人接手时,体面归档远好于慢慢腐烂。
8.1 归档四步
- 在 README 顶部加归档声明:一句话说明状态、最后维护版本、推荐替代品。GitHub 的 Archive 按钮会把仓库设为只读并显示横幅,但 README 声明对下游更重要。
- 给迁移指引:明确指出官方推荐的后继项目或 fork,最好附迁移步骤,减少下游的搜索成本。
- CVE 兜底:即便归档,也要保留一个安全联系人(
SECURITY.md里的邮箱或 Security Advisory 入口)。 - 通知下游:在 release notes、邮件列表、包管理器(如
npm deprecate)上发出通知,让依赖方有时间规划。
8.2 声明模板
> **This project is no longer maintained.**
> Last maintained version: v2.4.1 (2025-08-xx).
> Recommended alternatives: <pkg-a>, <pkg-b>.
> Security issues: we no longer accept reports; please migrate.
npm deprecate my-pkg "no longer maintained, use <pkg-a> instead" # 让安装时就能看到提示
8.3 一个反直觉的点
明确宣布「不维护了」比含糊地拖着更有价值。下游最怕的不是坏消息,而是不确定性——含糊状态让人既不敢依赖也不敢替换。同理,即便不再接收安全报告,也要在 SECURITY.md 里把这一点写明白,而不是让报告石沉大海。安全事件的常规处置惯例见 漏洞响应流程。
9. 可持续性评估清单
9.1 自评表
每季度做一次自评,每项 0/1/2 分(0 = 没有,1 = 部分,2 = 完备),满分 20:
| # | 检查项 | 判据 |
|---|---|---|
| 1 | bus factor ≥ 2 | 有 ≥ 2 人持有发布凭据与 admin |
| 2 | 文档完备 | CONTRIBUTING / RELEASING / GOVERNANCE 齐全 |
| 3 | triage 分流 | 有 triager 角色且 issue 有人分流 |
| 4 | 响应时长可控 | 首次响应中位数 < 7 天 |
| 5 | 资金可持续 | 有稳定收入或明确的无偿范围声明 |
| 6 | 角色明确 | 有角色定义与晋级路径 |
| 7 | 可休假 | 有代班机制,维护者能真的休息 |
| 8 | 安全渠道 | 有私密披露渠道与响应流程 |
| 9 | 继任预案 | 有书面交接清单 |
| 10 | 归档预案 | 有终止/归档的判断标准 |
9.2 分数解读
| 得分 | 状态 | 首要动作 |
|---|---|---|
| 0~6 | 高危,随时可能停摆 | 立即减负载:关旧 issue、加模板、写支持边界声明 |
| 6~12 | 勉强维持,无缓冲 | 加人:下放 triage、培养 reviewer |
| 12~16 | 基本健康 | 找钱:上 Sponsors/Open Collective、接触 Tidelift 或基金会 |
| 16~20 | 可持续 | 制度化:全部写入治理文档,去个人化 |
9.3 90 天改进路径
改进路径(按投入产出排序):
| 阶段 | 时间 | 动作 |
|---|---|---|
| 减负载 | 第 1~2 周 | 加 issue/PR 模板、写明支持边界、批量关闭过期 issue |
| 加人 | 第 3~6 周 | 下放 triage 权限给 2~3 人、建立 CODEOWNERS |
| 找钱 | 第 7~10 周 | 开通 Sponsors 或 Open Collective、评估 Tidelift 资格 |
| 制度化 | 第 11~13 周 | 写 RELEASING/GOVERNANCE、做一次接班演练 |
06 分先做「降负载」——关掉无人看的 issue、加 issue 模板、写「不提供免费支持」声明;612 分做「加人」——下放 triage 权限、培养 reviewer;12~16 分做「找钱」——上 Sponsors/Open Collective、接触 Tidelift 或基金会;16 分以上做「制度化」——把上面所有东西写成治理文档,让项目不依赖任何单个个人。
权衡取舍
| 措施 | 收益 | 代价/风险 | 适用条件 |
|---|---|---|---|
| 引入 co-maintainer | 提高 bus factor、分担负担 | 信任成本、协作摩擦、xz 式风险 | 有明确的权限提升流程 |
| 下放 triage 权限 | 立刻减轻 issue 压力 | 误关 issue、标签混乱 | 有清晰的 triage 规范 |
| 收费/接受资助 | 买时间、降低经济压力 | 需处理财务与报税、可能被质疑动机 | 项目被企业广泛依赖 |
| 缩减 scope | 直接降低负载 | 得罪用户、功能被 fork | 维护者已明确倦怠 |
| 归档 | 彻底止损、给下游确定性 | 下游需迁移、生态受损 | 无人接手且无商业价值 |
| 接受企业赞助 | 收入稳定、量级大 | 可能被要求路线图话语权 | 有治理结构约束赞助方 |
| 全职化(拿钱做维护) | 时间有保障、可持续 | 收入不稳定、失去「业余」的退出自由 | 有稳定订阅或基金会支持 |
常见坑清单
- 「再撑一撑就好了」——把倦怠当短期状态拖延,实际是结构性负载;应在信号出现时立即减负载,而不是等崩溃。
- 权限只给一个人——发布 token、域名、签名密钥单点持有;应至少两人持有并定期验证可发布。
- 为新贡献者直接开写权限——xz 式接管正是钻这个空子;应走 triage → reviewer → committer 的晋级流程。
- 没有 issue 模板和「不提供支持」声明——用户把免费项目当 SLA;应在 README/CONTRIBUTING 明确支持边界。
- 把所有赞助给 commit 最多的人——激励刷 commit、惩罚做脏活的人;应按实际工时分配。
- 只加人不写文档——新人无法独立发版,bus factor 名义上提升实则未变;应同步写 RELEASING.md。
- 维护者不敢休假——没有代班机制,休息即停摆;应设轮值与明确的代班人。
- 内部 fork 长期不合并——企业自以为掌控,实则承担永久 rebase 成本;应 upstream first。
- 归档时直接 archive 不写声明——下游无从得知状态、无从迁移;应在 README 顶部加声明与替代品指引。
- 归档后完全断开安全渠道——遗留 0day 无人可联系;应保留 SECURITY.md 联系人或明确声明不再受理。
- 只看 star 数判断健康——star 不反映维护负载;应看响应时长、bus factor、发布节奏。
- 把基金会当成「免费托管」——基金会提供法务与中立治理,但不替项目找钱;资金仍需项目自己争取。
- 把「找人接手」拖到彻底崩溃——越晚交接,接手人面对的技术债与心理负担越重;应在还有精力时就开始培养接班人。
小结
维护者倦怠的根因是责任无限而资源有限:一个人对质量、安全、兼容性负责,却没有对应的时间、金钱和权力。可持续性工作的全部目标,就是把这个不对称一点点扳回来——用 triage 下放减负载,用 co-maintainer 提 bus factor,用资助买时间,用治理文档让项目不再依赖任何单个个人。log4j 与 xz 分别从「没人接得住」和「接错人」两个方向说明了为什么这件事不能等。
可操作的起点很小:这个季度先做一次第 9 节的自评,把得分最低的两项挑出来改进。多数项目的低分项集中在「bus factor」和「文档」——而这两项恰好是成本最低、收益最大的:给第二个人发布权限,把发版步骤写成一页文档,一个下午就能完成,却能把项目从「随时可能停摆」变成「有人能接住」。
延伸阅读:判断项目是否健康看 项目健康度度量;让新人愿意留下并接棒看 贡献者漏斗;安全事件的处置流程看 漏洞响应流程;日常社区运营与冲突处理看 社区运营。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。