PostgreSQL

60 개의 포스트

datadog원문

Arm64 JIT 컴파일러 버그를 드러낸 PostgreSQL 세그멘테이션 오류 파헤치기 (새 탭에서 열림)

Postgres 서버에서 발생한 'Segmentation fault(signal 11)' 오류의 원인을 추적하여, 이것이 Postgres 자체의 결함이 아니라 Arm64 아키텍처 환경에서 작동하는 LLVM(JIT 컴파일러)의 버그임을 밝혀낸 과정을 다루고 있습니다. 대규모 파티션 테이블을 조회할 때 JIT가 활성화되면서 크래시가 발생했으며, 이를 통해 업스트림 LLVM의 문제를 해결하는 성과를 거두었습니다. ## JIT 컴파일과 크래시의 상관관계 * **세그멘테이션 폴트 발생**: 최신 버전의 Postgres를 사용 중임에도 특정 쿼리(죽음의 쿼리)를 실행하면 서버가 즉시 종료되는 현상이 발생했습니다. * **스택 오염 확인**: 코어 덤프 분석 결과, 호출 스택(Backtrace)이 비정상적으로 짧고 깨져 있었으며, 이는 JIT 실행 함수인 `ExecRunCompiledExpr` 부근에서 문제가 발생했음을 시사했습니다. * **트리거 조건**: 64개의 파티션과 160만 개 이상의 행을 가진 대규모 테이블을 스캔할 때, Postgres의 비용 기반 휴리스틱에 의해 JIT 컴파일이 활성화되면서 오류가 유발되었습니다. ## Postgres JIT와 LLVM의 역할 * **성능 최적화**: Postgres는 반복적인 SQL 표현식 평가 오버헤드를 줄이기 위해 LLVM을 사용하여 런타임에 네이티브 머신 코드를 생성합니다. * **튜플 디포밍(Tuple Deforming)**: 디스크상의 데이터를 메모리 표현으로 변환하는 과정을 네이티브 코드로 컴파일하여 처리 효율을 극대화합니다. * **컴파일 오버헤드**: JIT는 실행 속도를 높이지만 컴파일 시간이 추가되므로, Postgres는 실행 비용이 높은 쿼리에 대해서만 선택적으로 JIT를 적용합니다. ## 문제 해결 및 근본 원인 파악 * **임시 조치**: `SET jit = off;` 설정을 통해 JIT 기능을 비활성화함으로써 쿼리 지연 시간의 큰 손해 없이 프로덕션 환경의 크래시를 즉시 중단시켰습니다. * **디버깅 결과**: 데이터 복제 및 로컬 환경 재현을 통해 분석한 결과, 특정 조건에서 LLVM이 Arm64 아키텍처용 머신 코드를 잘못 생성하는 버그가 있음을 확인했습니다. * **업스트림 기여**: 이 조사는 단순히 설정을 변경하는 것에 그치지 않고, 어셈블리 수준의 분석을 통해 LLVM 프로젝트의 코드 수정까지 이끌어내는 계기가 되었습니다. ## 권장 사항 Arm64 기반 클라우드 환경에서 Postgres를 운영 중인데 원인을 알 수 없는 Segmentation fault가 발생한다면, 우선적으로 JIT를 비활성화하여 안정성을 확보하십시오. 이후 시스템의 LLVM 라이브러리 버전을 확인하고 관련 아키텍처 패치가 적용되었는지 점검하는 것이 필요합니다.

datadog원문

엔지니어링 부문 VP 스포트라이트: 이보 디미트로프 (새 탭에서 열림)

데이터독(Datadog)의 엔지니어링 VP 이보 디미트로프(Ivo Dimitrov)는 30년 이상의 경력을 가진 베테랑으로서, 고성능 저수준 시스템 개발자에서 대규모 분산 시스템을 총괄하는 리더로 성장해 온 인물입니다. 그는 마이크로소프트와 링크드인에서 쌓은 대규모 스토리지 인프라 구축 경험을 바탕으로, 현재 데이터독에서 메트릭과 이벤트 플랫폼의 기술적 혁신을 이끌고 있습니다. 기술적 깊이와 조직적 비전 사이의 균형을 강조하는 그의 여정은 복잡한 데이터 시스템을 다루는 엔지니어와 관리자들에게 중요한 통찰을 제공합니다. ### 저수준 시스템 개발에서 엔지니어링 리더십으로의 전환 * 전기 공학 전공 중 실시간 운영체제(RTOS) 커널 기여를 통해 소프트웨어 개발에 입문했으며, 이후 10년간 C/C++ 기반의 고성능 시스템 프로그래밍에 집중했습니다. * 마이크로소프트의 Azure Blob Storage 초기 팀에서 근무하던 중 조직 개편을 계기로 관리직을 맡게 되었으며, 현장에서의 실무 교육과 멘토링을 통해 리더십 역량을 쌓았습니다. * 자신의 업무에만 집중하는 단계를 넘어 타인의 성장을 촉진하고 조직 간의 경계를 조율하는 '오너십(Ownership)'의 가치를 발견하며 매니지먼트의 매력을 느꼈습니다. ### 대규모 분산 스토리지 플랫폼 구축 경험 * 링크드인 재직 당시, 현재까지 전체 데이터셋의 95% 이상을 처리하는 독점 키-값(Key-Value) 저장소인 'Espresso'를 초기 단계에서 성숙한 플랫폼으로 성장시켰습니다. * 파생 데이터 서빙을 위한 'Venice', 오픈소스 블록 스토리지인 'Ambry', 클러스터 관리자인 'Helix' 등 인터넷 규모의 스토리지 인프라 프로젝트들을 주도했습니다. * 이러한 경험을 통해 대규모 레거시 환경의 제약에서 벗어나, 기술적 위험을 감수하고 빠르게 혁신할 수 있는 문화적 유연성의 중요성을 깨달았습니다. ### 데이터독의 분산 데이터 시스템과 기술적 지향점 * 현재 데이터독에서 메트릭(Metrics), 이벤트(Events), 로그 및 트레이스 등 반정형 데이터를 처리하는 분산 데이터 시스템 조직을 총괄하고 있습니다. * 온라인 분석 워크로드에 최적화된 특수 메인 메모리 데이터베이스인 'Driveline'을 통해 시계열 데이터 처리의 효율성을 극대화하고 있습니다. * 서로 다른 도메인별 API를 통합하는 '교차 플랫폼 쿼리(Cross-Platform Queries)' 팀을 운영하여, 고객과 엔지니어 모두가 통일된 인터페이스로 데이터에 접근할 수 있도록 추상화 계층을 구축 중입니다. * 전체 쿼리의 80% 이상을 차지하는 알람(Alerts) 플랫폼을 메트릭 및 이벤트 플랫폼과 통합하여 시스템의 일관성을 높이고 있습니다. **실용적인 제언** 개인 기여자(IC)에서 관리자로 전환할 때는 기술적 전문성을 포기하는 것이 아니라, 그 전문성을 바탕으로 조직의 비전을 설계하고 팀원들이 역량을 발휘할 수 있는 환경을 조성하는 데 집중해야 합니다. 특히 데이터독의 사례처럼 쿠버네티스(Kubernetes) 기반의 현대적 인프라와 실험을 장려하는 문화를 결합할 때, 기술적 부채를 최소화하면서도 폭발적인 성장을 뒷받침하는 시스템을 구축할 수 있습니다.

figma3분 읽기큐레이션 요약

대규모 실시간 데이터를

Figma의 실시간 데이터 서비스 LiveGraph는 사용자와 쿼리 증가, 데이터베이스 샤딩으로 기존 구조의 한계에 도달했다. Figma는 초기 로컬 캐시와 단일 PostgreSQL의 전역 변경 스트림에 의존하던 아키텍처를 100배 규모까지 확장할 수 있도록 근본적으로 재설계하려 했다. 새 설계의 목표는 성능과 안정성을 유지하면서 데이터베이스 샤드와 읽기·업데이트 부하를 독립적으로 확장하고, 사용자 영향 없이 점진적으로 마이그레이션하는 것이다. ## LiveGraph의 역할 - LiveGraph는 GraphQL과 유사한 쿼리를 구독하는 웹 API를 제공한다. - 쿼리 결과를 JSON 트리로 반환하며, 객체와 관계를 정의한 스키마와 특정 그래프 일부를 조회하는 뷰를 사용한다. - Figma의 커스텀 React Hook을 통해 데이터가 변경되면 프런트엔드가 자동으로 다시 렌더링된다. - 캔버스 공동 편집, 댓글, FigJam 투표 등 여러 협업 기능에서 최신 데이터를 유지하는 기반 역할을 한다. ## 규모 증가로 드러난 문제 - 2021년 이후 LiveGraph 세션 수가 3배 증가했다. - 최근 1년 동안 뷰 요청 수는 5배 늘어났고, 세션 하나의 처리 비용도 점점 커졌다. - 데이터베이스 역시 단일 PostgreSQL 인스턴스에서 여러 수직·수평 샤드 구조로 변화하고 있었다. - 따라서 문제는 단순히 각 LiveGraph 서버가 데이터베이스 변경 사항을 모두 수집하는 데 그치지 않고, 클라이언트 세션·읽기 요청·데이터베이스 업데이트가 동시에 증가하는 복합적인 확장성 문제였다. ## LiveGraph 100x의 설계 목표 Figma는 현재의 읽기 및 데이터베이스 업데이트 부하를 장기적으로 100배까지 처리하기 위한 “LiveGraph 100x” 계획을 시작했다. - **서비스 속도 유지** - 초기 로드 시간과 실시간 업데이트에 대한 SLO를 유지하거나 개선해야 했다. - **데이터베이스 확장 지원** - 수직 확장뿐 아니라 수평 샤딩도 기본적으로 지원해야 했다. - 샤드가 늘어나도 신뢰성과 성능이 저하되지 않아야 했다. - **독립적인 확장 수단 확보** - 클라이언트 읽기량이 증가할 때와 쿼리 업데이트량이 증가할 때 서로 다른 구성 요소를 확장할 수 있어야 했다. - **안전한 점진적 마이그레이션** - 기존 LiveGraph 사용자를 중단시키지 않고 단계적으로 구조를 개선해야 했다. ## 초기 아키텍처와 변경 스트림 초기 LiveGraph는 단일 PostgreSQL과 하나의 서버를 중심으로 구성됐다. - PostgreSQL의 논리적 복제 스트림은 WAL에 기록된 행 단위 변경 사항을 전달한다. - 각 변경에는 행의 변경 전·후 이미지와 단조 증가하는 시퀀스 번호가 포함된다. - LiveGraph는 이 스트림을 추적해 데이터 변경을 실시간 업데이트로 재사용했다. - 모든 LiveGraph 쿼리는 기본 데이터베이스인 primary를 조회했다. - 서버 내부에는 인메모리 쿼리 캐시가 있었고, PostgreSQL의 각 행 변경이 발생할 때마다 관련 쿼리 결과를 직접 수정했다. - 즉, 캐시는 전체 결과를 다시 계산하기보다 개별 mutation을 결과에 반영하는 방식이었다. ## 단일 데이터베이스 구조의 한계 초기 구조에서는 데이터베이스가 하나였기 때문에 변경 스트림의 전역 순서를 가정할 수 있었다. - 모든 변경 사항이 하나의 PostgreSQL 인스턴스에서 생성됐다. - 따라서 LiveGraph는 하나의 전역적으로 정렬된 업데이트 스트림을 처리하면 됐다. - 하지만 단일 PostgreSQL 인스턴스가 용량 한계에 도달하면서 데이터베이스를 여러 수직 샤드로 나누게 됐다. - 여러 샤드가 동시에 변경 사항을 생성하면서 업데이트의 전역 순서가 더 이상 보장되지 않았다. - 기존의 “하나의 전역 순서 스트림”이라는 가정은 샤딩된 데이터베이스 환경에서 유지될 수 없었다. ## 재설계가 필요해진 이유 - LiveGraph는 데이터베이스 확장에 맞춰 변경 사항 수집과 캐시 갱신 방식을 바꿔야 했다. - 수직·수평 샤딩 환경에서는 여러 변경 스트림을 안정적으로 처리해야 한다. - 읽기 요청과 실시간 업데이트가 서로 다른 속도로 증가하므로, 전체 시스템을 한 방식으로만 확장해서는 효율적이지 않다. - Figma는 데이터베이스 용량 문제에 신속히 대응하면서도 기존 서비스의 성능과 안정성을 유지할 수 있는 전략적 변경이 필요했다. 실무적으로는 단일 데이터베이스의 전역 순서와 중앙 캐시에 의존하는 실시간 시스템이 초기에는 단순하고 효율적이지만, 샤딩 단계에서는 변경 순서·캐시 일관성·부하 분리 문제를 별도로 설계해야 한다는 점을 보여준다.

원문 읽기(새 탭에서 열림)
figma4분 읽기큐레이션 요약

Figma 데이터베이스 팀이 대

Figma는 데이터베이스 규모가 2020년 이후 약 100배 성장하면서 단일 Postgres와 수직 분할만으로는 한계에 도달했다. 먼저 캐시, 읽기 복제본, 수직 파티셔닝으로 확장 여유를 확보했지만, 수 테라바이트 규모의 테이블과 급격히 증가하는 쓰기량 때문에 수평 샤딩이 필요해졌다. Figma는 새로운 데이터베이스로 전면 이전하기보다 기존 RDS Postgres 전문성과 데이터 일관성을 유지하는 점진적 수평 샤딩을 선택해 약 9개월 만에 확장 기반을 마련했다. ## 급격한 성장과 수직 파티셔닝의 한계 - Figma는 2020년 AWS의 가장 큰 물리 인스턴스에서 단일 Postgres를 운영했다. - 2022년 말에는 다음과 같은 분산 구조로 발전했다. - 캐시 - 읽기 복제본 - 약 12개의 수직 분할 데이터베이스 - “Figma 파일”, “조직”처럼 연관된 테이블 그룹을 별도 데이터베이스로 분리해 점진적으로 확장했다. - 수직 파티셔닝은 CPU 사용량을 낮추고 빠르게 확장 여유를 확보하는 데 효과적이었다. - 그러나 수직 분할의 최소 단위는 테이블 하나이므로, 하나의 테이블 자체가 지나치게 커지는 문제는 해결하지 못했다. ## 데이터베이스 병목을 정량적으로 측정 - Figma는 CPU뿐 아니라 다음 지표를 함께 모니터링했다. - 디스크 I/O - 테이블 크기 - 기록되는 행 수 - 데이터베이스별 처리 한계 - 과거 운영 데이터와 부하 테스트를 조합해 각 데이터베이스와 샤드의 “남은 확장 여유”를 예측했다. - 수 테라바이트와 수십억 개의 행을 가진 테이블에서는 Postgres의 `VACUUM` 작업이 안정성에 영향을 주기 시작했다. - `VACUUM`은 트랜잭션 ID 고갈을 방지하는 필수 백그라운드 작업이지만, 대형 테이블에서는 처리 부담이 커진다. - 쓰기량이 가장 많은 테이블은 AWS RDS가 제공하는 최대 IOPS에 곧 도달할 상황이었다. - 이 문제는 테이블을 다른 데이터베이스로 옮기는 수직 분할만으로는 해결할 수 없어 수평 샤딩이 요구됐다. ## 확장 설계의 목표 Figma는 단순히 데이터를 여러 데이터베이스에 나누는 것보다, 운영과 애플리케이션 변경 위험을 최소화하는 것을 중요하게 봤다. - **개발자 영향 최소화** - 기존의 복잡한 관계형 데이터 모델을 최대한 유지한다. - 애플리케이션 개발자가 대규모 데이터 접근 코드를 전면 수정하지 않도록 한다. - **투명한 확장** - 최초에 샤딩 호환성을 확보한 뒤에는, 향후 샤드를 추가할 때 애플리케이션 변경을 최소화한다. - **대규모 백필 회피** - 수개월이 걸릴 수 있는 전체 테이블 백필이나 전체 데이터 마이그레이션을 피한다. - **점진적 적용** - 빠르게 증가하는 테이블부터 단계적으로 적용한다. - 각 단계에서 위험을 검증해 대규모 장애 가능성을 낮춘다. - **롤백 가능성 확보** - 물리적 샤딩 이후에도 문제가 생기면 이전 상태로 되돌릴 수 있어야 한다. - **강한 일관성 유지** - 다운타임과 일관성 위험을 유발할 수 있는 이중 쓰기 방식을 피한다. - 거의 무중단에 가까운 확장을 목표로 한다. - **기존 역량 활용** - 이미 축적한 RDS Postgres 운영 경험과 도구를 활용해 새로운 저장소의 불확실성을 줄인다. ## 대체 데이터베이스 검토 - Figma는 수평 확장을 지원하는 여러 기술을 검토했다. - CockroachDB - TiDB - Spanner - Vitess - 그러나 새 데이터베이스로 전환하려면 기존 Postgres와 새 저장소 사이의 복잡한 데이터 마이그레이션이 필요했다. - 데이터 일관성과 안정성을 확보하면서 핵심 기능을 모두 이전하려면 상당한 시간이 필요했다. - Figma는 이미 RDS Postgres를 안정적이고 성능 좋게 운영하는 전문성을 갖고 있었으므로, 새로운 데이터베이스로 바꾸면 이 역량을 다시 구축해야 했다. - 성장 속도가 매우 빨라 남은 확장 여유가 수개월뿐이었기 때문에, 새로운 저장소를 도입하는 것은 기술적으로 가능하더라도 일정과 위험 측면에서 적합하지 않았다. ## NoSQL을 선택하지 않은 이유 - NoSQL은 기본적으로 수평 확장을 제공하지만, Figma의 데이터 모델과는 잘 맞지 않았다. - Figma는 복잡한 관계형 데이터와 여러 테이블 간 관계를 Postgres 위에서 활용하고 있었다. - NoSQL API만으로는 이러한 관계형 질의와 데이터 모델의 유연성을 동일하게 제공하기 어려웠다. - 따라서 애플리케이션 구조를 대규모로 재설계하는 대신, 기존 관계형 모델을 유지하면서 Postgres를 수평 확장하는 방향을 택했다. ## 실용적인 결론 데이터베이스 확장은 처음부터 수평 샤딩으로 시작하기보다, 캐시·읽기 복제본·수직 파티셔닝으로 단기 여유를 확보한 뒤 실제 병목을 측정하며 단계적으로 진행하는 것이 현실적이다. 특히 기존 데이터베이스에 대한 운영 역량과 강한 일관성이 중요하다면, 새로운 저장소로 전면 이전하기보다 현재 시스템을 유지한 채 점진적으로 샤딩하는 전략이 위험과 개발 비용을 줄일 수 있다.

원문 읽기(새 탭에서 열림)
datadog원문

셀프 서비스 분석 확장: 5,000명의 직원에게 힘을 실어주는 도구들 (새 탭에서 열림)

Datadog은 200명에서 5,000명 규모로 급격히 성장하는 과정에서 발생하는 데이터 병목 현상을 해결하기 위해, 모든 직원이 중앙 데이터 팀의 도움 없이 스스로 데이터를 활용할 수 있는 '셀프 서비스 분석' 체계를 구축했습니다. 오픈 소스 기술을 기반으로 데이터 수집부터 변환, 발견, 리포팅까지 이어지는 통합 툴킷을 제공함으로써 데이터 팀은 단순 운영 업무에서 벗어나 고부가가치 과제에 집중할 수 있게 되었으며, 전사적으로 데이터 기반의 의사결정 문화를 정착시키는 성과를 거두었습니다. ### 셀프 서비스 분석의 세 가지 기둥과 사용자 분류 * 셀프 서비스 분석은 모든 임직원이 중앙 팀의 개입 없이 스스로 데이터를 활용해 의사결정을 내리는 상태를 지향하며, 이는 '데이터(Data)', '도구(Tools)', '지식(Knowledge)'이라는 세 가지 핵심 요소로 뒷받침됩니다. * 사용자의 데이터 숙련도와 니즈에 따라 사용자를 세 가지 페르소나로 분류하여 맞춤형 환경을 제공합니다. * **탐험가(Explorers):** 잘 정돈된 데이터와 미리 구축된 리포트를 활용하는 일반 사용자. * **빌더(Builders):** 직접 쿼리를 작성하고 팀을 위한 대시보드를 생성하는 숙련된 사용자. * **전문가(Experts):** 새로운 데이터를 노출하고 비즈니스 로직을 유지하며 데이터 품질을 제어하는 고숙련 사용자. ### 데이터 제품화와 단일 진실 공급원(SSOT) 구축 * 엔지니어링, 마케팅, 영업, 인사 등 모든 부서가 동일한 데이터를 바라볼 수 있도록 중앙 집중화된 '단일 진실 공급원(Single Source of Truth)'을 확립했습니다. * 'Bring Your Own Data(BYOD)' 툴을 개발하여, 데이터를 생성하는 어떤 팀이든 이를 분석 환경에 직접 노출하고 공유할 수 있는 자율성을 부여했습니다. * 데이터의 신뢰성을 높이기 위해 강력한 명명 규칙(Conventions)을 적용하고, 상세한 문서화와 데이터 품질 모니터링 시스템을 통해 사용자가 데이터를 믿고 사용할 수 있는 환경을 조성했습니다. ### 기술적 셀프 서비스 툴 스택: 수집에서 발견까지 * **데이터 수집(Intake):** 내부 데이터 스토어 및 서드파티 도구와 연결되는 커넥터, 데이터 요청을 위한 유저 인터페이스, 파이프라인 가시성 및 알림 기능을 제공합니다. * **데이터 변환(Transformation):** 전사 데이터 분석가들이 dbt와 SQL을 사용해 각 부서의 비즈니스 로직을 직접 제어할 수 있는 개발 환경을 구축했습니다. 이를 통해 데이터 모델링 레이어의 일관성을 유지하면서도 부서별 자율성을 보장합니다. * **데이터 발견(Discovery):** 모든 데이터셋과 필드에 대한 검색 기능을 제공하며, 데이터 리니지(Lineage), 소유권, 민감도, 신뢰도 등 풍부한 메타데이터를 제공하여 사용자가 필요한 데이터를 쉽게 찾고 이해할 수 있게 합니다. ### 실용적인 결론 조직이 커질수록 데이터 팀의 인원을 늘리는 것만으로는 데이터 수요를 감당할 수 없습니다. Datadog의 사례처럼 데이터 자체를 하나의 '제품'으로 취급하고, 현업 담당자들이 직접 데이터를 가공하고 소비할 수 있는 인프라와 가이드라인을 제공하는 것이 확장성 있는 데이터 문화를 만드는 핵심입니다. 이를 위해서는 도구의 도입뿐만 아니라 데이터 품질에 대한 엄격한 기준 확립과 사용자 교육이 반드시 병행되어야 합니다.

figma4분 읽기큐레이션 요약

데이터베이스 아키텍처

Figma는 사용자와 기능 증가로 단일 PostgreSQL 데이터베이스의 CPU 사용률과 지연 시간이 급증하자, 장애 위험을 선제적으로 낮추기 위해 멀티 데이터베이스 구조로 전환했다. 단기적으로 인스턴스 확장, 읽기 복제본, PgBouncer 등을 도입했지만 쓰기 부하와 복제 지연 문제는 해결하지 못했다. 수평 샤딩이나 NoSQL 전환 대신, 연관된 테이블 그룹을 별도 데이터베이스로 옮기는 수직 파티셔닝을 장기 해법으로 선택했다. ## 단일 데이터베이스의 확장 한계 - Figma는 권한, 파일 정보, 댓글 등 대부분의 메타데이터를 하나의 대형 Amazon RDS 데이터베이스에 저장했다. - 데이터베이스 트래픽은 매년 약 3배씩 증가했다. - 2020년 피크 시간대 CPU 사용률이 65%를 넘었고, 사용량이 한계에 가까워질수록 지연 시간이 예측하기 어려워졌다. - 데이터베이스가 완전히 포화되면 Figma 전체가 작동을 멈출 수 있었기 때문에, 장애가 발생하기 전에 확장 문제를 해결할 필요가 있었다. ## 단기적인 안정화 조치 Figma는 장기적인 구조 변경을 준비하는 동안 약 1년의 추가 여유를 확보하기 위해 다음 조치를 시행했다. - RDS 인스턴스를 `r5.12xlarge`에서 `r5.24xlarge`로 확장해 CPU 처리 여력을 늘렸다. - 여러 개의 read replica를 구성해 읽기 트래픽을 분산했다. - 새로운 사용 사례에는 별도 데이터베이스를 사용해 기존 데이터베이스의 성장을 제한했다. - PostgreSQL 연결 풀러인 PgBouncer를 도입해 수천 개에 달하는 데이터베이스 연결이 주 데이터베이스에 미치는 영향을 줄였다. - PgBouncer는 애플리케이션과 RDS 사이에서 연결을 관리하고 재사용하는 계층으로 동작했다. ## 읽기 복제본만으로는 부족했던 이유 - 데이터베이스 사용량을 분석한 결과, 데이터 수집·수정·삭제와 같은 쓰기 작업도 상당한 부하를 차지했다. - 모든 읽기 요청을 replica로 옮길 수 없었다. - 일부 기능은 복제 지연(replication lag)에 민감해 최신 데이터가 반드시 주 데이터베이스에서 제공되어야 했다. - 따라서 읽기와 쓰기 양쪽 모두에서 원본 데이터베이스의 작업을 추가로 분산해야 했다. ## 수평 확장 방안의 검토 Figma는 테이블을 여러 데이터베이스에 분산하는 수평 샤딩도 검토했지만, 다음과 같은 부담이 있었다. - Figma가 사용하는 PostgreSQL과 기본적으로 호환되지 않는 관리형 수평 확장 솔루션이 많았다. - NoSQL이나 MySQL 기반 Vitess로 이전하려면 애플리케이션에 큰 변경이 필요했다. - 마이그레이션 과정에서 이중 읽기·쓰기 구조를 운영해야 하므로 복잡성이 커졌다. - PostgreSQL 호환 NewSQL을 선택하면 클라우드 환경에서 매우 큰 분산 PostgreSQL 클러스터를 운영하는 초기 고객이 될 위험이 있었다. - 관리형 솔루션은 내부 동작과 확장 한계를 통제하기 어렵고, Figma 규모에서 충분히 검증되지 않은 문제를 직접 겪을 수 있었다. - 직접 호스팅하면 운영 지식과 인력을 새로 확보해야 하며, 상당한 운영 비용이 발생했다. ## 테이블 그룹 단위의 수직 파티셔닝 Figma는 수평 샤딩 대신 수직 파티셔닝을 선택했다. - 수직 파티셔닝은 테이블 또는 컬럼을 다른 데이터베이스로 이동하는 방식이다. - Figma는 개별 테이블의 행을 여러 데이터베이스로 쪼개는 대신, 서로 관련된 테이블 그룹 전체를 별도 데이터베이스로 옮겼다. - 이 방식은 기존 데이터베이스의 부하를 즉시 줄일 수 있었다. - 장기적으로는 특정 테이블 그룹에 대해 향후 수평 샤딩을 적용할 수 있는 기반도 제공했다. - 기존 PostgreSQL 생태계와 애플리케이션 구조를 크게 바꾸지 않고 확장할 수 있다는 점이 장점이었다. ## 분할 대상 선정 기준 데이터베이스를 분리하기 전에 어떤 테이블을 옮길지 평가해야 했다. 주요 기준은 다음 두 가지였다. - **영향도(Impact)** - 테이블을 이동했을 때 데이터베이스 작업량이 크게 줄어야 했다. - Figma는 쿼리에 대한 평균 활성 세션 수(AAS)를 사용해 부하를 측정했다. - PostgreSQL의 `pg_stat_activity`를 10밀리초 간격으로 조회해 쿼리별 활성 상태와 CPU 대기 관련 정보를 분석했다. - **격리성(Isolation)** - 분리 대상 테이블이 다른 테이블과 강하게 결합되어 있지 않아야 했다. - 테이블 간 의존성이 높으면 데이터베이스 간 조인과 트랜잭션 처리가 복잡해지므로, 독립적으로 이동할 수 있는 영역을 우선했다. 결국 Figma의 접근 방식은 단일 데이터베이스를 무리하게 확장하는 대신, 부하가 크고 다른 기능과의 결합도가 낮은 테이블 그룹부터 별도 데이터베이스로 분리하는 것이었다. 실무에서도 먼저 읽기 부하뿐 아니라 쓰기 부하와 복제 지연을 함께 측정하고, 수평 샤딩보다 운영 복잡성이 낮은 수직 분할부터 검토하는 것이 현실적인 전략이다.

원문 읽기(새 탭에서 열림)
figma3분 읽기큐레이션 요약

멀티플레이어를 더 안정적으로

Figma는 인메모리 상태와 30~60초 간격의 체크포인트에 의존하던 멀티플레이어 시스템에 변경 이력을 기록하는 저널(write-ahead log)을 도입했다. 저널은 파일의 전체 상태가 아닌 증분 변경을 자주 저장하므로 장애 발생 시 최신 체크포인트 이후의 변경을 재생해 복구할 수 있으며, 목표 데이터 손실을 1초 미만으로 줄였다. 또한 배포 시 모든 파일을 동시에 체크포인트하는 쓰기 부하 급증도 해소했다. ## 기존 멀티플레이어 구조 - 브라우저 클라이언트는 WebSocket으로 `multiplayer` 서비스에 연결한다. - 서버는 파일 상태를 메모리에 보관하면서 여러 클라이언트의 변경 사항을 수신·검증·정렬·충돌 해결한 뒤 전체 클라이언트에 전달한다. - 메모리 상태는 휘발성이므로 30~60초마다 파일 전체를 바이너리로 인코딩하고 압축해 S3에 체크포인트로 저장한다. - 체크포인트는 버전 기록 등 일부 기능의 기반이 된다. ## 체크포인트 중심 방식의 문제점 - 서버가 장애를 일으키면 마지막 체크포인트 이후 최대 60초의 작업을 잃을 수 있다. - 파일 전체를 저장하므로 파일의 크기와 복잡도가 커질수록 저장 비용도 증가한다. - 멀티플레이어를 재배포하면 메모리에 있던 모든 파일을 닫아야 하므로 동시에 대량의 체크포인트 쓰기가 발생한다. - 이로 인해 데이터베이스 부하가 급증하고, 배포가 사용자에게 보이지 않는 작업이어야 한다는 목표를 방해한다. ## 증분 변경을 저장하는 저널 - Figma는 파일 변경 사항을 기록하는 내구성 있는 트랜잭션 로그인 저널을 추가했다. - 멀티플레이어가 변경을 수락하면 변경 내용을 비동기적으로 저널에 기록한다. - 각 변경에는 파일별로 증가하는 시퀀스 번호를 부여한다. - 체크포인트에도 해당 시점의 시퀀스 번호를 함께 저장한다. - 저널에는 전체 파일이 아니라 사용자가 수행한 증분 변경만 저장한다. - 예: 텍스트 수정, 디자인 요소의 위치 변경, 목업 업데이트 등 - 증분 변경은 전체 파일보다 훨씬 작기 때문에 더 자주 기록해도 효율적이다. ## 장애 복구 방식 - 서버가 재시작되면 기존 체크포인트를 먼저 불러온다. - 체크포인트의 시퀀스 번호보다 큰 시퀀스 번호를 가진 저널 항목을 조회한다. - 해당 변경들을 순서대로 재생해 최신 파일 상태를 복원한다. - 기존 체크포인트 방식은 약 60초 간격으로 저장했지만, 저널은 약 0.5초 수준으로 변경 사항을 기록하는 방향을 취한다. - 그 결과 장애 시 데이터 손실 목표를 1초 미만으로 낮췄다. ## 배포 시 쓰기 부하 안정화 - 배포할 때 모든 연결을 종료하고, 아직 저장되지 않은 변경이 저널에 기록될 때까지 기다린다. - 99번째 백분위수 기준으로 이 과정은 1초 이내에 완료된다. - 배포를 위해 대규모 체크포인트를 한꺼번에 생성할 필요가 없어졌다. - 저널 쓰기는 평상시에도 지속적으로 발생하므로 데이터베이스 부하가 일정하고 예측 가능해진다. ## 데이터 저장소 선택 - 저널의 백엔드 저장소로 DynamoDB를 사용했다. - Postgres와 로컬 디스크 등 여러 선택지를 검토했지만, 높은 쓰기량을 수평 확장해야 한다는 점 때문에 Postgres는 선택하지 않았다. - 이 사례에서는 익숙한 데이터베이스보다 쓰기 규모와 확장성을 감당할 수 있는 저장소가 더 중요한 기준이었다. ## 변경 사항 배치 처리 - 클라이언트는 초당 30프레임, 즉 약 33ms마다 업데이트를 보낸다. - 모든 업데이트를 같은 빈도로 저널에 기록할 필요는 없으므로 여러 변경 사항을 묶어 일정 주기로 저장한다. - 이 배치 처리는 저널 쓰기 횟수를 줄이고 성능을 개선하면서도 체크포인트보다 훨씬 짧은 복구 지연 시간을 유지하기 위한 방식이다. Figma의 사례는 전체 상태를 드물게 저장하는 체크포인트와, 작은 변경을 자주 저장하는 저널을 함께 사용하는 구조가 실시간 협업 시스템에 적합하다는 점을 보여준다. 장애 복구 시간과 데이터 손실을 줄이려면 증분 로그를 도입하고, 시퀀스 번호를 기준으로 체크포인트와 로그를 연결하는 방식을 고려할 수 있다.

원문 읽기(새 탭에서 열림)
datadog원문

Datadog IT 팀이 계정 비활성화와 SaaS 지출 관리를 자동화한 방법 (새 탭에서 열림)

데이터독(Datadog)은 급격히 증가하는 SaaS 라이선스 비용을 최적화하고 보안 리스크를 줄이기 위해 기존의 내부 도구인 'Clarity'를 'Clarity License Manager(CLM)'로 확장했습니다. 이 시스템은 여러 SaaS 애플리케이션의 사용자 활동을 자동으로 모니터링하여 비활성 계정을 식별하고, 사용자 알림 및 자동 비활성화 프로세스를 통해 운영 효율성을 극대화합니다. 결과적으로 데이터독은 불필요한 비용 지출을 막는 동시에, 미사용 계정으로 인한 보안 위협을 효과적으로 제거하고 직원들에게는 원활한 계정 복구 경험을 제공하고 있습니다. ### 기존 라이선스 관리의 문제점 * 과거 IT 지원 팀은 분기별로 수동 감사를 수행하여 라이선스 사용 현황을 파악했으나, 이는 매우 비효율적이고 지루한 작업이었습니다. * IT 직원이 사용자에게 일일이 연락해 계정 유지 여부를 확인해야 했기 때문에 직원들의 업무 흐름을 방해하는 등 사용자 경험이 저하되었습니다. * 실시간 데이터에 기반한 인사이트가 부족하여 소프트웨어 구매 시 데이터에 기반한 의사결정을 내리기 어려웠습니다. ### 자동화된 라이선스 최적화 워크플로우 * 개별 SaaS API와 Google Workspace SAML 감사 로그를 결합하여 사용자 활동 데이터를 유연하고 보안상 안전한 방식으로 수집합니다. * 특정 기간(기본 90일) 동안 앱을 사용하지 않은 사용자에게 Slack과 이메일로 자동 알림을 발송하여 활성 상태 유지에 필요한 구체적인 행동을 안내합니다. * 사용자가 안내된 조치를 취하지 않을 경우 CLM이 해당 SaaS 계정을 자동으로 비활성화하며, 이 데이터는 Amazon RDS(Postgres)에 저장되어 관리됩니다. * 재접속이 필요한 직원을 위해 티켓 시스템(Freshservice)과 연동된 자동 복구 워크플로우를 구축하여, 단 몇 초 만에 이전 권한 그대로 계정을 복구할 수 있게 했습니다. ### 마이크로서비스 및 어댑터 기반 아키텍처 * Python과 AWS Lambda를 기반으로 한 마이크로서비스 구조를 채택하여 SaaS 환경의 확장에 유연하게 대응하고 시스템 회복 탄력성을 높였습니다. * 각 SaaS 애플리케이션의 고유한 로직을 처리하기 위해 '애플리케이션별 어댑터(Adapter)' 패턴을 도입했습니다. * 어댑터는 사용자 조회, 로그인 데이터 획득, 활성화/비활성화 등 공통 인터페이스를 제공하여 메인 마이크로서비스 로직과 개별 앱의 복잡한 API 통신 로직을 분리합니다. * 이러한 설계는 단일 책임 원칙(Single Responsibility)을 준수하며 코드의 재사용성을 높이고, 새로운 SaaS 도구를 시스템에 빠르게 통합할 수 있게 합니다. 기업의 규모가 커질수록 수동 라이선스 관리는 비용 누수와 보안 취약점을 야기하는 큰 부담이 됩니다. Datadog의 CLM 사례처럼 사용자 활동 데이터를 기반으로 비활성 계정을 자동 관리하고, 셀프 서비스 형태의 복구 프로세스를 갖추는 것은 비용 절감과 보안 강화라는 두 마리 토끼를 잡을 수 있는 실무적인 해법이 될 수 있습니다.

datadog원문

언제나 DNS 문제다… 그렇지 않은 경우를 제외하면: gRPC, Kubernetes, AWS 네트워킹 심층 분석 (새 탭에서 열림)

데이터독(Datadog)의 엔지니어들이 서비스 업데이트 중 발생한 원인 불명의 DNS 에러를 추적하며, 쿠버네티스 네트워킹과 AWS VPC 환경의 복잡한 상호작용을 해결해 나가는 과정을 다룬 글입니다. 로그상으로는 단순한 DNS 문제처럼 보였으나, 실제 원인은 AWS VPC의 연결 추적(conntrack) 한계와 하위 네트워크 레이어의 패킷 드랍에 있었습니다. 이 글은 고도화된 인프라 환경에서 단순히 리소스를 증설하는 것보다 커널 수준의 메트릭과 VPC 플로우 로그를 통한 심층 분석이 왜 중요한지를 잘 보여줍니다. **DNS 오류의 표면적 원인과 NodeLocal DNSCache** * 서비스 배포 시마다 DNS 에러가 발생하여 쿼리 지연과 모니터링 성능 저하가 나타났습니다. * 쿠버네티스의 `node-local-dns`가 메모리 부족(OOM) 및 최대 동시 요청 수(`max_concurrent`) 제한인 1,000개에 도달하여 요청을 거부하는 현상이 발견되었습니다. * 하지만 실제 초당 쿼리 수(QPS)는 예상 용량보다 훨씬 낮았으며, 이는 상위 DNS 리졸버와의 TCP 연결 실패로 인해 타임아웃이 발생하면서 동시 요청 슬롯이 빠르게 점유되었기 때문임이 밝혀졌습니다. **AWS VPC 연결 추적(conntrack)과 패킷 드랍** * 네트워크 성능을 정밀하게 확인하기 위해 AWS ENA(Elastic Network Adapter) 메트릭을 분석한 결과, `conntrack_allowance_exceeded` 수치가 급증한 것을 확인했습니다. * VPC 수준의 연결 추적 테이블(Hypervisor 레벨)이 포화 상태에 도달하면 보안 그룹 등의 상태 저장을 위한 연결 생성이 불가능해져 패킷이 드랍됩니다. * 특이하게도 인스턴스 내부의 리눅스 conntrack 엔트리는 6만 개 미만으로 안정적이었으나, VPC 레벨의 conntrack은 이미 한계에 도달하여 두 레이어 간의 가시성 차이가 존재함을 발견했습니다. **VPC 플로우 로그를 통한 심층 분석** * 인스턴스 유형을 상위 모델로 변경하여 임시적으로 문제를 해결할 수 있었으나, 근본 원인 파악을 위해 VPC 플로우 로그 분석을 병행했습니다. * Cilium, 쿠버네티스, AWS 네트워킹이 결합된 환경에서는 역경로 필터링(Reverse Path Filtering)이 정상적인 패킷을 'Martian packet'(출처가 불분명한 패킷)으로 오인하여 드랍하는 등 복잡한 문제가 발생할 수 있음을 시사했습니다. * DNS 전파 시간과 네트워크 마이크로버스트(Traffic Spikes) 역시 이러한 연결 추적 테이블 포화에 기여하는 핵심 요소임을 확인했습니다. **실용적인 결론** 단순히 로그에 나타나는 "DNS 에러"에만 집중하기보다, AWS ENA 메트릭의 `conntrack_allowance_exceeded`나 VPC 플로우 로그와 같은 하위 레이어의 지표를 함께 모니터링해야 합니다. 특히 대규모 쿠버네티스 클러스터를 운영한다면, 인스턴스 크기에 따른 VPC 수준의 conntrack 제한 수치를 미리 파악하고 적절한 인프라 사이징과 네트워크 정책 설정을 검토해야 합니다.

figma4분 읽기큐레이션 요약

LiveGraph: Figma의 실시간

Figma는 실시간 협업 제품에 필요한 데이터를 안정적으로 제공하기 위해 Postgres 위에 GraphQL 기반의 실시간 데이터 계층인 LiveGraph를 구축했다. LiveGraph는 프론트엔드가 선언적으로 데이터를 구독하면 데이터베이스 복제 스트림을 읽어 밀리초 단위로 변경 사항을 반영한다. 이를 통해 수동 이벤트 메시지와 클라이언트 상태 동기화의 복잡성을 줄이고, 대규모 실시간 데이터 구독을 지원한다. ## Figma에서 실시간 데이터가 필요한 이유 - 협업자가 파일을 추가하거나 권한을 변경하면 다른 사용자 화면에도 새로고침 없이 즉시 반영되어야 한다. - 따라서 서버에서 데이터를 한 번 가져오는 것만으로는 부족하며, 클라이언트가 현재 관심 있는 데이터의 변경 사항을 계속 받아야 한다. - 인프라 팀의 목표는 제품 개발자가 데이터 전파 방식이나 WebSocket 세부 구현을 직접 관리하지 않고도 실시간 뷰를 만들 수 있게 하는 것이었다. ## 기존 방식의 한계 - 초기에는 React 프론트엔드가 Ruby HTTP 엔드포인트에서 필요한 데이터를 한 번에 받아 Redux 전역 상태에 저장했다. - 데이터 변경 시 백엔드 코드에서 관련 클라이언트에 보낼 이벤트 메시지를 직접 작성하고, 프론트엔드는 WebSocket으로 이벤트를 받아 상태를 갱신했다. - 사용자와 데이터 규모가 커지면서 모든 데이터를 한 번에 로드하기 어려워졌고, 데이터를 점진적으로 불러오면서 다음 문제가 발생했다. - 특정 데이터가 메모리에 항상 존재한다는 보장이 없어짐 - 여러 제품 영역이 같은 데이터를 사용할 때 데이터 로딩 책임이 불분명해짐 - 이벤트를 어느 시점에 보내고 받아야 하는지 관리하기 어려워짐 - 단순한 “새 파일 생성” 이벤트와 달리 권한 변경은 다른 리소스의 가시성까지 연쇄적으로 바꿀 수 있어 이벤트 설계가 복잡했다. - 데이터베이스 쓰기 순서와 실시간 메시지의 송수신 순서가 항상 일치한다는 보장도 없었다. - 그 결과 클라이언트 상태가 서버 상태의 올바른 부분집합을 반영하지 못하는 일관성 버그가 발생했다. ## GraphQL 기반 Live Query 선택 - Figma는 개발자가 실시간 데이터 구독을 선언적으로 정의할 수 있는 일반적인 프레임워크가 필요하다고 판단했다. - GraphQL을 인터페이스로 사용하면 필요한 데이터와 관계를 쿼리로 표현하고, 시스템이 해당 데이터를 자동으로 가져오고 최신 상태로 유지할 수 있다. - 여기서 말하는 GraphQL 구독은 일반적인 이벤트 스트림 구독과 다르다. - GraphQL의 전통적인 `subscription`은 이벤트 메시지를 전달하는 방식에 가깝다. - LiveGraph가 목표로 한 것은 쿼리 결과 자체를 계속 갱신하는 “Live Query” 방식이다. - 프론트엔드는 GraphQL과 유사한 쿼리를 보내고, 서버는 결과를 JSON 트리로 반환한다. - 서버에는 엔터티와 관계를 정의하는 스키마 및 그래프의 일부를 조회할 수 있는 뷰가 존재한다. ## 기존 실시간 데이터베이스 대신 자체 구축한 이유 - Figma는 이미 Postgres를 대규모로 운영하고 있었기 때문에 Firebase나 RethinkDB 같은 별도의 실시간 데이터베이스로 이전할 수 없었다. - LiveGraph는 새로운 저장소가 아니라 기존 Postgres 위에 동작하는 쿼리 엔진이 되어야 했다. - Figma의 Multiplayer 시스템은 파일 단위의 쓰기와 충돌 해결을 담당하지만, LiveGraph는 여러 데이터의 조회와 실시간 동기화를 담당한다. - Hasura, Prisma, PostGraphile 등 GraphQL 기술도 검토했지만, 대규모 동시 구독을 핵심 요구사항으로 설계된 것은 아니었다. - Figma는 실시간 구독 수가 많아질수록 데이터베이스 부하가 커지는 폴링 방식도 피하고자 했다. - 폴링은 쿼리마다 주기를 정해야 한다. - 구독 수가 늘어나면 동일한 쿼리가 반복 실행되어 데이터베이스 부하가 증가한다. - 폴링보다 변경 발생 시점에 가까운 낮은 지연 시간을 확보하기 어렵다. ## 데이터베이스 복제 스트림 기반 설계 - LiveGraph는 주기적으로 데이터를 다시 조회하는 대신 Postgres의 데이터베이스 복제 로그를 추적한다. - 복제 스트림에서 변경 사항을 읽으면 실제 데이터베이스 변경을 감지한 뒤 구독 중인 쿼리 결과를 갱신할 수 있다. - 이 방식은 폴링보다 빠른 업데이트 지연 시간을 제공한다. - 다만 LiveGraph가 데이터베이스의 전체 변경량을 읽어야 하므로, 대규모 환경에서는 확장성이 중요하다. - Figma는 여러 데이터베이스 샤드의 변경 사항을 여러 머신에 분산 처리할 수 있는 구조를 고려했다. - 최종적으로 LiveGraph를 자체 구축한 이유는 Figma의 협업 기능에서 실시간 데이터가 핵심 기능이며, 이러한 요구사항이 경쟁력으로 이어질 수 있다고 판단했기 때문이다. ## 실용적인 결론 실시간 UI를 구축할 때 클라이언트별 수동 이벤트와 전역 상태 갱신에 의존하면 데이터 규모와 기능 복잡도가 커질수록 일관성 문제가 발생하기 쉽다. 기존 Postgres를 유지해야 하고 대규모 구독이 필요하다면, GraphQL 기반 선언적 쿼리와 데이터베이스 변경 스트림을 결합하는 방식이 폴링이나 수동 이벤트보다 확장성과 유지보수성 측면에서 유리하다.

원문 읽기(새 탭에서 열림)
figma4분 읽기큐레이션 요약

사후 분석: 202

2020년 1월 21~22일 Figma 장애는 장시간 실행된 고비용 쿼리와 PostgreSQL의 잘못된 쿼리 실행 계획, 그리고 이로 인해 누적된 공격적 autovacuum이 복합적으로 발생한 사건이었다. 1월 21일에는 문제 쿼리를 취소해 복구했지만, 그 여파로 데이터베이스 정리 작업이 밀리면서 다음 날 쓰기 IOPS와 잠금 경합이 급증했다. Figma는 PostgreSQL 11로 업그레이드해 문제를 안정화했고, 이후 고비용 쿼리 모니터링과 실행 시간 제한을 강화하기로 했다. ## 장애 발생 경과 ### 1월 21일: 장시간 실행 쿼리 - 오전 6시 11분, 자동 모니터링에서 오류율 증가를 감지했다. - 조사 결과, 데이터베이스 CPU를 과도하게 사용하는 장시간 실행 쿼리가 발견됐다. - 오전 6시 54분 해당 쿼리를 취소하자 성능이 정상으로 돌아왔다. - 그러나 쿼리 취소 과정에서 데이터베이스 내부에 정리해야 할 작업이 누적되었고, 이것이 다음 날 장애의 배경이 됐다. ### 1월 22일: 쓰기 부하와 잠금 경합 - 데이터베이스 CPU는 평소보다 낮았지만 쓰기 IOPS와 잠금 경합이 증가했다. - 오전 11시 42분에는 API 요청이 대기열에 쌓이며 일부 사용자가 서비스를 이용할 수 없게 됐다. - 불필요한 쿼리를 취소하고 할당된 IOPS를 늘려 일시적으로 안정화했지만, 오후 2시경 다시 성능이 악화됐다. - 데이터베이스를 재시작해 문제를 일으킨 것으로 추정한 백그라운드 프로세스를 임시 비활성화했다. - 오후 7시부터 긴급 점검을 진행하며 PostgreSQL을 업그레이드했고, 오후 8시 15분 서비스와 데이터베이스 지표가 정상화됐다. ## 공격적 autovacuum의 영향 - PostgreSQL의 autovacuum은 오래된 행 버전을 정리하고 트랜잭션 ID 고갈을 방지하는 자동 유지보수 작업이다. - 1월 21일 장시간 쿼리가 종료된 뒤 정리 대상 데이터가 대량으로 쌓였다. - 이 backlog가 임계치를 넘으면서 트랜잭션 ID 래핑을 막기 위한 더 공격적인 autovacuum이 실행됐다. - 당시 사용하던 PostgreSQL 버전에서는 이 작업이 테이블 잠금과 쓰기 작업에 큰 영향을 줬다. - Figma가 대형 테이블에서 실행 중인 autovacuum을 취소하자 지표가 일시적으로 개선됐지만, 작업은 다시 재개됐다. - `autovacuum_freeze_max_age` 값을 조정하고 데이터베이스를 재시작해야 공격적 autovacuum을 완전히 억제할 수 있었다. - 다만 autovacuum을 비활성화한 뒤에도 쓰기 지연과 잠금 경합이 계속되어, 이것만이 유일한 원인은 아니라고 판단했다. ## 잘못된 쿼리 실행 계획 - 문제의 핵심 쿼리는 복잡한 서브쿼리를 포함하고 있었고, 잠금 경합에 반복적으로 관여했다. - PostgreSQL 9의 통계 정보가 변경된 뒤 쿼리 플래너가 비효율적인 실행 계획을 선택한 것으로 분석됐다. - 실행 계획은 실제 결과가 3개 행뿐인데도 2천만 개 이상의 행을 반환할 것으로 잘못 추정했다. - 그 결과 인덱스를 사용하지 않고 전체 테이블 스캔을 수행했다. - 처리 과정에서 임시 버퍼에 대량의 데이터를 기록해 높은 쓰기 IOPS와 임시 데이터 사용량을 유발했다. - 즉, 낮은 CPU 사용률만으로 데이터베이스 상태가 양호하다고 판단하기 어려웠으며, 쓰기 지연·잠금·임시 버퍼 사용량을 함께 살펴야 했다. ## PostgreSQL 11 업그레이드 - PostgreSQL 9.6 이후에는 autovacuum과 관련된 중요한 최적화가 포함됐다. - PostgreSQL 10 이상에서는 Amazon RDS의 성능 분석 도구가 개선되어 원인 조사에 도움이 된다. - Figma는 이미 스테이징 환경을 PostgreSQL 11로 업그레이드하고 수개월간 테스트한 상태였다. - 운영 환경 업그레이드 절차도 사전에 마련해 두었기 때문에 긴급 상황에서도 업그레이드를 진행할 수 있었다. - PostgreSQL 11의 개선된 쿼리 플래너는 문제가 된 실행 계획이 선택될 가능성을 제거했다. - autovacuum의 성능 특성도 PostgreSQL 9에서 11로 오면서 개선되어 두 가지 주요 원인을 함께 완화했다. ## 후속 조치 - 고비용·장시간 실행 쿼리에 대한 모니터링을 강화한다. - 쿼리가 실행될 수 있는 시간에 더 엄격한 제한을 둔다. - 실행 계획의 예상 행 수와 실제 행 수 사이의 큰 차이를 지속적으로 점검한다. - CPU뿐 아니라 쓰기 IOPS, 쓰기 지연, 잠금 경합, 임시 버퍼 사용량, autovacuum backlog를 함께 모니터링해야 한다. - 데이터베이스 버전 업그레이드는 장애 발생 후 처음 검토하기보다, 스테이징 테스트와 운영 전환 계획을 미리 준비해야 한다. 실무적으로는 장시간 쿼리에 타임아웃을 설정하고, 정기적으로 `EXPLAIN ANALYZE`와 실행 계획 변화를 검토하며, autovacuum 상태를 별도 지표로 관리하는 것이 중요하다. alc-vesm.

원문 읽기(새 탭에서 열림)
figma4분 읽기큐레이션 요약

피그마의 멀티플레이어

Figma는 Google Docs처럼 복잡한 OT(Operational Transformation)를 적용하는 대신, 디자인 문서의 구조에 맞춘 단순한 자체 멀티플레이어 시스템을 구축했다. 클라이언트와 서버는 WebSocket으로 변경 사항을 동기화하고, 서버가 문서별 단일 조정자로 동작해 충돌을 관리한다. 이 방식은 실시간 협업뿐 아니라 오프라인 편집과 재접속까지 지원하면서도 Figma의 데이터 모델에 맞는 구현 단순성을 유지했다. ## 웹 기반 협업을 선택한 이유 - 멀티플레이어 기능이 있으면 파일을 내보내거나 복사본을 이메일로 주고받고, 변경 사항을 수동으로 동기화할 필요가 없다. - 링크 하나만으로 여러 사람이 현재 디자인 상태를 확인할 수 있다. - 디자이너뿐 아니라 카피라이터, 개발자 등도 같은 문서에 참여할 수 있다. - 초기에는 실시간 협업이 “디자인을 망치는 기능”으로 여겨졌지만, 웹 생산성 도구에는 자연스러운 기본 기능이 되었다. ## Figma의 클라이언트·서버 구조 - 웹 클라이언트는 WebSocket을 통해 멀티플레이어 서버 클러스터와 통신한다. - 문서마다 별도의 서버 프로세스를 두고, 해당 문서를 편집하는 사용자들이 같은 프로세스에 연결된다. - 문서를 열 때 클라이언트가 먼저 파일 전체를 내려받는다. - 이후 변경 사항은 양방향 WebSocket 연결을 통해 실시간으로 전송된다. - 댓글, 사용자, 팀, 프로젝트 같은 데이터는 멀티플레이어 시스템이 아니라 Postgres와 별도 동기화 시스템으로 관리한다. - 문서 편집과 기타 애플리케이션 데이터는 성능, 오프라인 지원, 보안 요구 사항이 다르기 때문에 구현을 분리했다. ## 오프라인 편집과 재접속 - 사용자는 네트워크가 끊긴 상태에서도 임의의 시간 동안 계속 편집할 수 있다. - 다시 온라인이 되면 클라이언트는 서버에서 최신 문서 사본을 받는다. - 그 위에 오프라인 동안 발생한 로컬 변경을 다시 적용한다. - 이후 새로운 WebSocket 연결을 통해 서버와 변경 사항을 계속 동기화한다. - 연결과 재연결 자체는 단순하게 만들고, 멀티플레이어의 핵심 복잡성은 이미 연결된 문서에 동시에 변경 사항이 들어오는 상황에 집중했다. ## OT와 CRDT 대신 자체 방식을 택한 이유 - OT는 Google Docs 등에서 널리 사용된 표준적인 협업 알고리즘이다. - 여러 사용자의 동시 작업을 변환해 충돌을 해결할 수 있지만, 구현과 검증이 복잡하다. - Figma는 텍스트 편집기와 달리 계층적인 디자인 객체를 편집하므로, 일반적인 OT 모델을 그대로 적용할 필요가 없다고 판단했다. - 스타트업으로서 빠르게 기능을 개발하고 실험하려면 더 단순한 구조가 유리했다. - Figma는 디자인 문서의 데이터 구조와 편집 패턴에 맞춘 전용 동기화 방식을 만들었다. ## 프로토타입을 통한 설계 검증 - 실제 제품 코드에 바로 적용하지 않고, 여러 클라이언트와 서버를 시뮬레이션하는 별도의 웹 기반 실험 환경을 만들었다. - 프로토타입에서는 여러 사용자의 상태와 변경 사항을 시각적으로 확인할 수 있었다. - 오프라인 클라이언트, 느린 네트워크, 제한된 대역폭 등 다양한 상황을 쉽게 재현했다. - 이를 통해 협업 알고리즘과 데이터 구조를 빠르게 비교하고 실험했다. - 설계가 확정된 뒤 프로토타입에서 검증한 아이디어를 기존 코드베이스에 이식했다. ## 서버 중심의 동기화 모델 - 하나의 문서에 연결된 사용자들은 같은 서버 프로세스를 공유한다. - 서버는 문서에 들어오는 변경 사항을 순서대로 처리하고 다른 클라이언트에 전달한다. - 클라이언트는 처음 받은 문서 상태를 기준으로 로컬 변경을 수행하면서 서버의 업데이트를 계속 반영한다. - 서버를 문서의 조정자로 두면 여러 클라이언트가 서로 직접 충돌을 해결할 필요가 줄어든다. - 동시에 발생한 변경의 처리 순서는 서버가 정하며, 모든 클라이언트가 최종적으로 같은 문서 상태에 도달하도록 한다. ## 이 접근법의 핵심 장점 - 범용 협업 알고리즘보다 Figma의 객체 중심 데이터 모델에 맞게 단순하게 구현할 수 있다. - 온라인 편집뿐 아니라 오프라인 작업과 재접속도 지원한다. - 별도 프로토타입으로 다양한 장애 상황을 반복적으로 테스트할 수 있다. - 문서 편집 동기화와 서비스 메타데이터 동기화를 분리해 각각의 요구 사항에 맞게 최적화할 수 있다. 실용적으로는 모든 협업 애플리케이션이 OT나 CRDT를 그대로 도입해야 하는 것은 아니다. 데이터 구조가 명확하고 충돌 패턴이 제한적이라면, 서버 중심의 단순한 프로토콜과 충분한 시뮬레이션 테스트를 결합하는 편이 더 빠르고 유지보수하기 쉬울 수 있다.

원문 읽기(새 탭에서 열림)
datadog원문

Datadog에서 고신뢰성 데이터 파이프라인 구축하기 (새 탭에서 열림)

데이터독(Datadog)은 매일 수조 건의 데이터를 처리하며 시스템의 신뢰성을 '정해진 시간 내에 정확한 결과물을 출력할 확률'로 정의합니다. 이들은 파이프라인의 장애를 완전히 막는 대신, 장애가 발생하더라도 데이터 전달 기한을 지킬 수 있도록 결함 허용(Fault Tolerance)과 빠른 복구에 초점을 맞춘 아키텍처를 구축했습니다. 특히 개별 작업 단위로 클러스터를 분리하고 장시간 실행되는 작업을 작게 쪼개는 전략을 통해 대규모 데이터 처리의 안정성을 확보하고 있습니다. ### 작업 격리를 위한 개별 클러스터 아키텍처 * 하나의 거대한 공유 클러스터를 사용하는 대신, 각 데이터 파이프라인 작업마다 독립적인 전용 클러스터를 할당하여 운영합니다. * 작업 간 리소스 경쟁을 원천 차단하여 특정 작업의 부하가 다른 파이프라인에 영향을 주지 않으며, 클러스터별 상태를 명확히 파악할 수 있어 모니터링이 용이합니다. * 작업의 특성에 따라 CPU 최적화 인스턴스나 메모리 최적화 인스턴스를 선택하는 등 하드웨어를 유연하게 튜닝할 수 있습니다. * 새로운 버전의 Hadoop이나 Spark를 도입할 때 전체 시스템을 중단할 필요 없이, 특정 클러스터부터 점진적으로 업그레이드하며 버그나 호환성을 테스트할 수 있습니다. ### 스팟 인스턴스 활용과 실패를 고려한 설계 * 비용 절감을 위해 AWS 스팟 인스턴스를 적극 활용하며, 이는 클러스터가 언제든 중단될 수 있다는 전제하에 파이프라인을 설계하도록 강제하는 '카오스 엔지니어링'의 효과를 줍니다. * 단일 작업의 실행 시간이 길어질수록 실패 시 손실되는 작업량과 복구 시간이 늘어나므로, 이를 방지하기 위해 작업을 수직적·수평적으로 세분화합니다. * **수직적 분할:** 데이터 변환 과정을 여러 단계의 작업으로 나누고, 단계 사이의 중간 데이터를 S3에 저장(Checkpointing)하여 실패 시 처음부터 다시 시작하지 않고 중간 지점부터 재개할 수 있게 합니다. * **수평적 분할:** 입력 데이터를 샤드(Shard) 단위로 파티셔닝하여 여러 작업이 병렬로 처리하게 함으로써 개별 작업의 규모를 작게 유지합니다. ### 롤업(Rollup) 파이프라인의 최적화 사례 * 과거 14시간 이상 소요되던 단일 메트릭 집계 작업을 '집계' 단계와 '커스텀 포맷 저장' 단계로 분리하여 관리합니다. * 첫 번째 집계 작업의 결과물을 S3에 Parquet 파일로 저장함으로써, 두 번째 단계에서 장애가 발생하더라도 집계 과정을 다시 반복할 필요가 없습니다. * Kafka 파티션 구조를 기반으로 데이터를 샤딩하여, 데이터 규모가 급증하거나 특정 샤드에 문제가 발생했을 때 해당 부분만 격리하여 리소스를 집중 투입하거나 빠르게 복구할 수 있습니다. * 이러한 구조는 작업 시작 오버헤드나 S3 쓰기 비용을 발생시키지만, 장애 복구 시간을 단축하고 전체 시스템의 데이터 가용성을 보장하는 데 결정적인 역할을 합니다. 대규모 데이터 시스템에서 신뢰성은 시스템이 절대 중단되지 않는 것이 아니라, 중단되었을 때 얼마나 빠르게 복구되어 사용자에게 제때 데이터를 전달하느냐에 달려 있습니다. 이를 위해 파이프라인을 최대한 작고 독립적인 단위로 쪼개고 중간 상태를 유지하는 설계는 복잡한 데이터 환경에서 필수적인 전략입니다.

datadog원문

Vagrant와 Terraform으로 지원 확장 (새 탭에서 열림)

Datadog의 솔루션 팀은 고객이 사용하는 다양한 기술 스택과 복잡한 인프라 환경에서 발생하는 문제를 정확히 재현하기 위해 Vagrant와 Terraform을 활용한 자동화된 샌드박스 시스템을 구축했습니다. 인프라 구축 과정을 코드화하여 팀 전체가 공유함으로써, 개별 엔지니어가 생소한 기술을 매번 처음부터 학습하고 설치해야 하는 비효율을 제거하고 문제 해결 속도를 획기적으로 높였습니다. 결과적으로 로컬 가상 머신과 클라우드 인스턴스를 자유롭게 오가는 유연한 디버깅 환경을 통해 팀 간 협업과 고객 지원의 품질을 극대화할 수 있었습니다. **Vagrant 프로비저닝을 통한 환경 구축 자동화** * 고객의 특정 OS, 커널 버전, 복잡한 통합 도구(Kafka, MS SQL, RabbitMQ 등)를 수동으로 설치하는 것은 시간이 많이 걸리고 오류가 발생하기 쉽습니다. * Vagrant의 '프로비저닝(Provisioning)' 기능을 활용하여, 인프라 설치 및 설정에 필요한 모든 명령어를 `setup.sh`와 같은 쉘 스크립트에 담아 자동화했습니다. * 한 번 작성된 프로비저닝 스크립트는 팀 공용 GitHub 저장소에 저장되어, 다른 팀원들이 동일한 이슈를 처리할 때 `vagrant up` 명령어 하나만으로 즉시 동일한 환경을 갖출 수 있게 합니다. **샌드박스 저장소의 구조화 및 유연성 확보** * 저장소는 운영체제와 배포판, 서비스 이름에 따라 계층적으로 디렉토리를 나누어 관리하며, 각 디렉토리에는 `Vagrantfile`, `setup.sh`, 그리고 설정 파일 등이 담긴 `/data` 폴더를 포함합니다. * 엔지니어 개인별로 달라야 하는 설정(호스트 이름, API 키, 태그 등)은 `.sandbox.conf.sh`라는 로컬 설정 파일에 분리하여 관리함으로써 스크립트의 범용성을 유지합니다. * 이를 통해 새로운 환경이 필요할 때 기존 템플릿을 복사하여 빠르게 변형할 수 있으며, 팀 내 기술적 노하우가 코드를 통해 자연스럽게 축적됩니다. **Terraform을 이용한 클라우드 확장 및 협업** * 로컬 가상 머신 사용 시 발생하는 RAM 자원 부족 문제를 해결하고 팀원 간 환경을 쉽게 공유하기 위해 Terraform을 도입하여 AWS EC2 인스턴스를 활용합니다. * Vagrant에서 사용하던 `setup.sh`와 `/data` 파일을 그대로 재사용하면서, 인스턴스 생성을 위한 `.tf` 파일만 추가하여 로컬과 클라우드 환경 간의 일관성을 유지합니다. * 클라우드 기반 샌드박스를 활용하면 여러 시간대의 팀원들이 동일한 원격 환경에 접속해 조사를 이어갈 수 있으며, 고객과의 실시간 상담 중에도 미리 준비된 환경을 즉시 배포하여 대응할 수 있습니다. **실용적인 결론** 반복적인 환경 구축이 필요한 기술 지원이나 개발 팀이라면 인프라를 코드로 관리(IaC)하는 것이 필수적입니다. Vagrant로 로컬에서 가볍게 시작하되, 동일한 프로비저닝 스크립트를 Terraform과 공유할 수 있도록 설계하면 로컬의 편의성과 클라우드의 협업 능력을 동시에 잡을 수 있습니다. 특히 `setup.sh`와 같은 범용 스크립트를 중심에 두면 도구가 바뀌어도 재사용성을 높일 수 있습니다.

figma4분 읽기큐레이션 요약

속도 제한에 대한 대안

Figma는 스팸 공격으로부터 서비스를 보호하기 위해 Redis 기반의 자체 레이트 리미터를 구축했다. 토큰 버킷과 고정 윈도 카운터는 메모리 효율이 좋지만 정확성이나 동시성 문제가 있었고, 슬라이딩 윈도 로그는 정확하지만 메모리를 많이 사용한다. Figma는 여러 기법을 조합해 분산 환경에서 빠르고 정확하며 메모리 효율적인 방식으로 요청량을 제한했다. ## 레이트 리미팅의 요구사항 - 사용자나 IP 주소별로 일정 시간 동안 허용할 요청 수를 제한한다. - 예: 1분에 25회 요청 허용 - 여러 웹 서버가 동일한 제한 정보를 공유해야 하므로 외부 저장소가 필요하다. - 웹 요청 처리 속도를 크게 저하시켜서는 안 된다. - 오래된 추적 데이터를 효율적으로 삭제해야 한다. - 과도한 요청을 정확하게 차단하면서 메모리 사용량도 최소화해야 한다. - Figma는 PostgreSQL보다 읽기·쓰기 속도가 빠르고 만료 키를 지원하는 Redis를 추적 데이터 저장소로 선택했다. ## 토큰 버킷의 장점과 동시성 문제 - 사용자마다 다음 두 값을 Redis 해시에 저장한다. - 마지막 요청 시각 - 현재 남아 있는 토큰 수 - 시간이 지나면 설정된 보충 속도에 따라 토큰을 다시 채운다. - 토큰이 0개가 되면 요청을 제한한다. - 장점: - 구현 개념이 단순하다. - 사용자별로 작은 해시 하나만 저장하므로 메모리 효율이 높다. - 일정한 요청 속도와 일시적인 버스트를 모두 처리할 수 있다. - 문제점: - Redis에서 값을 읽고 계산한 뒤 다시 쓰는 과정이 원자적이지 않다. - 두 서버가 동시에 같은 토큰 수를 읽으면, 둘 다 요청을 허용하는 경쟁 조건이 발생할 수 있다. - 결과적으로 실제 허용량보다 많은 요청이 통과할 수 있다. - Redis 락이나 Lua 스크립트로 원자성을 보장할 수 있지만, 락은 지연과 복잡성을 늘리고 Lua는 코드베이스에 별도 언어를 추가해야 한다. ## 고정 윈도 카운터의 단순성과 경계 문제 - 요청이 발생한 시간 구간을 키로 삼아 Redis 카운터를 증가시킨다. - 예: `user:1:2017-03-30T10:00`에 해당 분의 요청 수 저장 - 카운터가 제한값을 넘으면 요청을 거부한다. - 각 키에 만료 시간을 설정해 오래된 카운터를 자동 삭제한다. - `INCR` 같은 Redis 연산을 사용하므로 토큰 버킷보다 동시성 처리가 안전하다. - 메모리 사용량도 적고 구현과 동작을 이해하기 쉽다. - 하지만 윈도 경계에서 허용량보다 최대 두 배 많은 요청이 통과할 수 있다. - 예를 들어 분당 5회 제한에서 10:00:59에 5회, 10:01:00에 다시 5회를 보내면 실제로는 2초 안에 10회가 허용된다. - 따라서 고정 윈도만으로는 요청량을 정확하게 제한하기 어렵다. ## 슬라이딩 윈도 로그의 정확성과 메모리 비용 - 각 요청의 정확한 타임스탬프를 저장한다. - 새 요청이 들어오면 제한 시간보다 오래된 기록을 삭제하고, 현재 윈도 안의 요청 수를 계산한다. - 윈도가 계속 이동하므로 고정 윈도 경계에서 발생하는 폭주 문제가 없다. - 가장 정확한 방식이지만 모든 요청 기록을 보관해야 한다. - 요청 빈도가 높은 사용자나 공격자가 많아지면 저장해야 할 타임스탬프 수가 급증한다. - 따라서 정확성은 높지만 Redis 메모리를 많이 사용한다. ## Figma의 절충 방식 - Figma는 고정 윈도 카운터의 낮은 메모리 사용량과 슬라이딩 윈도의 정확성을 결합하는 방식을 사용했다. - 전체 제한 구간을 더 작은 시간 단위의 카운터들로 나누고, 현재 구간과 직전 구간의 요청량을 이용해 이동 중인 윈도의 사용량을 계산한다. - 개별 요청의 타임스탬프를 모두 저장하지 않고 카운터만 유지하므로 슬라이딩 윈도 로그보다 메모리 효율적이다. - Redis의 원자적 카운터 증가 연산을 활용해 여러 애플리케이션 서버가 동시에 요청을 처리해도 경쟁 조건을 줄일 수 있다. - Redis 키에 만료 시간을 지정해 오래된 시간 구간의 데이터가 자동으로 제거되도록 한다. - 이 방식은 완벽한 요청 단위 정확성보다는 약간의 근사치를 허용하는 대신, 다음 특성을 균형 있게 제공한다. - 분산 환경에서의 안전성 - 낮은 지연 시간 - 적은 메모리 사용량 - 고정 윈도보다 나은 제한 정확도 ## 스팸 공격 방어 효과 - 공격자는 다수의 이메일 주소로 문서 초대 요청을 반복해서 보냈다. - 레이트 리미터가 비정상적인 요청 증가를 조기에 감지해 추가 요청을 차단했다. - 그 결과 이메일 발송 비용의 급증과 발신자 평판 하락을 막을 수 있었다. - 레이트 리미팅은 단순한 성능 보호 장치뿐 아니라 이메일 초대, 비밀번호 재설정, 결제 등 악용되기 쉬운 기능의 스팸 방어 수단으로도 활용할 수 있다. 서비스 규모가 크고 여러 서버가 요청을 처리한다면 Redis 기반의 원자적 카운터와 만료 키를 우선 고려하는 것이 실용적이다. 높은 정확성이 필요하면 슬라이딩 윈도 로그를, 메모리와 성능을 중시하면 슬라이딩 윈도 카운터나 세분화된 고정 윈도 방식을 선택하는 것이 적절하다.

원문 읽기(새 탭에서 열림)