메모리 부족으로 3.2.0.beta3-dev에서 3.2.0.beta3 업그레이드 실패

안녕하세요,

프롬프트에 따라 3.2.0.beta3-dev에서 3.2.0.beta3로 업그레이드를 시도했는데, 에셋의 엠퍼(ember) 빌드 중 메모리 부족으로 인해 Discourse 인스턴스가 손상되었습니다. ./launcher rebuild app 명령을 실행해도 동일한 결과가 나타났습니다.

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb83f50 node::Abort() [ember]
 2: 0xa94834  [ember]
 3: 0xd647c0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [ember]
 4: 0xd64b67 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [ember]
 5: 0xf42265  [ember]
 6: 0xf5474d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [ember]
 7: 0xf2ee4e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [ember]
 8: 0xf30217 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [ember]
 9: 0xf113ea v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [ember]
10: 0x12d674f v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [ember]
11: 0x17035b9  [ember]
Aborted (core dumped)
error Command failed with exit code 134.
I, [2023-11-26T17:19:26.345389 #1]  INFO -- : yarn run v1.22.19
$ /var/www/discourse/app/assets/javascripts/node_modules/.bin/ember build
Environment: development
WARNING: ember-test-selectors: You are using an unsupported ember-cli-babel version. data-test properties are not automatically stripped from your JS code.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

비영리 단체를 위해 1GB 메모리를 가진 DigitalOcean 인스턴스에서 실행 중이라, 메모리를 늘리기 위해 리사이즈할 여유가 없습니다. 1GB는 Discourse의 최소 사양이며, 이전 버전들은 문제없이 실행되었습니다. 다시 정상적으로 실행할 수 있는 방법에 대한 아이디어가 있을까요?

스왑 공간이 있나요?

free -h

명령의 출력 결과는 무엇인가요?

               total        used        free      shared  buff/cache   available
Mem:           952Mi       321Mi       414Mi       3.1Mi       374Mi       631Mi
Swap:          2.0Gi        75Mi       1.9Gi

리빌드하는 동안에만 리사이즈하면 됩니다.

경쟁력 있는 가격과 기본 플랜에서 2GB RAM을 제공하는 Hetzner로 이사를 고려해 볼 수도 있습니다.

안녕하세요, @andreid님 :slight_smile:

저도 최근 재빌드 시 1GB DO 테스트 사이트에서 메모리 문제를 겪고 있습니다. 문제를 해결하기 위해 임시로 2GB로 업그레이드했습니다.

이제 문서에 있는 최소 요구 사양을 2GB RAM으로 업데이트하는 것이 가치가 있을지도 모르겠네요?

작년에 이런 일이 발생한 적이 있었고, 몇 가지 조치가 이루어졌던 것으로 기억합니다. JavaScript heap out of memory due to Ember CLI - #4 by JammyDodger. 이번에도 뭔가 할 수 있을지는 모르겠지만, 물어볼 예정입니다. :+1:

@RGJ와 @JammyDodger에게 감사합니다. 임시로 크기를 조정하니 문제가 해결되었습니다.

디스크 공간이 충분하다면, 1GB의 스왑 공간을 추가하는 것은 기능적으로 1GB의 RAM을 추가하는 것과 동일합니다. (업그레이드 실행 시간이 더 걸릴 수 있지만, 이는 기능 문제가 아닌 성능 문제입니다. 궁극적으로 원하는 것은 메모리 부족 상황을 피하는 것입니다.)

Discourse 측에서 문제를 완화하는 데 도움이 될 수 있는 추가 정보를 공유합니다. 제 인스턴스(DigitalOcean ~1GB 드롭렛, 스왑 2GB)는 최근 재빌드 시간이 눈에 띄게 길어졌으며, 4번 중 3번꼴로 동일한 치명적 오류가 보고되고 있습니다(./launcher cleanup를 실행한 뒤에는 운이 좋아지는 것 같지만, 이를 확인할 만큼 표본 수가 충분하지는 않습니다).

힙 아웃 오브 메모리 오류가 발생하기 직전, 다음과 같은 로그가 기록됩니다:

Node.js heap_size_limit (491.0) is less than 1024MB. Setting --max-old-space-size=1024.
Node.js heap_size_limit (491.0) is less than 2048MB. Disabling Webpack parallelization with JOBS=0 to conserve memory.

이 부분은 제 전문 영역이 아니므로, 잘못 짚은 부분이 있을 수 있습니다. 간단한 조사를 해본 결과, ember-cli가 node.js에 의존하고 있어 이 문제가 관련이 있다고 생각합니다. --max-old-space-size 플래그는 RAM보다 더 높은 값으로 설정할 수 있습니다(이 경우 스왑 공간으로 넘어가며, 이 경우에는 문제가 되지 않습니다). 따라서 1024는 더 이상 재빌드를 감당할 수 없는 인공적인 상한선일 수 있습니다.

참고: --optimize-for-size는 메모리 사용량을 줄이는 데 도움이 되는 node.js 플래그로 알려져 있습니다(Discourse/ember에서 사용 중인지, 이미 사용 중인지 확실하지 않습니다). 또한, 특정 node.js 사용 환경에서 가비지 컬렉터가 활성화되지 않는다는 사례가 있어 이것이 문제가 될 수 있습니다.

이 중 일부가 Discourse 측에서 ember/node.js 사용과 관련하여 관련이 있고 제어할 수 있다면, 누군가가 조사해 볼 가치가 있을 것입니다. 그렇지 않다면 걱정하지 마시고, 위에서 제안한 임시 2GB 업그레이드 솔루션을 진행하겠습니다. :slight_smile:

매우 좋은 지적입니다! 현재 저사양(Low-RAM) 머신에서는 여기에서 이를 1024mb로 설정하고 있습니다. 1500 또는 2000으로 늘리는 실험을 해보고 도움이 되는지 확인할 수 있습니다.

직접 시도해 보고 싶으시다면, app.yml 파일의 env: 섹션에 새 변수를 추가하여 설정할 수 있습니다:

수정: :warning: 이제 이것이 디스코스의 기본값입니다. 직접 설정할 필요가 없습니다.

  NODE_OPTIONS: "--max-old-space-size=2048"

아, 완벽하네요! 바로 시도해 보았습니다.

치명적인 오류가 매번 발생하는 것은 아니고, 최근에는 재빌드에 약 25분(이전 5~10분에서 증가)이 걸리기 때문에, 이 서버 사양에서 해당 수치를 늘리는 것이 메모리 문제를 해결하는지 확인하려면 시간이 좀 걸릴 것 같습니다.

하지만 이미 두 개의 Node.js heap_size_limit 경고가 더 이상 재빌드 로그에 표시되지 않고, 첫 번째 재빌드가 성공적으로 완료되었으므로 좋은 징조입니다.

수정: 위에서 언급한 app.yml의 NODE_OPTIONS 설정 덕분에 여러 번 재빌드해도 문제가 없었습니다. 좋아요!

수정2: 이 해결책은 그 마법 숫자 (데이비드의 게시물에서 가져온 링크)를 늘리는 방식으로 Discourse에 반영되어야 할 것 같습니다. 이렇게 하면 다른 저사양 RAM 머신들도 계속 작동할 수 있을 테니까요. 만약 이를 어떻게 해야 하는지 아는 분이 이 글을 보신다면, 정말 좋겠습니다. :slight_smile:

저희도 https://caddy.community 에서 같은 문제를 겪었습니다.

./launcher rebuild app를 몇 번 실행해 보았지만, 여러 가지 문제로 인해 실패했습니다.

처음에는 bundle install에서 rbtrace에 대한 오류가 발생했습니다 (An error occurred while installing rbtrace (0.5.0), and Bundler cannot continue. 메시지로 종료되었습니다).

그 후 결국 다음과 같은 OOM(메모리 부족) 문제가 발생했습니다:

I, [2023-12-12T07:50:59.497921 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake themes:update assets:precompile'
Node.js heap_size_limit (1010.0) is less than 1024MB. Setting --max-old-space-size=1024.
Node.js heap_size_limit (1010.0) is less than 2048MB. Disabling Webpack parallelization with JOBS=0 to conserve memory.

<--- Last few GCs --->

[3683:0x5dab130]   279104 ms: Scavenge 981.3 (1037.1) -> 974.5 (1037.1) MB, 8.3 / 0.0 ms  (average mu = 0.699, current mu = 0.681) allocation failure; 
[3683:0x5dab130]   279136 ms: Scavenge 981.8 (1037.1) -> 975.0 (1037.1) MB, 8.0 / 0.0 ms  (average mu = 0.699, current mu = 0.681) allocation failure; 
[3683:0x5dab130]   282606 ms: Mark-sweep 994.8 (1050.6) -> 987.7 (1048.9) MB, 3316.1 / 0.0 ms  (average mu = 0.593, current mu = 0.501) allocation failure; GC in old space requested


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb83f50 node::Abort() [ember]
 2: 0xa94834  [ember]
 3: 0xd647c0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [ember]
 4: 0xd64b67 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [ember]
 5: 0xf42265  [ember]
 6: 0xf5474d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, [snip]
Aborted (core dumped)
error Command failed with exit code 134.

마지막으로 ./discourse_doctor를 실행하니 결국 그 문제를 넘어갈 수 있었습니다 (왜 그랬을까요? 후속 실행 시 캐시에 더 많은 내용이 저장되어 메모리 사용량이 줄어든 걸까요? :thinking:)

I, [2023-12-12T08:02:50.556442 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake themes:update assets:precompile'
Node.js heap_size_limit (1010.0) is less than 1024MB. Setting --max-old-space-size=1024.
Node.js heap_size_limit (1010.0) is less than 2048MB. Disabling Webpack parallelization with JOBS=0 to conserve memory.
110:M 12 Dec 2023 08:07:50.026 * 100 changes in 300 seconds. Saving...
110:M 12 Dec 2023 08:07:50.030 * Background saving started by pid 3706
3706:C 12 Dec 2023 08:07:51.292 * DB saved on disk
3706:C 12 Dec 2023 08:07:51.294 * Fork CoW for RDB: current 1 MB, peak 1 MB, average 1 MB
110:M 12 Dec 2023 08:07:51.334 * Background saving terminated with success
Purging temp files
Bundling assets

하지만 이것은 우리가 겪어야 했어야 할 마찰이 아니었습니다. 앞으로 이 부분이 개선되기를 바랍니다.

참고로:

# free -h
              total        used        free      shared  buff/cache   available
Mem:          1.9Gi       1.3Gi        87Mi       138Mi       593Mi       394Mi
Swap:         2.0Gi       337Mi       1.7Gi

물론이죠. 그래서 여기서 정보를 수집하고 있습니다.

NODE_OPTIONS 환경 변수를 조정하는 것만으로도 충분해 보이므로, 앱의 종속성 중 하나나 V8의 변경 사항으로 인해 이전 값이 더 이상 작동하지 않게 된 것 같습니다.

@david 어떻게 생각하시나요?

나쁘지 않아 보입니다! 물론 30분 이상 걸리는 재빌드는 여전히 이상적이 아니므로, 가까운 미래에 개선될 수 있기를 바랍니다. 하지만 이 방법은 문제를 일단 막는 데 좋은 해결책인 것 같습니다.

Postgres 버전 16은 버전 13에 비해 더 적은 공간을 차지하고 훨씬 더 잘 최적화되어 있다는 점에 주목할 가치가 있습니다. 이는 서버가 소비하는 총 메모리 양을 줄일 수 있습니다.

오늘도 2GB + 2GB 스왑 설정으로 작은 사이트에서 비슷한 재빌드 문제를 겪었습니다.

2GB + 4GB 스왑으로 확장하니 이번에는 무사히 넘어갔습니다.

참고로, 제 경우에는

을 app.yml에 추가해도 도움이 되지 않았습니다. 실제로 문제를 해결해 준 것은 단순히

sudo apt update
sudo apt upgrade

을 실행하는 것이었습니다.