学习资料

memos 实测:单文件自建笔记服务,不用 Docker

🦋admin LV1 · 1 次浏览 · 0 条回复

手机里记的东西越来越散:微信收藏、系统便签、几个 markdown 文件散在 NAS 的不同目录里。真要找的时候,一条都想不起来存在哪。我想要的东西很简单——随手写一句话就存下,手机和电脑打开都是同一份,数据在自己机器上,而且别让我为了记一句话先学会 Docker Compose。

memos 大致就是干这个的。开源、轻量、一条一条往下写的笔记服务,支持标签、图片、搜索和 HTTP 接口,官方直接给 Windows、macOS、Linux 的桌面版和纯服务端包。我在一台四核老笔记本(Ryzen 5 3550H、8GB 内存、Windows 11)上把它当服务端跑了一周,下面这些数字都是自己量的。

memos 实测:单文件自建笔记服务,不用 Docker

一个 exe,没有运行时依赖

官方的 Windows 包 22.1MB,解压出来就一个 memos.exe,65MB。不用装 .NET,不用装 Java,不用先起 Docker Desktop,命令行带上 --port 8081 --data D:\memos-data 两个参数就能跑。这一点对我挺重要:小主机上如果只为了记笔记装一整套容器运行时,占的资源和它干的活完全不成比例。

冷启动(第一次要建库、初始化表结构)到 /healthz 返回 200,345ms。库建好之后再启动,162 到 168ms。空闲状态常驻内存 38.5MB,写到 400 条笔记后 45MB,压测最猛的时候 57MB。对一台 8GB 的老机器来说,这点开销基本可以当它不存在。

写入和查询能到什么程度

用它的接口连写 200 条(每条一句话加一个标签),单条耗时中位数 6ms,p90 是 8ms,p99 是 11ms,最慢一次也是 11ms。接着让 100 个请求同时对列表接口发起查询,总共 505ms 全部完成,单请求中位数 382ms。

这个量级对「一个人或者一家人用」完全够,但别指望它扛几百人同时在线——它就是个 SQLite 单进程服务,定位本来也不在那里。

备份:只拷那个 .db 文件,等于备份了一个空库

这是我这周踩得最深的一个坑。

进程被强杀之后我去翻数据目录,只有三个文件:memos_prod.db、memos_prod.db-wal、memos_prod.db-shm。诡异的是主库 memos_prod.db 只有 4096 字节,而 memos_prod.db-wal 有 2,710,992 字节——差不多 2.7MB。也就是说 200 条笔记全都在 WAL 里,主库文件还是个空壳。SQLite 默认要等 WAL 攒到一定页数才做 checkpoint,几百条笔记根本到不了那个阈值。

于是做了一次对照实验:把 memos_prod.db 单独复制到一个新目录启动,服务能正常起来(224ms),但登录直接报 unmatched username and password,一条笔记都没有。把三个文件一起复制过去,启动 168ms,登录正常,200 条笔记全在。

结论很直接:如果备份脚本写的是 cp *.db 或者 rsync --include=*.db,那它每天备份的都是一个 4KB 的空文件,而且你直到要恢复的那天才会发现。要么把 -wal 和 -shm 一起复制,要么先停进程再拷。顺带说一句,日志里能看到 schema 版本(0.31.0 对应 schemaVersion=0.31.8),跨大版本恢复前记得先看一眼这个号。

批量导入会被限流打回来

本来想把旧笔记一次性灌进去,结果灌到一半全是 429。

干净环境下测:连续快速写入,第 121 条开始返回 too many requests,此时总共才过了 841ms。然后我等它恢复,等了 52.6 秒才重新写进去一条。更坑的是读接口和写接口共用这个配额——恢复之后我连续读 300 次列表,其中 139 次也是 429。

所以迁移旧数据必须分批加退避重试,一次几百条硬怼只会让你以为服务挂了。它有个 --rate-limit 参数,默认开着;自己一个人用、确定不会暴露在公网上,可以关掉,对外提供服务就留着。

登录接口有个反直觉的写法

第一次调 /api/v1/auth/signin,我按常规传 {"username":"...","password":"..."},返回 invalid credentials,怎么试都不对,差点以为密码存错了。后来查它的接口定义才发现请求体是嵌套的:

{"passwordCredentials":{"username":"tester","password":"..."}}

扁着传时 username 能被识别,password 会被当成空字符串,最后报的就是凭据无效——这种错误信息最容易让人怀疑自己密码打错了。另外首次部署时 /api/v1/instance/profile 会返回 needsSetup: true,这时候 POST /api/v1/users 建的第一个用户直接就是管理员,建完这个字段变成 false。

它适合谁,不适合谁

和 Obsidian 这一类本地优先的方案比,最大的区别是「谁是数据的中心」。Obsidian 是本地 md 文件,多端同步得靠网盘或者 Syncthing,两端同时改同一个文件就会出冲突副本,最后靠人手动合并。memos 是服务端优先,所有客户端只跟服务端说话,不会产生文件级冲突,代价是断网只能看缓存。

和 Trilium、Kavita 那类比,它们是树状结构,适合写有层级的长文;memos 是时间流水加标签,更像一面数字便签墙。想搭双链知识库别选它,想随手记一句话、回头还能搜到,它比装一整套笔记系统省事得多。

真要放到 NAS 或者小主机上,我的做法是:--data 指到 SSD 或外挂盘,前面套一层反代上 HTTPS,把 --instance-url 设成对外地址(分享链接会用到它),备份按上面说的三件套来,另外隔一段时间用它自带的导出功能留一份 JSON 兜底。手机端不用装东西,浏览器打开同一个地址就能写,界面在窄屏上会自动收成单列,用起来和原生应用差别不大。

用了这一周,最大的感受是「记东西的门槛低」比「功能多」更重要。以前那些笔记软件,光是想要不要建个目录、该放哪个笔记本,就足够让我把想说的话咽回去;现在打开就一个输入框,写完按 Ctrl+Enter,剩下的交给标签和搜索。

你们那边是把碎片笔记放在服务端,还是坚持本地 md 文件那一派?

回复

还没有回复,抢个沙发

登录后即可参与讨论

去登录 注册账号

相关帖子