memory-management

4 개의 포스트

pinterest

Pinterest의 Apache Spark에서 (새 탭에서 열림)

Pinterest는 대규모 Spark 환경에서 빈번하게 발생하는 OOM(Out-of-Memory) 오류를 해결하기 위해 'Auto Memory Retries' 기능을 도입했습니다. 이 시스템은 태스크 수준에서 리소스 요구량을 동적으로 판단하고, 실패 시 더 큰 메모리 프로필을 가진 실행기(Executor)에서 태스크를 재시도하도록 자동화합니다. 이를 통해 수동 튜닝의 번거로움을 줄이고 자원 효율성을 높여 전체적인 작업 실패율과 운영 비용을 획기적으로 낮추는 성과를 거두었습니다. ### 기존 Spark 리소스 관리의 한계와 문제점 * Pinterest의 Spark 클러스터는 하드웨어 대비 높은 메모리 요구량으로 인해 OOM 오류가 잦았으며, 전체 작업 실패 원인의 약 4.6%가 메모리 부족에서 기인했습니다. * 사용자가 모든 스테이지와 태스크의 메모리 요구량을 정확히 예측하여 수동으로 설정하는 것은 매우 어렵고 시간이 많이 소요되는 작업입니다. * 데이터 스큐(Skew) 현상으로 인해 같은 스테이지 내에서도 특정 태스크만 과도한 메모리를 사용하는 경우가 많아, 모든 태스크를 최대치에 맞춰 설정하면 심각한 자원 낭비가 발생합니다. * 제품 팀의 우선순위 문제로 인해 비용 절감을 위한 수동 최적화가 지속적으로 이루어지기 어려운 구조적 한계가 있었습니다. ### Auto Memory Retries의 단계별 대응 전략 * **CPU 할당량 증설을 통한 메모리 확보 (1단계):** 실행기에 1개 이상의 코어가 있는 경우, OOM 발생 시 첫 번째 재시도에서 태스크당 CPU 할당량(`spark.task.cpus`)을 두 배로 늘립니다. 이를 통해 실행기 내 동시 실행 태스크 수를 줄여 개별 태스크가 사용할 수 있는 공유 메모리 공간을 즉각적으로 확보합니다. * **물리적으로 큰 실행기 투입 (2단계):** CPU 조절만으로 해결되지 않거나 단일 태스크가 이미 실행기 전체 메모리를 사용 중인 경우, 물리적으로 더 큰 메모리를 가진 새로운 실행기를 동적으로 런칭합니다. * **하이브리드 확장 프로필 적용:** 기본 설정의 2배, 3배, 4배 크기의 리소스 프로필을 미리 등록하고 단계별로 순차 적용합니다. Apache Gluten을 사용하는 워크로드의 경우 Off-heap 메모리도 함께 증설하여 가속화된 연산을 지원합니다. ### 시스템 구현 및 Spark 엔진 확장 * **태스크 수준의 리소스 프로필:** 기존 Spark의 고정된 리소스 할당 방식에서 벗어나, `Task` 객체에 개별 리소스 프로필 ID(`taskRpId`)를 저장할 수 있도록 확장하여 동일한 TaskSet 내에서도 태스크마다 사양을 다르게 가질 수 있게 구현했습니다. * **스케줄링 로직 최적화:** `TaskSetManager`는 OOM 감지 시 즉시 상위 프로필을 할당하며, `TaskSchedulerImpl`은 증설된 CPU 속성을 가진 태스크를 기존 실행기에서 우선 실행할 수 있게 하여 리소스 재사용 속도를 높였습니다. * **동적 리소스 할당:** `ExecutorAllocationManager`가 상위 프로필을 필요로 하는 대기 태스크를 실시간으로 추적하고, 물리적으로 큰 실행기가 필요한 시점에 맞춰 Kubernetes 등에 자원을 요청합니다. * **사용자 경험 개선:** 사용자가 어떤 태스크가 더 많은 자원을 사용했는지 쉽게 파악할 수 있도록 Spark UI의 태스크 목록에 리소스 프로필 ID를 표시하는 기능을 추가했습니다. 효율적인 Spark 운영을 위해서는 모든 작업을 최대 메모리 요구량에 맞추기보다, 상위 90%(P90) 수준의 일반적인 설정으로 실행하고 예외적인 태스크만 'Auto Memory Retries'로 구제하는 탄력적 전략이 권장됩니다. 이는 데이터 스큐가 심한 대규모 파이프라인에서 운영 안정성을 확보함과 동시에 인프라 비용을 최적화할 수 있는 강력한 해법이 될 것입니다.

datadog

수백 개의 파드에서 Go 1.24 메모리 회귀를 추적해 찾아낸 방법 (새 탭에서 열림)

Go 1.24로의 업그레이드 이후, 새로운 맵 구현인 스위스 테이블(Swiss Tables)에 대한 기대와 달리 일부 서비스에서 메모리 사용량(RSS)이 약 20% 증가하는 현상이 발견되었습니다. 조사 결과, Go 런타임 내부의 메모리 관리 지표는 안정적이었으나 시스템 레벨의 실제 물리 메모리 점유가 늘어난 것으로 확인되었습니다. 이는 Go 1.24에서 진행된 `mallocgc` 함수의 리팩토링 과정에서 발생한 미묘한 메모리 할당자 회귀(Regression) 현상이 원인이었습니다. ### 런타임 지표와 시스템 지표의 불일치 * Go 1.24 업그레이드 후 데이터 처리 서비스의 RSS(Resident Set Size)가 눈에 띄게 증가했으나, Go 런타임 지표와 힙 프로파일상에는 아무런 변화가 기록되지 않았습니다. * 이는 Go 런타임 입장에서는 메모리를 더 사용하고 있지 않다고 판단하지만, 운영체제(Linux) 입장에서는 프로세스가 더 많은 물리 메모리를 점유하고 있는 상태임을 의미합니다. * Kubernetes의 메모리 제한(Limit)이나 OOM 킬러는 시스템 지표인 RSS를 기준으로 작동하기 때문에, 런타임 지표에 나타나지 않는 이러한 증가는 서비스 안정성에 치명적일 수 있습니다. ### 주요 변경 사항에 대한 가설 검증 * 먼저 Go 1.24의 핵심 변화인 '스위스 테이블'과 '스핀 비트 뮤텍스(Spin bit mutex)'를 원인으로 의심하고 실험을 진행했습니다. * `GOEXPERIMENT=noswissmap` 및 `GOEXPERIMENT=nospinbitmutex` 플래그를 사용하여 해당 기능들을 각각 비활성화한 후 빌드하여 배포했으나, 메모리 증가 현상은 해결되지 않았습니다. * 이를 통해 이번 문제는 새로운 기능 자체가 아니라, 런타임의 더 깊은 곳에서 발생한 변화 때문임을 확인했습니다. ### 가상 메모리와 물리 메모리의 매핑 분석 * 리눅스의 `/proc/[pid]/smaps` 파일을 분석하여 프로세스의 메모리 영역별 가상 메모리(Size)와 물리 메모리(RSS)의 차이를 추적했습니다. * 분석 결과, Go 1.23에서는 힙 영역의 RSS가 가상 메모리 크기보다 약 300 MiB 낮게 유지되었으나, Go 1.24에서는 가상 메모리 크기와 RSS가 거의 일치하는 현상이 발견되었습니다. * 결과적으로 Go 1.24의 런타임이 이전 버전보다 가상 메모리를 실제 물리 RAM에 더 공격적으로 할당(Commit)하고 있다는 사실을 밝혀냈습니다. ### mallocgc 리팩토링과 할당자 이슈 * Go 1.24 변경 로그를 정밀 분석한 결과, 메모리 할당의 핵심 로직인 `mallocgc` 함수에 대대적인 리팩토링이 있었음을 확인했습니다. * 이 과정에서 발생한 의도치 않은 로직 변화가 할당된 메모리를 실제 물리적 공간에 매핑하는 방식에 영향을 주어 RSS 상승을 유도한 것으로 파악되었습니다. * 작성자는 이 문제를 Go 개발 팀과 공유하여 원인을 확인했으며, 이는 런타임 리팩토링으로 인한 성능 회귀의 일종으로 결론지어졌습니다. Go 1.24 업그레이드를 고려 중인 팀은 런타임 내부 지표(Heap usage)뿐만 아니라 시스템 레벨의 RSS 지표를 면밀히 모니터링해야 합니다. 비록 메모리 할당자에서 미묘한 RSS 증가가 관측되었지만, 동시에 도입된 스위스 테이블은 대규모 인메모리 맵을 사용하는 서비스에서 수백 기가바이트의 메모리를 절약할 수 있는 잠재력을 가지고 있으므로 서비스 특성에 따른 비교 분석이 필요합니다.

datadog

수백 개의 파드에서 (새 탭에서 열림)

제공된 내용에는 본문이 포함되어 있지 않고, Datadog 웹사이트의 메뉴 목록과 링크 정보만 있습니다. 따라서 글의 주장, 기술적 접근법, 결론을 정확히 요약할 수 없습니다. 확인되는 정보로는 글의 URL에 `go-memory-regression`이 포함되어 있어 Go 애플리케이션의 메모리 회귀 문제를 다룬 글일 가능성이 있다는 점뿐입니다. 본문 요약을 위해서는 다음 중 하나를 보내 주세요. - 블로그 본문 전체 - 본문이 포함된 HTML 또는 Markdown - 글의 실제 텍스트가 보이는 캡처나 링크 내용 현재 제공된 메뉴에는 인프라 모니터링, APM, 로그 관리, 보안, RUM, CI/CD, AI 등 Datadog 제품 내비게이션만 포함되어 있으며, 기술적인 설명이나 분석 내용은 없습니다.

discord

디스코드에서 수백만 (새 탭에서 열림)

디스코드(Discord)는 서비스 초기 광범위한 호환성을 위해 32비트 아키텍처를 선택했으나, 현대적인 컴퓨팅 환경에 발맞춰 64비트 전환의 필요성을 강조하고 있습니다. 32비트는 단일 버전으로 거의 모든 윈도우 환경을 지원할 수 있다는 장점이 있었지만, 엄격한 메모리 제한으로 인해 발생하는 크래시 문제와 라이브러리 지원 중단이라는 한계에 봉착했습니다. 결과적으로 디스코드는 더 높은 안정성과 성능을 제공하기 위해 최신 하드웨어 표준인 64비트 아키텍처로의 이전을 추진하고 있습니다. ### 초기 32비트 선택의 배경과 이점 * **광범위한 호환성**: 2015년 출시 당시 디스코드는 윈도우의 하위 호환성 레이어를 활용해 32비트와 64비트 기기 모두에서 작동하는 단일 앱 버전을 유지하고자 했습니다. * **개발 효율성**: 하나의 실행 파일만 관리하면 되었기에 초기 개발 단계에서 리소스를 집중하고 사용자 접근성을 높이는 데 유리했습니다. * **적은 메모리 사용량**: 이론적으로 32비트 애플리케이션은 64비트에 비해 포인터 크기가 작아 메모리를 덜 사용하는 특성이 있습니다. ### 32비트 아키텍처의 기술적 한계 * **메모리 주소 지정 제한**: 32비트 애플리케이션은 사용할 수 있는 메모리 양에 물리적인 상한선이 존재합니다. 64비트 기기에서 실행하더라도 이 제한을 초과하면 성능 저하나 예기치 않은 크래시가 발생합니다. * **성능 저하 및 오류**: 디스코드가 고도화됨에 따라 메모리 집약적인 작업이 늘어났고, 32비트의 한계치에 도달하여 사용자 경험을 해치는 사례가 빈번해졌습니다. ### 64비트 전환의 필연성 * **라이브러리 생태계의 변화**: 디코드의 기반이 되는 Electron, WebRTC와 같은 주요 라이브러리들은 이미 수년 전부터 64비트를 기본 아키텍처로 채택하고 있습니다. * **유지보수 및 보안 리스크**: 업계 표준이 64비트로 이동함에 따라 32비트 라이브러리에 대한 버그 수정이나 최적화가 줄어들고 있으며, 이는 장기적으로 잠재적인 보안 취약점과 비효율성에 노출될 위험을 높입니다. * **미래 지향적 최적화**: 64비트 환경에서는 더 많은 시스템 자원을 안정적으로 활용할 수 있어, 인게임 오버레이와 같은 고성능 기능을 더욱 매끄럽게 구현할 수 있습니다. 데스크톱 애플리케이션 개발 시 초기에는 32비트의 범용성이 매력적일 수 있으나, 서비스의 규모가 커지고 현대적인 라이브러리를 지속적으로 활용해야 한다면 64비트 전환은 선택이 아닌 필수입니다. 안정적인 메모리 관리와 커뮤니티의 기술 지원을 받기 위해서는 하드웨어 표준에 맞춘 아키텍처 업데이트가 반드시 선행되어야 합니다.