折腾家里她的几个晚上

0. 起因

起因特别无聊。
就是无聊了,想整点活,优化一下Nextcloud吧。
几个晚上,前后改了 20 项配置。
然后发现真正管用的就一项。


1. 差点就去抄清单了

最开始的想法很朴素:找一份“Nextcloud 性能优化最佳实践”,一条条照着改完,收工。
临抄前想了想,还是先摸排下现状吧。
一测磁盘 IO:0.07 MB/s。
🌿。提前准备好的一整套虚拟磁盘调优方案就完犊子吧。


2. 然后挖出来一个 69 毫秒

接着往下挖,就挖到 innodb_flush_log_at_trx_commit 了。
这参数管的是事务提交时多久把日志刷到盘上。= 1 是每提交一笔刷一次,= 2 是每秒刷一次,平时只写页缓存。
= 1 就是每记一笔账跑一趟银行柜台盖章,= 2 是先记本子上、下班前统一去盖。
差多少,看柜台多远。
我这台的柜台——虚拟机嘛,底下那块盘是宿主模拟出来的——单次 fsync 实测 69 毫秒。
我压测跑 1000 次单行事务,花了 69.156 秒,TPS 14。十四。我第一反应是脚本写错了,又跑了一遍,还是 14。
它不是算不过来。它是每笔都在排队等那 69 毫秒。
改成 2,同样的脚本:

改前改后
1000 次单行事务69.156 s0.842 s
TPS141188

🌿,🐮🍺。
同步、上传、照片索引,全都跟着快了。代价是有的:整机断电或宿主崩了,最多丢最后 1 秒已提交的事务。kill 进程、正常关机、restart 都不丢。官方 my.cnf 示例里就这么写的,单机没做复制本来就这个取舍,我 sync_binlog 本来就是 0。
家用网盘,认了。存交易流水的话我不会碰它。
不过这个 82 倍是沾了虚拟机的光——物理 SSD 上同样的改动,可能也就两三倍。


3. 剩下的活儿,基本是打扫卫生

性能收益约等于零,但满足强迫症。

  1. 日志:2.8G → 24M。顺手给 journald 加了 500M 封顶,之前它压根没设上限,随便长。用的 truncate 不是 rm——rm 掉文件,服务手里那个句柄还在往已经消失的 inode 里写,空间一 KB 都释放不出来。这个我以前栽过。
  2. Collabora:1094MB → 354MB。这服务加载过文档就不还内存了,跟仓鼠似的。跑了十天攒下十个空闲进程、1G 内存,而最后一次真用 Office 是四天前。合着在我这儿养了一窝闲进程。
  3. PHP-FPM:常驻 14 → 6,swap 从 1601MB 掉到 282MB。

4. 几个没兑现的

  1. key_buffer_size 128M → 8M。我特意记下了改前的数,等着看内存掉 120MB。

    掉了 2MB。

    全库 269 张表零 MyISAM,那 128M 从头到尾就没真正占过物理页,调小配置值当然释放不出东西来。行吧,就当清了个不合理配置。

  2. opcache.memory_consumption 512 → 256,明确不省内存,共享内存是惰性分配的。纯属给配置文件做美容。
  3. preview_max_memory 2048 → 256。这是天花板不是油门,挡的是“单张预览图允许吃 2G”那条路。全库最大的图才需要 61MB,不会有任何文件因为降配拿不到预览。
  4. FPM 进程数省了大概 100MB。不是我一开始以为的 700MB——为什么,往下看。

5. 数字

5.1 性能

指标优化前优化后
数据库写入(1000 次事务)69.156 s0.842 s(82×)
事务吞吐14 TPS1188 TPS
登录页0.159 s0.083 s(p95 0.088)
文件列表页—0.044 s
并发—约 27 req/s
MySQL 慢查询有0
页面延迟(第四批改前 vs 改后)0.082 s0.081 s(持平)

5.2 内存与磁盘

指标优化前优化后
Swap1601 MB282 MB
Collabora1094 MB354 MB
php-fpm 常驻 worker146–7
可用内存4273 MB4452–4558 MB
/var/log2.8 GB24 MB(封顶 500 MB)
mariadbd942 MB942 MB(纹丝不动)
缓冲池命中率66.4%(冷启动)99.894%

登录页那 0.076 秒不能全算配置的功劳,里面有一部分只是缓冲池从冷到热。别把冷启动到热起来的便宜都记我头上。能拍胸脯的就数据库写入那个 82 倍,同一脚本改前改后各跑一次。
三次重启数据库,每次 9 到 12 秒,Nginx 一条 5xx 都没多出来。


6. 改了啥

参数 / 动作改前 → 改后位置
innodb_flush_log_at_trx_commit ⭐1 → 2my.cnf
apc.shm_size32M → 256Mphp.ini + php-cli.ini
key_buffer_size128M → 8Mmy.cnf(两处)
apc.enable_cli0 → 1php-cli.ini + php.ini
pm.max_requests缺失 → 500php-fpm.conf
pm.min_spare_servers10 → 5php-fpm.conf
pm.start_servers10 → 5php-fpm.conf
opcache.memory_consumption512 → 256php.ini + php-cli.ini
request_slowlog_timeout30 → 5php-fpm.conf
preview_max_memory2048 → 256NC config.php
innodb_flush_neighbors1 → 0my.cnf
innodb_io_capacity / _max默认 → 1000 / 4000my.cnf
innodb_read/write_io_threads4/4 → 8/8my.cnf
缓冲池预热三件套关 → ON/ON/75my.cnf
根分区挂载relatime → noatime/etc/fstab
Collabora 瘦身(8 项)见注coolwsd.xml
清空全部日志(truncate)2.8 GB → 24 MB/var/log 等
journald 限容(6 项)无上限 → 500M / 两周journald.conf
mysqld 重启 ×3每次 9–12 秒—
php-fpm reload ×4先 -t 校验—

Collabora 那 8 项:空闲子进程 4→1、内存占比、语言只留中英、脏内存上限 3072→200、虚拟内存 0→1024、空闲超时 3600→600、关更新检查、日志级别 trace→warning。

每项改之前都备份了带时间戳的副本,随时能单独回退。


7. 我搞错的几个地方

  1. 先说最蠢的一个。 我一看 RSS:php-fpm 占 1937MB,好家伙,内存第一大户,比数据库还狠。我袖子都撸起来了,准备大干一场省它 700MB。
    错了。
    RSS 这个口径会把进程之间共享的内存在每个进程头上都重复算一遍。我这台 OPcache 共享内存 512MB,14 个 worker 每人算了一遍,凭空多出好几千 MB。
    换成 PSS 再看,14 个 worker 合计 324MB。
    700MB 的收益,缩水到 100MB。
  2. 然后是差点照抄的。 Redis 配 maxmemory-policy allkeys-lru,一百篇教程一百篇都这么说。我差点就复制粘贴了,后来一想不对:我用 Redis 存事务文件锁,这策略内存一满,连锁一起扔。锁扔了,门还在,那我锁谁呢。
    官方文档选 Redis 做锁的前提写得清清楚楚——保证缓存对象在需要期间一直可用。这跟我的用法直接打架。维持 noeviction。
  3. 类似的还有 opcache.enable_cli=1,听着特别有道理,实测慢一倍。CLI 脚本跑一次就退出,缓存根本留不住,每次启动还多一遍校验开销。有道理的事不一定对,今年已经遇到第三回了。

8. 收尾

就这些。下次再攒一堆毛病出来,继续记。

最后修改:2026 年 10 月 21 日
如果觉得我的文章对你有用,请随意赞赏