PostgreSQL

  • PostgreSQL 데이터를 Parquet로 이관하는 Cold Storage 파이프라인

    처음에는 애플리케이션에서 SELECT 결과를 읽어 Parquet 파일로 쓰려고 했습니다. 데이터가 적을 때는 잘 동작했습니다. 범위가 커지자 모든 직렬화와 전송이 애플리케이션을 통과했습니다. Migration Job의 메모리 사용량과 실행 시간이 데이터량에 따라 크게 흔들렸습니다. Cold Storage의 목적은 단순히 파일 하나를 만드는 것이 아니었습니다. 이관이 끝난 범위는 온라인 PostgreSQL에서 정리해야…

    읽기 →

  • 실시간 집계가 느려졌을 때 통계를 미리 계산하는 방법

    대시보드의 통계 API는 처음에 원본 이벤트와 결과 항목 테이블을 요청마다 집계했습니다. 정확하고 구현이 단순했지만 데이터가 늘면서 하나의 화면이 여러 개의 GROUP BY를 동시에 실행했습니다. 기간, 장비, 제품, 결함 종류 조합이 다양해 캐시 적중률도 낮았습니다. 짧은 기간은 괜찮았지만 장기 조회와 동시 사용자가 겹치면 응답 시간이 크게 흔들렸습니다.…

    읽기 →

  • Dual Write의 빈틈을 Reconciliation Job으로 복구하기

    MongoDB에 원본을 저장한 뒤 Redis Streams로 이벤트를 발행하고, Worker가 PostgreSQL 조회 모델을 만드는 구조를 운영했습니다. 전체 데이터 파이프라인의 처리 순서는 정상 흐름만 보면 단순하지만 MongoDB 저장과 Redis 발행은 하나의 트랜잭션이 아니었습니다. 저장 직후 프로세스가 종료되거나 Redis가 잠시 응답하지 않으면 원본은 존재하지만 이벤트는 없는 상태가 생깁니다. 이…

    읽기 →

  • 여러 Pod가 PostgreSQL 월별 파티션을 동시에 만들지 않게 한 방법

    감사 로그는 계속 쌓이지만 오래된 기록을 조회하는 빈도는 낮습니다. 그래서 audit_log와 audit_log_target을 occurred_at 기준의 월별 RANGE 파티션으로 나눴습니다. 데이터가 어느 파티션으로 들어갈지는 명확했지만, 다음 달 파티션을 누가 언제 만들지는 별도의 문제였습니다. PostgreSQL은 입력값을 받아 줄 파티션이 없으면 부모 테이블에 대신 보관하지 않습니다. DEFAULT 파티션을 두지 않은…

    읽기 →

  • 대규모 시계열 데이터를 PostgreSQL 파티션으로 나누기

    시간 순서로 계속 쌓이는 이벤트 데이터는 처음에는 단일 PostgreSQL 테이블로도 충분했습니다. 최근 며칠을 조회하는 API, 장비별 필터, 결함 통계 모두 적절한 복합 인덱스로 빠르게 처리됐습니다. 문제는 데이터와 인덱스가 함께 커진 뒤 나타났습니다. 조회 조건은 최근 범위였지만 조회에 사용되는 인덱스는 전체 이력을 포함했습니다. 대량 삭제로 발생한 WAL과…

    읽기 →

  • 실시간·Hot·Cold 3계층 데이터 아키텍처를 설계한 이유

    시간 순서로 쌓이는 이벤트 데이터도 시간이 지나면 접근 빈도와 갱신 방식이 달라집니다. 수집 직후에는 새 데이터가 계속 들어오고 상태가 갱신되지만, 최근 며칠 또는 몇 주의 데이터는 화면 조회와 통계에서 반복해서 읽힙니다. 수개월이 지난 데이터는 거의 조회되지 않지만 감사, 장기 통계, 파일 내보내기를 위해 보관해야 합니다. 초기에는…

    읽기 →

  • Prisma의 과도한 Join이 프로세스를 죽였을 때 쿼리를 분해한 방법

    필요한 관계를 ORM의 include에 모두 넣어 한 번의 query로 완성된 응답을 만들었습니다. 코드 한 줄로 풍부한 객체 graph를 얻을 수 있었지만 여러 to-many 관계의 cardinality가 곱해지자 SQL 반환 행이 폭증했고, 이어서 객체 조립에 필요한 메모리도 함께 늘었습니다. 작은 개발 데이터에서는 드러나지 않던 이 문제가 운영 환경에서는…

    읽기 →

  • 온프레미스 제품에서 DB 없는 설정과 PostgreSQL 설정을 함께 지원하기

    온프레미스 제품을 단일 노드에 설치하려는 환경에서는 애플리케이션 하나를 실행하기 위해 PostgreSQL까지 운영하는 일이 부담이 될 수 있었습니다. 중앙에서 설정을 수정하고 여러 인스턴스가 공유해야 하는 환경에는 데이터베이스가 잘 맞았지만, 설정이 거의 바뀌지 않는 소규모 설치에는 같은 구성이 지나치게 무거웠습니다. 처음에는 기존 Repository에 isOnprem 조건을 추가하면 두 환경을…

    읽기 →