今天早上大约 5:35,我的论坛磁盘使用量突然激增并导致崩溃,完全离线。我不得不调整 Digital Ocean 镜像的大小才能使其恢复运行。唉。
以下是过去 24 小时的磁盘使用情况:
问题:我可以查看哪些日志或事后分析来弄清楚到底发生了什么?! 我检查了 Discourse 控制面板中的日志,但那里没有任何线索……日志在站点崩溃时戛然而止,随后在站点重新上线时又立即恢复。
今天早上大约 5:35,我的论坛磁盘使用量突然激增并导致崩溃,完全离线。我不得不调整 Digital Ocean 镜像的大小才能使其恢复运行。唉。
以下是过去 24 小时的磁盘使用情况:
问题:我可以查看哪些日志或事后分析来弄清楚到底发生了什么?! 我检查了 Discourse 控制面板中的日志,但那里没有任何线索……日志在站点崩溃时戛然而止,随后在站点重新上线时又立即恢复。
我会先从找出是哪个目录导致问题开始。我的标准做法是进入 /var/discourse 目录,然后运行 du -h -d 1 命令。进入占用空间最大的目录,重复此过程,直到找到可疑目录。一旦找到,这可能会为你提供线索,帮助你了解问题所在。
也许可以自动备份?
是的,备份通常是这类故障的常见原因——过去 7 天的磁盘使用情况如何?
另外请注意,本地上传 也包含在这些备份中,因此如果你在 18:00 左右上传量显著增加,也会导致备份归档体积增大。
嗯。我一直在将文件从 S3 迁移回本地服务器,但该过程似乎是实时运行的,每次只能处理几百张图片(每张约 300KB),即每批约 0.1 GB。在过去的一周里,我可能运行了该脚本 20 次,因此 20 批总共占用了约 2 GB 的磁盘空间。我的磁盘空间原本非常充足。
有没有可能,尽管脚本看起来是实时迁移这些文件(从 S3 下载并立即上传到 Digital Ocean),但仍然存在某种队列作业的延迟,这些作业在凌晨 5:30 被触发,与图片迁移有关?
(另外:我手动运行这些批次直到晚上 9 点,所以据我所知,从晚上 9 点到凌晨 5:30 服务器崩溃前,服务器一直在进行正常操作。)
以下是我过去 7 天的磁盘使用情况。由于正在导入图片,磁盘使用量一直在稳步上升,但你可以看到它在凌晨 5:30 突然飙升至 100%:
除了我在“日志”选项卡中看到的日志文件外,是否还有其他日志文件可能提供关于凌晨 5:35 发生什么的线索?
嗯。我的备份设置为每两天上传到 S3,但从 9 号之后就没有任何记录了?
顺便提一下,看到上述情况后,我点击了 Discourse 中的按钮手动触发备份。整个过程耗时 28 分钟,看起来一切正常;现在我在 Discourse 和 Amazon S3 的备份视图中都能看到那个 .tar.gz 文件了。那么,为什么自动备份没有触发呢?!啊啊啊啊。
我很困惑……这些目录的占用空间都不算特别大:
root@x-app:/var/www/discourse# du -h -d 1
3.5M ./lib
104K ./bin
8.0K ./.tx
148M ./public
8.0K ./.bundle
14M ./plugins
4.3M ./db
4.0K ./log
532M ./tmp
8.9M ./spec
17M ./config
556M ./vendor
8.0K ./images
329M ./.git
2.0M ./script
80K ./docs
2.5M ./test
16K ./.github
17M ./app
1.6G .
即使查看 Docker 容器内的整体磁盘空间,也没有之前那么大。我之前使用的是一个 80 GB 的 DigitalOcean Droplet,就是它达到了 100% 的使用率。于是我将其扩容至 160 GB,翻了一倍。理论上,这意味着其中一个目录的占用应该达到 50%,对吗?
root@x-app:/var/www/discourse# df -h
Filesystem Size Used Avail Use% Mounted on
overlay 155G 58G 98G 38% /
tmpfs 64M 0 64M 0% /dev
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
shm 512M 2.6M 510M 1% /dev/shm
/dev/vda1 155G 58G 98G 38% /shared
tmpfs 3.9G 0 3.9G 0% /proc/acpi
tmpfs 3.9G 0 3.9G 0% /proc/scsi
tmpfs 3.9G 0 3.9G 0% /sys/firmware
你之前几乎每晚磁盘使用率都会接近 100%——看起来这次刚好成了压垮骆驼的最后一根稻草。我推测之前的备份失败是因为在创建要发送到 S3 的本地备份文件时磁盘空间不足,但只是失败了,并没有导致你的论坛崩溃。你最终注意到问题,是因为磁盘空间不足恰好在关键时刻让 PostgreSQL(或 Redis,或其他组件,这其实并不重要)无法正常工作,从而导致你的论坛宕机。
(我的服务器上有近 100GB 的图片。我执行 Discourse 的定时备份时不包含上传文件,但包含缩略图。然后,我会先对备份目录进行异地基于文件的增量备份,再对上传目录进行同样的操作。我已经测试过这种恢复方式,去年正是基于它完成了站点迁移。每晚存储 100GB 的 tar 压缩包显然是不现实的。)
啊哈,原来那些小尖峰是 Discourse 正在尝试创建备份!这下就说得通了。
那么,这是我过去 7 天的图表:
也许我们看到的情况是:
在过去的一周里,Discourse 多次尝试创建备份。这个过程会暂时占用大量磁盘空间,而每次尝试时,由于空间不足,备份都未能成功完成。
昨晚它再次尝试创建备份时,进度更靠前了一些,但不幸的是导致网站崩溃了。
这听起来很有道理,因为上一次成功的备份是在 7 月 9 日。因此,它等待了 2 天(根据我的设置),然后在 7 月 11 日再次尝试。那次失败了,于是它又等待了 24 小时,分别在 12 日、13 日以及 14 日进行了致命的那次重试。
如果情况确实如此,我希望 Discourse 能:
在备份失败时提供更明确的通知;
或许,如果 Discourse 在开始备份时发现可用磁盘空间低于某个百分比(例如 10%),就应自动“中止”备份(并生成通知),这样在磁盘空间已经紧张时,它甚至不会开始备份。
顺便一提,如果这真的是发生的情况,那么查看 7 月 11 日第一次失败的备份记录会发现,当时还有约 40% 的可用磁盘空间(大约 32GB!!!),但这仍不足以让备份成功完成。这是真的吗?!为什么 Discourse 在生成备份时需要如此大量的临时/工作空间?
昨晚它未必取得了进一步的进展;你只是“输掉了一场比赛”——当空间耗尽时会发生什么,取决于哪个组件首先受到问题的影响。
如果它无法进行备份,我倾向于认为它可能会尝试发送消息,但如果磁盘空间已满,它可能无法成功。![]()
一个固定的百分比并不能说明太多问题;与上传内容相比,数据库可能非常小,反之亦然,而且是否包含缩略图、是否包含上传内容等因素也会影响结果。我想,或许可以设置一个可配置的空闲空间要求,以便你根据自己的网站进行调整。
我不清楚你是如何判断“过分”的——在我看来,这并不算过分。
说得对;正如你指出的,这里有很多变量在起作用。
哦,理论上“正确”的做法应该是计算备份等所需的空间量,等等。但为了保持超级简单,是的,就用一个固定的百分比就好。我只是在想……如果两个选择是“你的站点可能会完全崩溃并离线”或者“这是一个不完美但快速的解决方案”,那我当然选择后者,谢谢。![]()
说到感谢,也要谢谢你一直以来在迁移工作以及对此事的建议上给予的帮助。![]()
估算备份所需空间是计算机科学中的难题之一……它和进度条算是远亲。![]()
说正经的,备份的一部分是数据库转储,而很难提前估算其大小。如果你的图片多到空间成为问题,将它们纳入备份存档可能已超出主流做法。
通常情况下,在系统管理方面,可用空间监控和备份健康检查一直是运维负担,而非应用本身的负担。这也是大家付费让 CDCK 托管 Discourse 的原因之一。
还有很多其他情况会导致空间耗尽。我知道你关注的是那个让你中招的问题,但问题其实更为普遍,我认为这通常应作为运维开销来处理。
虽然我不想泼冷水,但根据帖子内容,实际上并没有确凿证据表明 Discourse 备份流程是导致该问题的原因。
为什么不 100% 确认这个问题确实是由每日备份流程引起的呢?主机上运行的每日 crontab 任务不止一个。
@pnoeric 是否对 /var/discourse 文件系统(容器外部)执行了 du 命令?
在您的笔记中,@pnoeric 写道:
root@x-app:/var/www/discourse# du -h -d 1
但这完全遗漏了包含所有备份和上传内容的 Discourse 共享目录!同时也遗漏了主机上的所有 Docker 文件(以及镜像)(如果长时间不修剪镜像,这些文件可能会变得很大)。
执行此检查的正确位置是在容器外部(而不是在容器内部):
例如(在容器外部):
cd /var/discourse
/var/discourse# du -sh *
4.0K bin
4.0K cids
56K containers
12K discourse-doctor
24K discourse-setup
164K image
24K launcher
4.0K LICENSE
12K README.md
24K samples
8.0K scripts
62G shared
148K templates
您看,在这台主机上,shared 目录大小为 62G。
以及从文件系统的 /var 目录(容器外部):
cd /var
# du -sh *
511M cache
20K composetest
62G discourse
1.6G docker
8.0K legacy
52G lib
4.0K local
0 lock
4.0K locks
5.7G log
24K logs
64K mail
4.0K opt
4.0K registry
4.0K shared
1.9M spool
48K tmp
25G linux_app
2.2G www
我并非想泼冷水,但在四处提出大量针对 Discourse 的“修复方案”之前,最好能 100% 确认 Discourse 备份 cron 任务确实是问题的根源。
我们目前的 Discourse 备份流程从未出现过任何问题,此外,管理主机文件系统本身并不是 Discourse 的任务。
如下所示:
du
Filesystem 1K-blocks Used Available Use% Mounted on
udev 32892500 0 32892500 0% /dev
tmpfs 6584232 2136 6582096 1% /run
/dev/md2 470927632 215969956 230966124 49% /
tmpfs 32921160 0 32921160 0% /dev/shm
tmpfs 5120 0 5120 0% /run/lock
tmpfs 32921160 0 32921160 0% /sys/fs/cgroup
/dev/md0 482922 75082 382906 17% /boot
/dev/sda1 244988 4636 240353 2% /boot/efi
tmpfs 6584232 0 6584232 0% /run/user/1000
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/0f8be368b0154285423630ad50148ee2d5fdcb357c46125eafa7374ca34ef29a/merged
shm 524288 1620 522668 1% /var/lib/docker/containers/ca7b55fc5a0c123f7b2b1234ea210aa8286a34167cba9344b7929547bd323c9b/mounts/shm
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/7cd7e8b5b35b496eaed68753cc995e9303499a24721062055e2f06beb07e26c8/merged
shm 65536 0 65536 0% /var/lib/docker/containers/3cc0c90c3e3a5db6692e7b5d21727fbb1c13c8e07e48e4f6d954214fc03694a9/mounts/shm
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/31533fdf68033eed96dab4f9df89025ea3dab172ed48b6ce6431840a8df1c8ea/merged
shm 524288 0 524288 0% /var/lib/docker/containers/631fbabedda9a430dd8204ec66fb45c7514d948025124171b960ea424e28d5d4/mounts/shm
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/7a3ba2223ee93bc868b52b3707799d0fd7b4ca6dcc0df29f20c2c98a53903ff1/merged
shm 65536 0 65536 0% /var/lib/docker/containers/7a145366268c8ac5543a4555dc1bfc63c1e85a654e4c793e96fc2cc2e8514388/mounts/shm
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/add4bdd7bd88df7a0e05dff21896d3ef796f7cf2ff9759e0bb04b1953f16cd95/merged
shm 65536 0 65536 0% /var/lib/docker/containers/123743e122089b94660a6bdd2a9e55055ad91b6f75cce4ac760f36066bcf14d0/mounts/shm
overlay 470927632 215969956 230966124 49% /var/lib/docker/overlay2/b376ff32eaac0c58463e8b99b6db9ec0da3405c3f7a9f00b5430f10e07d372b0/merged
shm 524288 0 524288 0% /var/lib/docker/containers/63c52bc571b5f0d2544417da10efc37d3957e7a38f44bc8325145e795ee29559/mounts/shm
让我们看看 Docker 文件:
# cd /var/lib
# du -sh docker
30G docker
我们的 Docker 镜像会定期修剪和清理。
@bartv 正确地建议从这里开始:
我建议先从找出是哪个目录爆满开始。我的标准做法是进入 /var/discourse,然后运行
du -h -d 1。选择最大的目录,进入其中并重复此过程,直到找到可疑目录。一旦找到,这可能会为您提供一些线索,说明发生了什么。
这是一个不错的开端,但主机文件系统上还有很多其他位置可能导致文件系统填满,包括 Docker、core 文件等。
仅凭一张显示每日出现一次尖峰百分比的图表,还不足以有把握地断定 Discourse 备份 cron 进程是根本原因。它可能是,但也可能不是,基于目前的证据!
太好了,我会试试你提到的所有内容。谢谢。
没错,这显然是一次备份操作。
不,已有充分证据:除了一个例外,使用量峰值均呈两天一次的间隔出现,而备份频率也设置为两天一次。此外,我们在 Meta 上的过往经验也表明,这正是此类故障的典型表现。
没错,这是一个面向未来的可靠方案。不过,对于开始遇到 VPS 磁盘空间限制的用户,我们的首要建议是使用 机器外上传存储,并配合 S3 机制。
既然 @pnoeric 正试图将图片移出 S3,那么在仍位于 S3 的备份中存储所有图片的多份副本,就无法实现“移出 S3
我的情况是,我有很多图片,这意味着当用户查看这些图片时,会产生大量的传输带宽。因此,当图片托管在 Amazon S3 上时,带宽费用才是真正让我难以承受的原因。特别是当我意识到可以将所有图片存储在 DigitalOcean(DO)的 Droplet 上,并且这些存储和带宽费用已经包含在我已有的付费套餐中时(未来某个时候,也许将数据移回 S3 会有意义,或者再次升级 DO Droplet 可能更划算……)。
所以我最初使用的是 S3,后来才发现了自己的错误。因此,我现在的情况是,利用你提供的优秀代码,将所有图片从 S3 迁移回 DO。
在 S3 上保留完整备份(包括所有图片)则是另一回事——这些备份存放在 S3 的“冷存储”中,除非出现问题,否则不会被访问,因此不会产生高额的带宽费用。
另外:我一直在思考备份和磁盘使用的问题。我仍然认为这里缺少了一些东西。也许只是一个警告信息,或者更好的文档说明。但我的 Discourse 实例当时只使用了 60% 的磁盘空间,而异地备份却失败了。如果能提供某种磁盘空间需求的估算,或者在磁盘空间不足时发出警告,似乎总比现在的情况要好。而现在的情况是:由于空间不足,连续几天没有备份,随后发生严重崩溃,导致论坛完全离线。:-\
(@riking 甚至说过“备份是导致此类故障的常见原因。”那么 Discourse 实例是否经常因为备份失败且没有潜在问题预警而崩溃?)
换一种更简单的说法,从 3 万英尺高空俯瞰:如果一个软件的基本功能(自动备份)会导致整个系统离线,这似乎是一个设计缺陷。尤其是我们讨论的这个功能,仅仅是利用磁盘空间来准备备份,甚至并不将备份存储在同一块磁盘上。
不,他的意思是,通过任何服务器上的任何软件进行备份,都可能填满磁盘并引发问题。
当然,但这就是为什么你要用 CDN 来前置 S3。不要直接从 S3 提供图片,那样会贵得离谱
。你可以轻松使用 CloudFront 甚至 CloudFlare 来前置 S3。CloudFlare 的免费套餐就能实现这一点。
此外,将它们本地存储也是个很糟糕的主意,你将被迫不必要地升级你的 VPS。本地 SSD 的成本会高得多。
啊,好的,明白了。
那我该如何知道 Discourse 准备备份可能需要多少磁盘空间呢?软件并没有告诉我,也许明天就会变成 500 GB,导致我的 Digital Ocean 服务器再次宕机。
至少如果我能做个粗略估算,就能尽量掌控局面。
哇,真是个好主意,我从来没想过。那我是不是应该在我的 Amazon 存储桶前面加一层 CDN,然后告诉 Discourse 使用 S3 来提供所有资源?(就像我之前那样?哈哈)