系统审计笔记
盘点不是备份。盘点是「我自己都不知道我装了多少东西」——在盘点之前,再多备份方案都是赌博。
之前写过一篇《Mac mini 重装前,我做了一次系统级资产审计》,记录的是那一次具体怎么做的、看到了什么、最后决定怎么处理。这一篇把那次审计沉淀下来的几条规则单独拎出来——备份优先级矩阵、关键资产识别信号、配置冲突模式。它们对所有攒了多年的个人资料库都通用,不限于 Mac,也不限于 AI 工作站。
动机很直接:我自己被坑过几次以后才知道,普通人对自己机器上的真实状态几乎一无所知。装过的软件早忘了一半,配置散在十几个地方,密钥被复制到了三四个文件里,几个项目还跑着进程没关。你以为备份了,其实只备了表层。真正会出事的那部分根本没被看见。
真实快照:先把数字摆出来
这次审计跑下来的几个数字,我自己看到都吓一跳。
- 磁盘已用 370GB(总共 926GB)——我以前以为只用了一半,结果接近 40%。
- Git 仓库 9 个,其中 4 个没有 remote(git 远端)——意思是这 4 个仓库一旦本地硬盘挂了,就彻底没了。
- 未提交文件 179 个——分散在那 9 个仓库里,每一个都是「我以为我会回头提交」但其实一直没提交的工作。
- LaunchAgent(macOS 的开机后台服务)22 个——我能叫得出名字的不超过 10 个,剩下一半根本想不起来是装哪个项目时落下的。
- Homebrew(macOS 包管理器)安装的命令行工具 75+ 个;npm 全局包 5 个。
- .env(环境变量文件)14+ 个——散在不同项目里,里面装着各种 API Key(外部服务的接口密钥),全部不进 git。
- 监听端口 23 个,活跃 AI 服务 11 个——开机就在跑,但我从来没把这张表完整列出来过。
这张表本身就是审计的第一份产物。没有它,所谓「备份」就只是把 Desktop、Documents、几个看得见的项目目录复制一遍——剩下那 80% 的真实资产全部在视野之外。
我现在的第一条规则:动手做备份决策之前,先逼自己把这张数字表填出来。填不出来就别谈备份。
备份优先级三层:P0、P1、P2
数字表填完,下一个问题:哪些必须备、哪些可以重来、哪些根本不用管。
早期我试过「全部都重要」这种态度,结果是「全部都不重要」。备份策略一旦没有优先级,就退化成「能备什么备什么」,关键数据丢了也只能怪运气。所以我现在只用三层,多了维护不动。
P0:不备份会严重损失
丢了就中断工作,外部资源也重建不了。这是 P0 的标准。
- 未提交代码——还没 push 到 remote 的那些,本地硬盘是唯一副本。
- 业务数据库——本地跑着的 Postgres(开源关系型数据库)、SQLite(嵌入式数据库),里面装着实际业务数据。
- 向量数据——chromadb、lancedb、mem0(几个本地向量数据库)里的 embedding(向量表示),这是最特殊的一类,下面单独讲。
- 语音资产——录音、生成的音频样本,原始的就那一份。
- .env 文件——里面是各种第三方服务的 API Key,丢了要重新去几十个网站申请。
- 自定义 LaunchAgent——开机自动跑的那些服务定义,丢了等于把日常工作流的入口全砸了。
P1:恢复成本高,但能重建
不会致命,但恢复要花一两天。
- 模型缓存——本地拉下来的 LLM 权重,重新下载几十 GB 是体力活。
- 全局包——Homebrew 和 npm 装的命令行工具集合,可以用 Brewfile 之类的清单重建,但前提是你有清单。
- AI CLI 配置——Claude Code、Codex CLI 之类的工具配置,里面的 prompt、自定义命令、MCP 接入都在这里。
- 浏览器配置——书签、扩展、登录态。同步过的是一回事,没同步的小工具配置又是另一回事。
P2:可以重新下载或配置
最低层,丢了基本无所谓。
- Homebrew 包本身——清单在就能重装。
- 应用安装包——AppStore 或者厂商网站都能再下。
- 构建产物——node_modules、build、dist 这种,源码在就能再生成。
三层的关键不是分得多细,是「分了之后真的按层级处理」。P0 必须冗余(云端 + 异地物理副本),P1 一份就够,P2 不备。体量从「全盘几百 GB」降到几十 GB,反而能做到「每天自动跑、出问题立刻发现」。
全备一切,备份太大就跑不动。跑不动就改成每周一次,再变成每月一次,最后变成「上次备份是半年前」。分层不是为了省空间,是为了让备份真的能跑下去。
关键资产识别的 6 个信号
分类之后,下一个问题:这些东西藏在哪里?普通备份工具看不见,得自己一类一类去找。
我每次盘点都按这 6 个信号走一遍,每个信号对应一个真实场景。漏一个,重装后可能就会「啊那个东西没了」。
信号 1:未提交代码
最容易被忽略的一类。大家默认「代码都在 git 里」,但 git 里只有提交过的部分,没提交的那 179 个文件全部不在。
做法:把机器上所有 git 仓库列出来,逐个跑 git status 看有没有未提交的改动,再跑 git remote -v 看有没有远端。两个都不对的仓库就是高危——没 remote,本地是唯一副本;未提交,连本地也没归档。
我那次发现的 4 个无 remote 仓库里,2 个是早期实验留下的,但里面有一些当时调出来的关键参数和小工具,丢了我得重做一遍。这东西不会让你立刻意识到价值,但真没了才会想起来。
信号 2:运行中的数据库
本地跑着 Postgres、SQLite、ChromaDB(一种向量数据库)这种服务,备份时直接复制数据文件经常是坏的——数据库在写,复制出来的可能是中间状态。
这一类资产的备份动作不是「复制文件」,是「先停服务、或者用数据库自己的 dump(导出数据)工具」。两个都不做就开始备份,事后恢复时大概率会发现备份是坏的。
更现实的是——大部分人压根不知道自己机器上有哪些数据库在跑。它们都是某个项目装的时候作为依赖装进来的,跑在某个端口上,开机自动启动,从来没主动想过它们。盘点时得专门去查所有监听端口、所有数据库进程,看看里面都装了什么。
信号 3:向量数据(这个最特殊)
chromadb、lancedb、mem0 这种本地向量库存的是 embedding——把文档、聊天记录、知识点编码成的高维向量。理论上能从源数据重新计算,实际上几乎不可能。这是它最特殊的地方。
重建需要三个条件同时满足:源数据还在、当时用的 embedding 模型还能拿到、当时的分块和清洗规则还记得。少一个,重建出来的向量库就和原来不一样——搜索结果会变、相似度阈值要重调、整条流程都得回归测试。
我自己的几个本地知识库都跑了几个月,期间换过 embedding 模型、调过分块策略、清理过几次错误条目。从零重建,可能比当初第一次建还麻烦。向量数据在我这里是 P0,和数据库放同一层。
信号 4:.env 文件
.env 文件用来装环境变量,里面经常塞各种 API Key、数据库连接字符串、第三方服务的 token。按规矩它不该进 git,备份的时候要专门处理。
它们散在各个项目的根目录、config 子目录,有时候还藏在 dotfile(隐藏文件)的更深层。我那次扫到 14+ 个,分布在 8 个项目里。逐个打开一看,里面装着各种第三方服务的接入凭证,丢了要重新去几十个网站申请,还得记得当初申请时填的是哪个邮箱、哪个团队、哪一份限额。
盘点时必须扫一遍 .env、.env.local、.env.production 这类文件,记下它们在哪、里面装了什么类型的密钥,专门进 P0。
信号 5:自定义 LaunchAgent
LaunchAgent 是 macOS 的开机后台服务定义,文件放在 ~/Library/LaunchAgents/ 里。每个文件描述一个开机自动启动的服务——可能是某个 AI 服务、某个监控脚本、某个定时任务。
我那次扫到 22 个,至少一半是早期某个实验装上去再也没卸过的。这一类资产丢了不会立刻有感——但你下次开机会发现一堆东西不见了:自动启动的 AI 服务、定时跑的备份脚本、监控异常的小工具,全部消失。要一个一个回想当初是怎么配的,几乎不可能。
LaunchAgent 全目录必须进 P0,整个 ~/Library/LaunchAgents/ 一起备。同时这也是个清理机会——盘点时顺便决定哪些可以删了,不要无脑全保留。
信号 6:明文密钥(最危险的一类)
我自己最不敢回头看的一类。盘点时检查 shell profile(终端启动配置文件,比如 .zshrc、.bashrc、.bash_profile),经常会发现一行 export OPENAI_API_KEY=... 之类的——明文密钥,跟着 shell 一起开机加载。
这里有两个问题。一是安全:明文存在配置文件里,任何能读到这个文件的进程都能拿走(包括你装的某些不太干净的工具)。二是流动:shell profile 经常被备份到云盘、被复制到新机器、被贴进求助截图——一不小心密钥就传出去了。
这一类不只是备份问题,是改造问题。备份时要把 shell profile 完整备走(属于 P0),但盘点完之后必须排一个任务——把所有明文密钥从 shell profile 挪到密码管理器,再从环境里读出来用。这件事我自己还没做完,下一步就是它。
配置冲突的 5 种常见模式
备份做完不等于整理完。同一台机器跑了几年,配置之间会互相冲突,普通备份方案完全发现不了这一层。
我那次盘点把碰到的冲突归成了 5 种模式。每一种都不致命,但合在一起就会让人重装系统后发现「为什么有些东西好像能跑、又好像不对」。
模式 1:端口语义漂移
最常见:3100 在 A 项目里是 web 服务,在 B 项目里是某个数据库管理界面,在 C 项目里被某个 AI 工具占了。三个东西都开机自动启动,谁先抢到就用谁;剩下的两个静默失败,没人会主动告诉你。
更隐蔽的是端口号差一位——3100 和 13100 被不同组件分别使用,配置文件里写错一位就连到错的服务上。日志里看不出错,对面也是个 HTTP 服务,只是返回的不是你要的东西。
盘点时要把所有监听端口列出来,对照各项目配置文件里的端口声明,看有没有冲突。这件事备份工具做不了,只能自己跑一遍。
模式 2:旧路径残留
crontab(定时任务表)里写着 /Users/me/old-project/run.sh,但 old-project 那个目录三个月前就删了。软链指向已经不存在的目录。MCP(Model Context Protocol,AI 工具用来连外部服务的协议)配置里指向某个已经迁移走的服务。
这一类残留备份会被原样保留——恢复时它们还在配置里,但指向的目标早就没了。轻则日志报错,重则某个工具依赖的路径不存在,直接挂掉。
盘点时把 crontab、所有软链、所有外部工具的配置文件过一遍,逐条验证指向的路径或服务还存在。不存在的就当场决定:要么删,要么改指向新路径。
模式 3:失效服务依赖
A 服务的配置里写着「依赖 B 服务在 5432 端口」,但 B 服务三个月前换成 C 服务了,5432 端口空着。A 服务每次启动会尝试连,连不上就用 fallback 逻辑跑一个降级模式——你完全不知道它在跑降级。
这种问题平时不容易暴露,降级模式经常「看着也能用」。等真出问题去查日志,才发现某个关键链路其实已经断了好几个月。
盘点时要逐个服务看配置里依赖了什么,再交叉对照「这些依赖现在还在跑吗」。不在跑的依赖要么删掉,要么补上,不要让它继续以「应该在」的状态留在配置里。
模式 4:跨根调度
我自己踩过最深的坑是这一类。一个 scheduler(调度器)原本只管自己项目的任务,但配置里逐渐被加了几条「顺便也跑一下隔壁项目的脚本」。等某天把隔壁项目重构、目录搬走,这个调度器还在按老路径跑,要么报错、要么跑错文件。
更糟糕的是,这种跨根调度往往不对称:A 调度器知道自己在调 B,但 B 完全不知道有人在外面调它。维护 B 的时候自然不会考虑 A 的依赖,冲突在毫无预警的状态下发生。
盘点时必须给每个调度器画一张「我调了谁」的清单,再倒过来看「谁在调我」。两边对上以后才能判断哪些跨根调度是合理的、哪些是历史包袱。
模式 5:历史副本混淆
同一份配置文件存了几份:本地一份、备份目录一份、archive 里一份、某次实验时复制出来又一份。名字都差不多,内容略有差异,时间戳也都不远。要判断哪一份是 canonical(权威的、官方的)几乎靠考古。
一个人还能强撑,但时间一长就崩——半年后回头看,根本想不起来哪份是「现在真的在用的那份」。AI 工具进来读这堆文件,更容易选错。
盘点时每一份关键配置必须指定一个 canonical 路径,其他副本要么删掉、要么明确标成历史(比如挪到一个 archive/ 子目录里)。原则是「同一时间只能有一份在用」,不允许「都还能用」。
冷存储里值得留的几类文件
盘点完不是全删。除了 P0/P1/P2,还有一类东西不影响系统运行,但「以后想写文章会回头查」。我把它叫冷存储里的留种。
大部分历史文件其实价值不高——旧聊天记录、旧实验输出、旧版本的设计稿、过期的临时报告。可以一刀切扔掉。但这四类我会单独挑出来留:
- 跨模块分析——把系统几个模块放在一起看的全景图、调用链、权限传播路径。做一次成本很高,留着以后回头看自己当时怎么理解的。
- 教学整理——某门公开课的中英对照笔记、整理过的章节摘要。已经过滤过一遍的二次产物,比原视频好用。
- 调研报告——行业、技术演进、某个工具的对比评估。当时花了几天调研得出的结论,几个月后还能当起点。
- 元信息——质量检查报告、分类清单、目录结构快照。是关于「资料本身的资料」,重建很麻烦但实际就那么几份。
判断标准很简单:扔掉的成本是「以后想到要重做一遍」,留下来的成本是「占点磁盘」。前者代价远高于后者,那就留。但留也要进冷存储目录,不要混在工作目录里——混了以后每次打开都要再判断一次「这个是热数据还是冷数据」,注意力被磨光。
盘点完之后做什么
盘点不是做一次就完了。我现在的节奏:每次做大动作之前——重装系统、迁移机器、换硬盘——都重新跑一遍这套流程。平时维持一份动态清单,新增加的 LaunchAgent、新写的 .env、新装的全局工具,都顺手记一笔。
这件事最难的不是工具,是心态。承认「我自己不知道我装了多少东西」需要勇气——很多人会下意识抗拒,承认了就得面对那张数字表。但只要面对过一次,下一次就轻松多了。
整理资料库的本质,不是更勤奋地备份,是把「看不见的资产」变成「看得见的清单」。看不见就赌运气;看得见才谈得上策略。
我下一步还有几件没做完:把所有明文密钥从 shell profile 挪到密码管理器、修掉那几条配置冲突、给 22 个 LaunchAgent 做一次清理删一半、把 4 个无 remote 的本地仓库要么加 remote 要么彻底归档。这些都不是一次能做完的——能做完的也不是一份清单能解决的问题。
但有了这张数字表和这几条规则,至少下次面对它们的时候不会再问「这台机器到底装了什么」。这就够当起点了。