给个人站点做选型,最容易犯的错误是拿它去和大厂架构比。比完之后,你会觉得什么都该上:数据库要主从,图片要对象存储,缓存要 Redis,搜索要 Elasticsearch。但真正每天维护这套东西的人只有我一个,机器也只有一台。
这一年我在数据库和文件存储之间做了三次比较明确的权衡。每一次都不是“哪个参数更好”,而是“哪个我修得动”。
第一次:博客到底要不要数据库
最早的方案很自然:既然有后端,就上 MySQL。评论、文章元数据、访问统计都放进去,听起来完整。
真算下来,需求很小。文章是静态生成的,评论可以用第三方服务,统计只需要按天聚合。为了这些数据起一个 MySQL,意味着要管端口、账号、权限、备份、升级和内存。2G 的机器上,MySQL 空跑就要占掉几百兆。
我也试过 SQLite。它没有独立进程,数据就是一个文件,备份就是复制文件,恢复就是换文件。缺点是并发写入弱,多个进程同时写会锁库。
最后我选了 SQLite,但把用途限制得很死:只存少量结构化数据,写入频率低,所有写操作串行。评论没有自建,统计在构建时生成。这样它的缺点碰不到,优点全留下。
如果哪天需要多用户、高并发写入,SQLite 就不再合适。但在那之前,为它准备一套主从数据库,是在为不会发生的问题付维护费。
第二次:图片放本地还是对象存储
第二个决定更纠结:图片放服务器本地,还是放对象存储。
放本地的好处很直接:路径可控、迁移简单、备份时和站点一起打包、不依赖外部服务。坏处是占磁盘,访问要走服务器带宽,图片多了会拖慢页面。
对象存储的好处也明显:容量几乎无限、可以接 CDN、源站压力小。坏处是数据在远端,备份链路变长,迁移和费用都要重新计算。
我一开始选了对象存储,把图片全部传上去,文章里写外链。用了几个月,问题逐渐出现:
- 备份脚本只备了服务器,图片不在里面,恢复时站点是“残缺”的;
- 想换服务商时,要重新上传并改所有链接;
- 图片一多,费用不再可以忽略;
- 本地开发时没有网络就看不了图。
后来我把图片迁回本地,用一个固定目录管理,构建时生成不同尺寸。对象存储没有完全去掉,而是降级成“异地副本”:本地是主,定期同步上去做容灾和加速。这样既保留了本地可控,也没有放弃远端冗余。
这个决定的关键不是“对象存储好不好”,而是“主副本放在哪里,我才能在一次故障里把它找回来”。
第三次:自建数据库还是用托管
第三次权衡发生在给一个小服务选数据库的时候。托管数据库省心:自动备份、监控、升级都不用管。自建则便宜、可控,但出了问题得自己修。
我列了一张很朴素的表:
| 维度 | 自建 | 托管 |
|---|---|---|
| 每月成本 | 低 | 高 |
| 备份 | 自己写脚本 | 平台提供 |
| 故障处理 | 自己排查 | 提工单 |
| 迁移 | 自己导 | 平台工具 |
| 可控性 | 高 | 中 |
如果按“省心”排序,托管明显更好。但我算了一下实际数据量:每天写入不到几百条,库文件几十兆,连接数长期是个位数。这个规模下,自建数据库的日常维护成本几乎为零,真正的风险是“我不会恢复”,而不是“机器不够快”。
所以我选自建,同时补了两件事:每天自动备份并校验,每季度做一次恢复演练。如果这两件事做不到,我会立刻改用托管——不是因为自建不好,而是因为我没有能力对它负责。
我最后留下的东西
现在的结构很普通:
- 博客是静态站,构建时生成,运行时不查数据库;
- 少量结构化数据放在 SQLite,写入串行,每天备份;
- 图片以本地为主,对象存储做异地副本;
- 所有数据都有至少一份可以离线恢复的备份。
这套东西的参数一点也不亮眼。它没有高可用,没有读写分离,也没有自动扩缩容。但它有一个我很看重的性质:任何一个组件坏掉,我都能在一个晚上之内说清楚它在哪里、怎么恢复、最坏会丢多少数据。
选型到最后,比的不是谁更快,而是谁的错误更可控。对一个人维护的站点来说,后者几乎总是更重要。