JOIN을 지웠더니 편안해졌다, Application-Level Join 실전 도입기
·
탐구 생활/데이터베이스
이전 글에서는 RDBMS 조인이 '넓은 테이블(Wide Table)'과 '깊은 페이지네이션(Deep Pagination)'을 만났을 때 겪게 되는 수학적, 아키텍처적 한계와 디스크 스필(Disk Spill) 현상을 다루었습니다. 이 글에서는 디스크 스필이 실제 프로덕션 환경에서 어떻게 시스템 장애를 유발했는지, 그리고 이를 어플리케이션 레벨 조인(Application-Level Join)이라는 설계 패턴으로 어떻게 타파했는지 공유합니다.장애의 발단제가 맡은 서비스는 간혹 데이터베이스 CPU사용률이 80~90%까지 치솟는 문제가 발생하고 있었습니다. 이때마다 Read Instance가 수평확장되어서 결국 서비스가 안정화 되었지만, Read Instance가 확장되고 안정화되고 백엔드 어플리케이션과 연결될때..
MySQL vs PostgreSQL, 조인의 불확실성과 엔진별 한계
·
탐구 생활/데이터베이스
ORM이 보편화되면서 백엔드 개발자들은 select_related나 joinedload(JPA에서는 JOIN FETCH)를 통해 손쉽게 두 테이블을 INNER JOIN으로 엮어냅니다. 그리고 "옵티마이저가 알아서 쿼리를 최적화하여 필요한 데이터만 조인하겠지"라고 기대합니다. 하지만 데이터베이스가 감당해야 할 데이터가 수백만 건을 넘어가고, 넓은(Wide) 테이블에 깊은 페이지네이션(Deep Pagination)이 결합하는 순간 이 기대는 처참히 무너집니다. 이 글에서는 PostgreSQL과 MySQL(InnoDB)의 내부 아키텍처를 바탕으로, RDBMS 조인이 태생적으로 안고 있는 구조적 한계와 알고리즘의 맹점을 이론적으로 분석해 봅니다.관계 대수의 제약과 의미론적 장벽(Semantic Barrier)P..
Python GIL과 캐시 스래싱, 그리고 ARM64(Graviton)의 물리적 시너지
·
탐구 생활/Python
Python WSGI Django 환경에 Rust 를 받아들여서 하루 1.8억건의 요청을 견디는 백엔드 서버를 만든 글에서 자세히 보면 한가지 중요한 사항이 빠져있습니다. 바로 AWS 환경에서 ARM64(Graviton) CPU를 사용함으로써 Error Rate와 RPS가 모두 안정화 됐다는 점입니다.해당 글에서는 Rust를 이용함으로써 Accept Queue 에서 accept() 을 호출하는 과정에 안정화되어 Error Rate이 줄어든건 설명이 되지만 RPS가 개선된건 주로 CPU교체 때문이었습니다. 개인적으로 Python GIL 제약하에 CPU구조의 차이로 인해 X86_64(AMD64)와 Graviton(ARM64)에서 차이가 발생했다고 알고 있었지만 그 내용을 깊이 파보진 않았습니다. 이 글을 통..
RDB 복합인덱스 조금 깊게 알아보기
·
탐구 생활/데이터베이스
느린 쿼리를 마주한 백엔드 엔지니어의 첫 번째 반사 신경은 보통 인덱스 추가입니다. 하지만, 인덱스를 걸었는데도 쿼리 응답 속도가 꿈쩍도 하지 않거나, 되려 쓰기 성능(TPS)만 곤두박질치는 기이한 현상을 마주할 때가 있습니다. 이 글은 실제 이커머스 서비스의 트래픽을 처리하는 과정에서 발견한 잘못 설계된 복합 인덱스 한 줄에서 출발합니다.인덱스가 B+Tree가 물리적으로 데이터를 정렬하는 방식(Lexicographical Order), PostgreSQL의 힙(Heap) 테이블 한계와 HOT(Heap-Only Tuple) 업데이트 파괴로 이어지는 나비효과까지, RDBMS 엔진의 밑바닥을 파헤쳐 보겠습니다.겉보기엔 멀쩡한 인덱스의 함정문제의 시작은 이커머스 도메인의 핵심인 OrderItem (주문 상품)..
리뷰 퀄리티 판단 엔진을 만든 과정
·
탐구 생활/LLM
지금 우리는 파운데이션 모델의 API 를 이용하는것만으로 AI를 이용할 수 있습니다. 이처럼 AI에 대한 접근성이 정말 높아졌는데요, 이런 흐름은 자연스럽게 제품에 놓아득어서 회사에서도 LLM 을 이용한 다양한 Feature 를 개발하게 되었습니다. AI를 이용해 리뷰를 요약하는 기능을 만들고, 리뷰의 감정을 분류하는 기능을 만들고, 그리고 이번 글의 주제가 되는 리뷰의 퀄리티를 판단 엔진을 만들었습니다. LLM을 이용하기 너무 편한 시대이다 보니 구현보다 중요해지는 요소는 LLM 판단 퀄리티에 대한 제어와 고객이 느끼는 가치입니다. 이번 글에서는 리뷰 퀄리티 판단 엔진을 만들면서 어떻게 LLM 판단 결과를 제어하고 고객이 느끼는 가치를 평가했는지에 대해서 다룹니다.도움이 되는 리뷰란?이커머스에서 리뷰에..
MySQL vs PostgreSQL 2편: UPDATE의 나비효과
·
탐구 생활/데이터베이스
MySQL vs PostgreSQL 1편에서는 MySQL의 Index-Organized Table(IOT)과 PostgreSQL의 Heap Table 구조를 비교하며, 데이터를 저장하고 읽는(Read) 방식의 근본적인 차이를 알아보았습니다. PostgreSQL은 무거운 데이터를 억지로 정렬하지 않고 힙(Heap) 공간에 마구잡이로 던져 넣은 뒤, 인덱스에서 물리적 주소(TID)로 다이렉트로 꽂아버리는 방식을 택했습니다. 읽기(Read) 관점에서는 트리를 두 번 타야 하는 MySQL보다 구조적으로 훨씬 명쾌하고 빨라 보였죠. 하지만 데이터베이스의 진짜 숙명은 조회가 아니라 끊임없는 '변경(UPDATE)'에 있습니다. 오늘은 데이터가 변경되는 순간, 평화롭던 PostgreSQL의 힙 구조에 어떤 거대한 나비..
MySQL vs PostgreSQL 1편: 데이터는 어떻게 저장되는가?
·
탐구 생활/데이터베이스
지난 글에서는 B+Tree의 원리를 통해 데이터베이스 인덱스가 디스크 I/O를 어떻게 획기적으로 줄여내는지 깊이 파헤쳐 보았습니다. 전 세계에서 가장 널리 쓰이는 RDBMS인 MySQL(InnoDB)을 기준으로 설명했었는데, 제가 실무에서 주로 다루는 PostgreSQL에 대한 설명이 부족해서 개인적으로 못내 아쉬웠습니다. 사실 MySQL InnoDB에 존재하는 클러스터링 인덱스(PK로 만들어진 B+Tree의 리프 노드에 실제 데이터가 예쁘게 정렬되어 저장되는 구조)는 PostgreSQL에는 존재하지 않습니다. 오늘은 PostgreSQL의 구루 히로노부 스즈키(Hironobu Suzuki)의 The Internals of PostgreSQL를 길잡이 삼아, 두 DB의 근본적인 저장 구조 차이와 읽기(Re..
B+Tree 구조와 데이터베이스 인덱스
·
탐구 생활/데이터베이스
스타트업에서 백엔드 엔지니어 실무를 하다보면 웹, 인프라/클라우드, 데이터베이스까지 폭 넓게 지식과 실무 경험을 쌓을 수 있다는 장점이 있습니다. 하지만 이렇게 일하다보면 "이건 왜 이렇게 돌아가는거지?" 하고 의문이 들 때가 있는데요, 오늘은 데이터베이스 그 중에서 인덱스가 왜 빠른지에 대해서 조금 깊이 알아보고자 합니다.그 유명한 B+Tree 구조에 대해서데이터베이스 인덱스에 대해서 이야기할때 가장 기본적이고 추상적인 설명은 이름 그대로 "데이터를 빠르게 찾기 위한 색인을 넣는 과정" 입니다. 하지만 실무를 어느정도 해본, 혹은 전공서적을 공부중인 학생이라면 이정도 설명으로는 충분하지 않습니다. 이 글의 조금더 깊이 알아본다는 주제를 충족하기 위해서는 우리는 대표적인 RDBMS 의 인덱스인 B+Tre..