본문 바로가기

전체 글43

PostgreSQL 내부구조 (6) ㅡ Index 1편에서 본 ctid, 4편에서 본 Visibility Map. 이 둘이 인덱스에서 어떻게 쓰이는지 알아보자. 인덱스는 별도의 자료구조처럼 생각하지만, 실제로는 1편의 힙 페이지 구조 위에 얹혀 동작한다. 이 글에서 다루는 것:인덱스가 저장하는 것 — 키와 ctid, 그리고 저장하지 않는 것모든 인덱스가 보조 인덱스(secondary index)라는 의미인덱스 스캔의 비용 — 힙 random I/O인덱스 종류 (B-tree · GiST · SP-GiST · GIN · BRIN · Hash)와 각각의 사용처B-tree가 정렬을 제공한다는 것, 멀티컬럼 인덱스Index Only Scan과 Visibility Map의 관계인덱스 유지 비용 — 쓰기 증폭과 비대화인덱스가 저장하는 데이터인덱스가 한 항목에 저장하.. 2026. 7. 18.
PostgreSQL 내부 구조 (5) — WAL과 Checkpoint, 장애 복구의 핵심 1편에서 dirty 페이지를 디스크에 쓰기 전에 "WAL이 먼저 flush되어야 한다"고 언급했다. PostgreSQL이 어떻게 갑작스러운 크래시 후에도 일관된 상태를 복원하는지 알아본다. 이 글에서 다루는 것: Write-Ahead Logging 원칙LSN과 pd_lsn, full page writes (torn page 문제)Checkpoint (redo point · checkpoint_timeout · max_wal_size · checkpoint_completion_target)크래시 복구 과정synchronous_commit Write-Ahead Logging — 데이터보다 로그가 먼저WAL은 파일에 저장되는 로그다. WAL의 원칙은 한 줄이다.데이터를 디스크에 쓰기 전에, 그 변경 내용을 먼.. 2026. 4. 18.
PostgreSQL 내부 구조 (4) — VACUUM, 옛 버전은 누가 치우는가 2편(MVCC) 에서 본 것처럼 PostgreSQL은 옛 버전을 안 지운다. 시간이 지나면 어떤 트랜잭션도 더 이상 보지 않는 dead tuple이 쌓인다. 이걸 누가, 언제, 어떻게 치우는지 알아보자.이 글에서 다루는 것:dead tuple, table bloat, VACUUM의 두 가지 역할 (페이지 회수 / freeze),Visibility Map (all-visible · all-frozen), autovacuum 트리거 조건과 튜닝, autovacuum cost 모델,트랜잭션 ID wraparound (freeze), anti-wraparound vacuum,VACUUM vs VACUUM FULL모니터링 (pg_stat_user_tables · datfrozenxid)Dead Tuple이 만드는.. 2026. 4. 18.
PostgreSQL 내부 구조 (3) — Locking, 동시성의 또 다른 축 2편에서 다룬 MVCC가 "읽기와 쓰기를 어떻게 분리하는가"라면, 락은 "동시 쓰기를 어떻게 조율하는가"다. 이 글에서 다루는 것:테이블 락 8단계와 호환성, 행 락 4종행 락의 여부의 저장 위치 (튜플 헤더)데드락, lock wait 디버깅 (pg_locks · pg_blocking_pids)타임아웃 설정 (statement_timeout · lock_timeout · idle_in_transaction_session_timeout) MVCC만으로는 부족한 순간2편에서 본 MVCC는 한 가지를 보장한다. 읽기는 쓰기를 막지 않고, 쓰기는 읽기를 막지 않는다. 옛 버전이 남아 있으니 SELECT는 자기 스냅샷에 맞는 버전을 보면 되고, UPDATE는 새 버전을 만들면 된다. 그런데 다음 상황들은 MVCC.. 2026. 4. 18.
PostgreSQL 내부 구조 (2) — MVCC와 격리 수준 1편에서 본 t_xmin, t_xmax가 어떻게 동시성 제어에 쓰이는지, 왜 PostgreSQL은 행을 덮어쓰지 않고 여러 버전을 남겨두는지 알아보자. 이 글에서 다루는 것:MVCC (INSERT · UPDATE · DELETE의 실제 동작)CLOG(Commit Log), hint bits이상현상 (dirty read · nonrepeatable read · phantom read · serialization anomaly), 쓰기 스큐 (write skew)격리 수준 (Read Committed · Repeatable Read · Serializable) MVCC의 핵심 아이디어MVCC(Multi-Version Concurrency Control)는 한 문장으로 정리된다.데이터를 덮어쓰지 말고, 새 버.. 2026. 4. 18.
PostgreSQL 내부 구조 (1) — 페이지와 Shared Buffers PostgreSQL의 모든 데이터가 저장되는 물리 구조를 알아보자. 이후 편에서 다룰 MVCC, VACUUM, 인덱스가 왜 그렇게 동작하는지는 이 구조를 알아야 이해된다. 이 글에서 다루는 것:8KB 페이지 레이아웃 (PageHeaderData, Line Pointer, 튜플 헤더 (xmin · xmax · ctid · t_infomask))Shared Buffers (Hash Table · Buffer Descriptor · Buffer Block)Clock SweepRing Buffer 모든 것은 8KB 페이지다PostgreSQL에서 테이블, 인덱스, 시퀀스는 전부 고정 크기 8KB 페이지의 배열로 저장된다. 디스크에서 읽을 때도, 메모리에 올릴 때도, 단위는 항상 이 8KB 페이지다. "블록(blo.. 2026. 4. 18.
PostgreSQL 기본 (0) — 연결과 프로세스 구조 쿼리가 실행되기까지 "클라이언트 → 서버" 사이에서 일어나는 과정과 PostgreSQL의 프로세스 모델과 데이터 흐름을 정리한다. PostgreSQL은 프로세스 기반이다PostgreSQL은 멀티스레드가 아니라 멀티프로세스 구조다. 클라이언트 연결 하나당 OS 프로세스 하나가 붙는다. 이 구조의 중심에 있는 것이 Postmaster다.Postmaster — 모든 프로세스의 부모PostgreSQL 서버를 시작하면 가장 먼저 뜨는 프로세스가 Postmaster이며 역할은 세가지다.listen: 설정된 주소와 포트(기본 5432)에서 클라이언트 연결 요청을 대기fork: 연결 요청이 들어오면 새 백엔드 프로세스를 forkmangement: 백그라운드 프로세스(bgwriter, checkpointer, auto.. 2026. 4. 18.
대용량 파일 멀티파트 업로드, 정말 빠를까? 대용량 파일 업로드에서 "멀티파트로 쪼개면 빨라진다." 라고 가볍게 생각했다. 7GB 파일을 5가지 방식으로 실측한 결과, 네트워크가 병목인 환경에서는 모든 방식의 전송 속도가 동일했다.이 글에서 전달하려는 메시지는 세 가지다.멀티파트 청킹의 목적은 속도가 아니라 안정성과 서버 리소스 효율이다. (멀티파트로 청킹한 데이터를 병렬 업로드, 병렬 조회를 하면 물론 속도는 빨라진다. 하지만 네트워크 대역폭에 제한을 받는다.)병렬 업로드는 단일 TCP가 대역폭을 못 채울 때만 의미 있다.파일 업로드 경로에서 가장 느린 구간이 전체 속도를 결정한다. 병목이 아닌 구간을 최적화해도 전체 속도는 변하지 않는다.대용량 파일 업로드 파이프라인파일이 클라이언트에서 스토리지까지 도달하는 전체 경로는 다음과 같다.이 파이프라.. 2026. 4. 17.
PostgreSQL 내부 구조 — 시리즈를 시작하며 PostgreSQL(18버전) 의 내부 동작 원리를 공식 문서를 참고해 정리한 시리즈다. 목차 순서로 정리하지만 중간에 기본 개념이 생략된 부분이 있을 수 있다.PostgreSQL 18버전 공식 문서 링크: https://www.postgresql.org/docs/18/index.html 시리즈 목차각 편은 앞 편의 개념을 회수하며 이어진다.8KB 페이지와 Shared BuffersPostgreSQL의 모든 데이터가 저장되는 단위인 8KB 페이지의 내부 구조, 튜플 헤더, ctid, 그리고 메모리 캐시 역할을 하는 shared buffers.MVCC와 격리 수준PostgreSQL이 행을 덮어쓰지 않고 여러 버전을 만드는 이유. xmin/xmax 기반 가시성 판단, 4가지 격리 수준이 막는 이상현상, 쓰기.. 2026. 4. 16.
Spring 비동기 처리: MVC 비동기 → WebFlux → Virtual Threads 동기 블로킹 모델의 한계점Spring MVC의 비동기 확장Reactive 패러다임Java 21 Virtual Threads 각 접근 방식의 동작 원리와 트레이드오프를 정리했다.1. 도입: 동시성과 I/O 블로킹 문제전통적인 Java 웹 서버(Tomcat, Jetty 등)는 Thread-per-request 모델을 기반으로 동작한다.클라이언트 요청이 들어오면 스레드 풀에서 하나의 OS 스레드를 할당하고,해당 스레드가 요청의 전체 라이프사이클(수신 → 비즈니스 로직 → DB/외부 API 호출 → 응답 전송)을 담당한다.이 모델은 구조가 단순하고 디버깅이 용이하지만, I/O 바운드 작업이 많은 환경에서 한계를 드러낸다.핵심 문제는 I/O 대기 시간 동안 스레드가 아무 작업도 수행하지 않으면서도 점유 상태를 유.. 2026. 3. 26.
Dual Write와 데이터 정합성: 전파 지연과 장애 복구 전략 목차문제 정의: 분산 시스템과 Dual Write문제 유형 1: 상태 전파 지연 (일시적 불일치)문제 유형 2: 시스템 장애 (정합성 붕괴) Case A: 이벤트 유실 (Outbox, CDC) Case B: 유령 데이터 (이중 방어 전략: 선제적 검증, 상태 머신 & 자가 치유)결론: 대응 전략 요약1. 문제 정의: 분산 시스템과 Dual Write1.1 분산 시스템과 상태 관리분산 시스템은 하나의 목표를 위해 여러 노드가 네트워크로 협력하는 구조다.각 노드는 메모리를 공유하지 않으며, 상태 전달은 오직 네트워크 메시지 통신에 의존한다. 많은 서비스는 다음과 같이 여러 이종(Heterogeneous) 시스템에 상태를 분산 저장한다.RDBMS: 원본 데이터 영속화 (= Source of Truth)Cach.. 2026. 1. 1.
분산 시스템 시간 정합성: UTC, NTP Kafka 기반 분산 시스템에서 transactional outbox 테이블에 메시지가 분명 존재하는데도 발행되지 않는 문제를 겪었습니다. 원인은 Producer와 Poller(Message Relay: Polling)가 서로 다른 시간을 기준으로 이벤트를 판단하고 있었던 것이었습니다. 이 글은 이 경험을 바탕으로, 왜 분산 환경에서는 UTC를 공통 시간 기준으로 삼아야 하고, 그것만으로는 왜 충분하지 않은지를 정리한 글입니다. 목차문제 정의원인: “모든 서버의 시계는 같을 것이다”라는 착각해결책요약1. 문제 정의 이벤트 기반 아키텍처의 분산 시스템(Producer–Consumer)에서는물리적 시간 불일치(Clock Skew / Drift)와타임존 해석 차이로 인해 다음과 같은 문제가 발생할 수 있습니다.. 2025. 12. 23.
3D 모델 요청/응답 API 설계 클릭 한 번, 객체는 여러 개: 3D 지도 데이터 로딩 전략 비교3D 애플리케이션에서 지도 위 한 점을 클릭했을 때, 본인이 찾는 객체가 로딩되기를 기대한다.예를 들어 지도에서 스타벅스를 찾으면, 그 자리에 스타벅스 건물이 나타나는 장면을 떠올린다.하지만 실제 그 지점에는 스타벅스만 있는 것이 아니다.스타벅스 건물주변 나무가로등신호등땅(토지)즉, 하나의 좌표(타일) 위에는 여러 개의 3D 객체가 동시에 존재한다. 이것들이 꼭 하나의 모델일 필요는 없다 이 객체들은 하나의 3D 모델로 미리 합쳐져(Merge) 있을 수도 있고, 여러 개의 3D 모델로 분리되어 있을 수도 있다.어느 쪽이 정답이라는 건 없고, 이건 온전히 개발자의 설계 영역이다. 그래서 질문은 이렇다. "이 타일(지역, 공간)을 클릭했을 .. 2025. 12. 22.
현실판 자비스, 팔란티어 들어가며 단순한 대시보드나 리포팅 툴을 넘어, 데이터가 기업의 의사결정 구조를 어떻게 혁신할 수 있는지 예측하기 위해 이 시장의 선두주자인 '팔란티어(Palantir)'가 어떤 문제를 정의했고, 기술적으로 어떻게 해결했는지 간단하게 정리했습니다. 질문: 지식이 많아지면 우리는 더 똑똑해질까요, 아니면 더 혼란스러워질까요? 흔히 지식의 90%는 쓸모없는 파편이며, 이를 그룹핑하고 요약해낸 10%만이 비로소 가치 있는 정보가 된다고 합니다. 즉, 아무리 데이터가 많더라도 그 안의 관계(Relationship)가 정리되지 않으면 그건 지식이 아니고 '혼잡(Chaos)' 입니다. 1. 팔란티어가 정의한 문제: 데이터 사일로(Data Silo)영화 에서 토니 스타크가 "적의 위치는?", "플랜 B 가동해"라고 .. 2025. 12. 20.
[마이그레이션] Spring 4 → Boot 3.4: Java 17, Gradle, JAR, 그리고 제어권의 변화 최근 Spring 4 + Java 8 기반의 레거시 시스템을 Spring Boot 3.4 + Java 17로 마이그레이션 했습니다. 초기에는 단순한 라이브러리 버전 업그레이드로 접근했습니다. 하지만 마이그레이션을 진행할수록, 단순한 프레임워크 교체가 아닌 애플리케이션 아키텍처의 재설계였으며, 인프라에 종속되었던 시스템 제어권을 애플리케이션으로 가져오는 전환점이었습니다. 이번 글에서는 마이그레이션 과정에서 경험한 기술적 변화 5가지를 정리했습니다.서블릿 제어권: WAS(Tomcat) 중심에서 Application 중심으로배포 방식: 환경 종속적인 WAR에서 독립적인 JAR로빌드 도구: 정적인 Maven에서 유연한 Gradle로설정 관리: 파편화된 XML에서 중앙 집중형 YAML로런타임: Java 8(T.. 2025. 12. 12.
1시간 만에 ‘환승연애4 이상형 월드컵’ 배포하기 최종 결과물 링크: https://e-xchange-4-ideal-type-world-cup.vercel.app/GitHub 링크: https://github.com/minseojo/EXchange-4-Ideal-Type-World-Cup '환승연애 4 이상형 월드컵' 웹을 1시간 만에 만들기 위해Gemini Canvas로 디자인과 기능을 구현하고,완성된 프로젝트를 Vercel로 배포한 뒤,배포된 웹의 방문 통계를 Google Analytics로 확인하는 전체 과정을 정리했습니다.코드 작성 방법 (Gemini Canvas)만들고 싶은 앱은 다음과 같은 흐름을 가진 React 웹페이지입니다.이름/닉네임 + 성별 입력성별에 따라 환승연애 4 출연진 필터링토너먼트 형식으로 이상형 월드컵 진행최종 우승자를 공유.. 2025. 12. 8.
신뢰성을 위한 Timeout 처리와 멱등성 설계 전략 네트워크 통신에서 Timeout은 단순히 '실패'를 의미하지 않습니다.클라이언트와 서버 사이의 요청-응답 처리 과정에서 Timeout이 발생했을 때 생길 수 있는 3가지 시나리오를 살펴보고, 단순히 '재시도'를 선택했을 때 발생하는 정합성 문제와 이를 해결하기 위한 멱등성(Idempotency) 전략에 대해 정리했습니다. 목차네트워크 통신 흐름 네트워크 통신 개념 TCP 3-way Handshake 과정 Timeout 개념네트워크 Timeout 종류 Connection TimeoutRead TimeoutTimeout 발생 후 요청의 실제 상태 (3가지 경우)요청이 서버에 도달하지 못한 경우요청이 서버까지 도달했고 실패한 경우요청이 서버까지 도달했고 성공했지만 응답이 유실된 경우 (*가장 위험한 케이.. 2025. 12. 2.
5,000개 파일을 원자적으로 배포하기: Atomic Rename 패턴과 SeaweedFS 아키텍처 한 줄 요약: "데이터를 움직이지 말고, 데이터를 가리키는 포인터를 움직여라" 올해 3D 타일 배포 파이프라인을 새롭게 구축했습니다. 빌드 한 번에 최대 5,000개의 파일이 생성되고, 이런 빌드 결과물이 수십 회 이상 누적되어 하나의 배포 버전을 이룹니다. 가장 큰 기술적 난제는 물리적으로 분리된 DB(상태)와 오브젝트 스토리지(파일) 사이의 정합성 유지였습니다. 업로드 도중 장애가 발생하면, 스토리지에는 파일이 올라갔는데 DB에는 실패로 기록되는 — 두 시스템 간 상태 불일치가 언제든 일어날 수 있었습니다. 복잡하고 성능에 불리한 2PC(Two-Phase Commit) 대신, Atomic Rename 패턴을 적용하여 이 문제를 해결했습니다. 완성된 데이터를 스테이징 경로에 먼저 격리한 뒤, 배포 시.. 2025. 11. 27.
SRP를 만족하는 모듈화 리팩토링 과정 기존 GIS 엔진은 모놀리식 시스템입니다.전국 단위 데이터를 한 번에 처리하는 파이프라인은 수십 시간에서 많게는 수백 시간이 걸렸습니다. 이를 개선하기 위해 멀티노드 기반의 병렬 빌드 시스템으로 전환했습니다. 그 과정에서 모듈화 리팩토링을 진행했습니다.하지만 초기에 하나의 모듈에 많은 책임을 주어 확장성과 유지보수성을 떨어트렸습니다. 이 글에서는 SRP(Single Responsibility Principle)를 만족하지 않는 모듈이 어떤 문제를 일으키는지,그리고 이 문제를 해결하기 위해 SRP를 만족하는 모듈로 어떻게 구현 했는지 정리했습니다.모듈화 전/후 구조 차이 모듈화 전: 프로세스가 1개의 모듈을 실행하고, 해당 모듈에서 여러 내부 메서드(기능)를 실행하는 구조모듈화 후: 프로세스가 1개의 모듈.. 2025. 11. 16.
[I/O 멀티플렉싱] select · poll · epoll 참고레디스가 빠른 이유: https://velog.io/@redjen/%EB%A0%88%EB%94%94%EC%8A%A4%EB%8A%94-%EC%99%9C-%EB%B9%A0%EB%A5%BC%EA%B9%8Cselect 와 epoll: https://ozt88.tistory.com/21https://velog.io/@im2sh/%EC%86%8C%EC%BC%93-17-select%EB%B3%B4%EB%8B%A4-%EB%82%98%EC%9D%80-poll selectFD 한도: 기본 FD_SETSIZE=1024 (빌드 시 키우면 늘릴 수 있지만 보통 1024로 가정)FD 관심목록: 사용자 공간이 비트셋을 매 호출마다 재구성해 커널로 전달복잡도: 커널이 maxfd까지 선형 스캔 O(n), 사용자도 FD_ISSET로.. 2025. 10. 10.
Gzip, Zstandard, Brotli 압축 비교 - 3D 모델 파일 3D 모델 파일을 두 가지 목적을 가지고 압축을 고려했습니다.아카이빙(보관용)대용량 파일의 전송 효율화gizp, zstd, brotli 압축 코덱의 성능을 단순히 수치로만 비교했습니다.별도의 해석을 덧붙이지 않은 이유는, “어떤 코덱이 가장 좋다”는 절대적인 기준이 없기 때문입니다.압축의 목적과 사용 환경에 따라 최적의 선택은 달라집니다. 압축 목적에 따른 고려 사항 (예시)압축률은 어느정도여야 하는가? 50%? 20%? 10%?압축목적이 아카이빙이라면 며칠? 몇개월? 몇년?압축파일 조회 주기가 어느정도?압축목적이 전송용이라면 어떻게? 브라우저라면 브라우저는 압축 포맷을 지원하는가? (gzip, br 등)압축하려는 파일은 text? binary?압축속도는 얼마나 빨라야하는가? 0.0001초? 1초? 10.. 2025. 10. 7.