백업 중 디스크 사용량 급증, Discourse가 완전히 충돌했습니다 :(

오늘 아침 5시 35분경, 내 포럼의 디스크 사용량이 갑자기 치솟으며 서버가 충돌했고 사이트가 완전히 오프라인 상태가 되었습니다. Digital Ocean 이미지를 리사이즈해야 겨우 복구할 수 있었습니다. 정말 힘들었습니다.

최근 24시간 동안의 디스크 사용량 그래프는 다음과 같습니다:

질문: 대체 무슨 일이 있었는지 파악해 보기 위해 어떤 로그나 사후 분석(post-mortem analysis)을 살펴볼 수 있을까요? Discourse 제어판의 로그를 확인해 보았지만 아무런 단서가 없습니다… 로그는 사이트가 충돌한 시점에서 끊겨 있다가, 사이트가 다시 온라인이 된 시점부터 바로 다시 기록되기 시작합니다.

어느 디렉터리가 문제를 일으키고 있는지부터 파악하는 것으로 시작하겠습니다. 제 표준 접근 방식은 /var/discourse 디렉터리로 이동한 다음 du -h -d 1 명령을 실행하는 것입니다. 가장 용량이 큰 디렉터리를 찾아 들어간 후 이 과정을 반복해 원인을 찾아내세요. 원인을 찾으면 어떤 일이 일어나고 있는지 파악하는 데 힌트가 될 수 있습니다.

자동 백업은 어떨까요?

네, 백업은 이런 유형의 실패의 일반적인 원인입니다. 7일간의 디스크 사용량은 어떻게 되나요?

또한 로컬 업로드도 이러한 백업에 포함되므로, 18:00 전후로 업로드량이 크게 증가했다면 백업 아카이브 크기 또한 증가했을 것입니다.

음. 저는 S3에서 파일을 내보내고 로컬 서버로 다시 가져오는 작업을 진행해 왔습니다(S3에서 가져오기 실패 관련 링크). 하지만 이 과정은 실시간으로 실행되는 것처럼 보이며, 한 번에 몇백 장의 이미지(각각 약 300KB)만 처리되므로 배치당 약 0.1GB에 불과합니다. 지난 일주일 동안 스크립트를 약 20회 실행했으니, 20개 배치 = 총 약 2GB의 디스크 공간이 사용되었을 것입니다. 저는 디스크 공간이 충분했으므로 문제가 없었습니다.

스크립트가 S3에서 이미지를 다운로드하고 Digital Ocean으로 즉시 업로드하는 것처럼 실시간으로 이동하는 것처럼 보이더라도, 5시 30분에 실행된 큐(job) 작업과 관련하여 이미지 이동과 연관된 어떤 지연(lag)이 발생했을 가능성이 있을까요?

(참고: 저는 밤 9시까지 이 배치들을 수동으로 실행했습니다. 제가 아는 한, 서버는 5시 30분에 다운될 때까지 밤 9시부터 5시 30분까지는 정상적인 운영을 수행하고 있었습니다.)

아래는 제 7일간의 디스크 사용량입니다. 이미지가 가져와지면서 꾸준히 증가하다가 5시 30분에 100%까지 급격히 치솟는 부분이 보입니다:

‘로그’ 탭에서 볼 수 있는 로그 파일 외에, 5시 35분에 무슨 일이 있었는지에 대한 단서를 줄 수 있는 로그 파일이 있을까요?

음. 내 백업은 S3로 2일마다 전송되도록 설정되어 있는데, 9일 이후로는 아무것도 없어요?

Discourse ‘백업’ 화면

Amazon S3 화면

참고로, 위 내용을 보고 나서 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 컨테이너 내부에서 전체 디스크 공간을 살펴봐도 이전만큼 크지 않습니다. 80GB DigitalOcean 드롭렛을 사용했는데, 그곳이 100%를 차지했습니다. 그래서 용량을 160GB로 두 배로 늘렸습니다. 이론적으로 이는 이 중 하나가 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

이전에는 거의 매일 밤 CPU 사용률이 100%에 가까운 스파이크가 발생했었습니다. 이번에는 그 한계를 넘어서버린 것으로 보입니다. S3로 전송하기 위해 로컬 백업 파일을 생성하는 과정에서 디스크 공간 부족으로 인해 이전 백업들이 실패했을 것으로 추정됩니다. 다만 단순히 실패했을 뿐 포럼 자체를 손상시키지는 않았을 것입니다. 마침 포럼을 멈추게 할 적절한 시점에 디스크 공간 부족으로 인해 postgresql(또는 redis, 혹은 다른 서비스, 정확히는 중요하지 않습니다)이 문제를 일으키자 여러분이 드디어 그 사실을 인지한 것입니다.

(제 서버에는 약 100GB의 이미지가 저장되어 있어, Discourse 정기 백업 시 업로드 파일은 제외하고 썸네일만 포함하여 백업합니다. 그런 다음 먼저 백업 디렉터리에 대해 오프사이트 파일 기반 증분 백업을 수행하고, 그 다음에 업로드 디렉터리에 대해 동일한 방식으로 백업합니다. 이를 복원 테스트로 검증했으며, 지난 해 수행했던 사이트 마이그레이션의 기반이 되었습니다. 매일 밤 100GB짜리 tarball 파일을 저장하는 것은 터무니없는 일입니다.)

아하, 그래서 그 작은 스파이크들은 Discourse가 백업을 시도하는 과정이었군요! 이제 상황이 조금 명확해졌습니다.

다시 지난 7일간의 차트를 보여드리겠습니다.

아마 우리가 보고 있는 현상은 다음과 같습니다:

  1. 지난 일주일 동안 여러 차례 Discourse가 백업을 시도했습니다. 이 과정은 일시적으로 많은 디스크 공간을 차지하는데, 시도할 때마다 공간이 부족해 해당 백업들은 모두 실패했습니다.

  2. 그리고 지난밤에 다시 백업을 시도했을 때, 이전보다 더 멀리까지 진행되었지만 불행히도 사이트가 충돌했습니다.

마지막으로 성공한 백업이 7월 9일이었으므로, 이는 일리 있는 추측입니다. 설정에 따라 2일(7월 11일)을 기다린 후 다시 시도했으나 실패했고, 이후 24시간을 기다려 12일, 13일에 다시 시도했으며, 14일에 치명적인 재시도가 있었습니다.

만약 이것이 사실이라면, 저는 다음 사항을 보고 싶습니다:

  1. 백업이 실패할 때 Discourse에서 더 나은 알림을 제공해 주었으면 합니다.

  2. 백업을 시작할 때 사용 가능한 디스크 공간이 x%(10%?) 미만이라면, Discourse가 자동으로 백업을 “실패” 처리(알림 생성)하도록 하는 것이 어떨까요? 이렇게 하면 디스크 공간이 이미 부족한 경우 백업을 시작조차 하지 않을 수 있습니다.

참고로, 만약 이것이 정말로 일어난 일이라면, 7월 11일에 발생한 첫 번째 실패한 백업을 보면 사용 가능한 디스크 공간이 약 40%(약 32GB!!!)였는데도 백업을 성공적으로 완료할 수 없었습니다. 이것이 맞나요?! 백업을 생성할 때 Discourse가 왜 그렇게 과도한 임시/작업 공간이 필요한 것일까요?

어젯밤에 반드시 더 진행되었다고 할 수는 없습니다. 단순히 “경주에서 졌을” 뿐입니다. 공간이 부족해지면 어떤 구성 요소가 먼저 영향을 받느냐에 따라 결과가 달라집니다.

백업에 실패하면 메시지를 보내려고 시도할 가능성이 높다고 생각합니다. 하지만 디스크 공간이 부족하면 성공하지 못할 수도 있습니다. :scream:

고정된 비율만으로는 큰 정보를 제공하지 않습니다. 데이터베이스가 업로드에 비해 매우 작을 수도 있고, 그 반대일 수도 있으며, 썸네일을 포함할지, 업로드를 포함할지 여부에 따라 변수가 생기기 때문입니다. 사이트 환경에 맞게 조정할 수 있도록 설정 가능한 여유 공간 요건을 도입하는 방안도 생각해 볼 수 있겠습니다.

"과도하다"고 판단하신 기준은 잘 모르겠지만, 제 생각에는 과도하지 않습니다.

그럴 수 있겠네요. 말씀하신 대로 변수가 많으니까요.

아, “올바른” 방법은 백업에 필요한 공간 양을 계산하는 것 등이겠죠. 하지만 최대한 간단하게 유지하려면, 네, 그냥 고정된 비율(%)을 사용하는 것이 좋습니다. 다만 이렇게 생각해보면… 두 가지 선택지가 “사이트가 완전히 충돌하여 오프라인이 될 수 있다”와 “완벽하지는 않지만 문제를 빠르게 해결할 수 있는 임시 조치”라면, 저는 후자를 선택하겠습니다. 감사합니다. :wink:

그리고 감사의 말씀도 드리고 싶은데, 마이그레이션 관련해서 그리고 이 문제에 대한 의견까지 주셔서 정말 감사합니다. :+1:t2:

백업에 필요한 용량을 추정하는 것은 컴퓨터 과학에서 가장 어려운 문제 중 하나입니다… 진행률 표시줄의 먼 친척격이죠. :wink:

진지하게 말씀드리면, 백업의 일부는 데이터베이스 덤프이며, 이를 사전에 추정하는 방법이 무엇인지 모르겠습니다. 이미지가 충분히 많아서 용량이 문제가 되는 경우, 백업 아카이브에 이미지를 포함하는 것은 아마도 일반적인 관행 밖의 일이 될 것입니다.

일반적으로 시스템 관리의 경우, 자유 용량 모니터링과 백업 상태 관리는 애플리케이션의 부담보다는 관리자의 부담으로 여겨져 왔습니다. 이는 사람들이 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

이 호스트에서 공유 디렉터리가 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에 수많은 "수정 방안"을 제안하기 전에 Discourse 백업 크론이 실제 문제의 원인임을 100% 확실하게 확인하는 것이 매우 중요합니다.

현재 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, 코어 파일 등 호스트 파일 시스템에서 파일 시스템을 가득 채울 수 있는 다른 많은 장소가 있을 수 있습니다.

하루에 한 번씩 백분율 스파이크가 발생하는 그래프만으로는 Discourse 백업 크론 프로세스가 근본 원인이라고 단정할 수 있는 근거가 충분하지 않습니다. 그럴 수도 있지만, 지금까지의 증거에 기반하면 아닐 수도 있습니다!

정말 좋습니다. 말씀해 주신 것들을 모두 시도해 보겠습니다. 감사합니다.

네, 분명 백업 관련 문제입니다.

아니요, 증거는 충분합니다: 예외 하나를 제외하고 스파이크가 2일 간격으로 발생하며, 백업 빈도도 2일로 설정되어 있습니다. 과거 메타(Meta)에서의 경험에서도 정확히 동일한 장애 패턴이 확인된 바 있습니다.

네, 앞으로 진행하기 위한 훌륭한 계획입니다. 다만, VPS에서 디스크 용량 한계에 부딪히기 시작하는 사람들에게 첫 번째 권장 사항은 S3 메커니즘을 활용한 머신 외부 업로드 저장입니다.

@pnoeric 님은 이미지를 위해 S3에서 나오려는 중이시므로, S3 안에 있는 백업에 모든 이미지의 여러 사본을 저장하는 것은 S3에서 나오려는 목적을 달성하지 못합니다. @pnoeric 님, 이건 제게 혼란을 줍니다 — S3에서 나오려고 하시면서, 모든 이미지를 S3에 여러 백업 사본으로 저장하고 있기 때문에 파일의 일부만 S3에서 옮기려는 것이라면, 그 의의는 무엇인가요?

어쨌든, 저는 대안들이 어떤지 보여드리려 했습니다. 백업은 어렵습니다. 특히 백업에서 _복원_할 수 있기를 원한다면 더더욱 그렇습니다.

저는 서버 공간이 충분해지고, S3에 머물 가치가 없을 정도로 성장이나 트래픽이 크지 않아서 “S3”(제 경우 디지털 오션 스페이스)에서 나왔습니다. 하지만 저는 특이한 케이스인 것 같아서, 아마도 S3에서 마이그레이션 시 데이터 손상 문제를 해결하는 제 PR에 대한 리뷰 한 마디도 받지 못한 이유일 겁니다. :stuck_out_tongue: 그래서 제 백업 방식이 매우 비정상적일 것으로 예상합니다.

제 상황은 이미지가 많아 사람들이 그 이미지들을 볼 때 상당한 전송 대역폭이 발생한다는 점입니다… 그래서 이미지가 Amazon S3에 있을 때, 대역폭 비용이 정말 치명적이었습니다. 특히 이미지의 모든 것을 DO 드롭렛에 저장하면 이미 지불하고 있는 대역폭/저장소 요금에 포함될 수 있다는 사실을 깨달았을 때 더더욱 그랬습니다. (미래의 어느 시점에 S3로 되돌리는 것이 합리적일 수도 있고, 아니면 DO 드롭렛을 다시 늘리는 것이 더 합리적일 수도 있겠지만…)

그래서 처음에는 S3를 사용하다가 제 실수를 깨달았습니다. 그래서 현재는 여러분의 훌륭한 코드를 사용하여 S3의 모든 이미지를 DO로 이전하고 있습니다.

S3에 전체 백업(이미지 포함)을 유지하는 것은 전혀 다른 이야기입니다. S3에는 "콜드 스토리지"로 저장되어 문제가 발생하지 않는 한 접근되지 않으므로, 큰 대역폭 비용이 발생하지 않습니다.

또한: 백업/디스크 사용 상황에 대해 더 생각해 보았습니다. 여전히 여기서는 뭔가 빠져 있다고 생각합니다. 아마도 경고 메시지나 더 나은 문서화가 필요할 것입니다. 제 Discourse는 디스크 용량의 60%만 사용 중이었지만, 오프사이트 백업이 실패하고 있었습니다. 필요한 디스크 공간에 대한 추정치, 또는 디스크 공간이 부족할 경우의 경고, 혹은 무언가가 현재와 같은 상황(공간이 부족할 때 발생하는 일: 며칠 동안 백업이 되지 않고, 그 후 포럼이 완전히 오프라인이 되는 하드 크래시)보다는 낫지 않을까 싶습니다. :-\

(@riking도 "백업은 이 유형의 장애의 일반적인 원인"이라고 말했습니다. 즉, 잠재적 문제에 대한 경고 없이 백업 실패로 인해 Discourse 인스턴스가 정기적으로 크래시하는 건가요?)

이를 매우 간단하게, 30,000피트 높이에서 내려다보는 관점에서 다시 말하자면: 소프트웨어의 기본 기능(자동 백업)이 전체 시스템을 오프라인으로 만들 수 있다면 그것은 설계상의 결함으로 보입니다. 특히 백업을 준비하기 위해 디스크 공간을 사용하는 기능일 뿐, 같은 디스크에 저장하지도 않는 상황에서요.

아니요, 그는 어떤 소프트웨어를 사용하여 어떤 서버에서든 백업을 수행할 경우 디스크가 가득 차 문제를 일으킬 수 있다는 의미였습니다.

맞는 말이지만, 그래서 S3 앞에 CDN을 두는 겁니다. S3에서 이미지를 직접 서빙하면 비용이 터무니없이 비싸져요 :scream:. Cloudfront이나 심지어 CloudFlare를 사용해 S3 앞에 CDN을 두는 건 꽤 쉽습니다. CloudFlare의 무료 플랜으로도 이를 달성할 수 있어요.

그리고 로컬에 저장하는 것도 꽤 좋지 않은 선택입니다. VPS를 불필요하게 확장해야 하게 되거든요. 로컬 SSD는 훨씬 비싸질 거예요.

아, 알겠습니다. 이해했어요.

그럼 Discourse가 백업을 준비하는 데 필요한 디스크 공간이 얼마나 될지 어떻게 알 수 있을까요? 소프트웨어가 알려주지 않으니, 내일 갑자기 500GB가 필요해져서 Digital Ocean 서버가 다시 오프라인이 될지도 모릅니다. :man_shrugging:t2: 적어도 대략적인 계산을 할 수 있다면 상황을 파악해 볼 수 있을 것 같아요.

와, 정말 좋은 아이디어네요. 그런 방법은 생각해 본 적이 없었습니다. 그러면 제 Amazon 버킷에 CDN을 적용하고, Discourse에 모든 에셋을 S3에서 사용하도록 설정하면 되는 건가요? (이전처럼요? ㅋㅋ)