본문 바로가기

분류 전체보기

(319)
Nest의 DI(Dependency Injection) NestJS DI 동작 단계별 흐름ApplicationConfig 초기화부트스트랩 시 ApplicationConfig가 먼저 생성됩니다.글로벌 미들웨어, 파이프, 인터셉터 등 전역 설정을 담당합니다.이후 DI Container가 생성되어 의존성 그래프 구축이 시작됩니다.모듈 스캔 (Dependency Scanner)모든 모듈 내 프로바이더, 컨트롤러, 익스포트를 스캔합니다.각 provider의 토큰을 계산해 Container에 등록합니다.forwardRef를 활용해 순환 참조 가능성을 미리 추적합니다.InstanceWrapper로 상태 관리각 의존성은 InstanceWrapper로 감싸집니다.상태: isPending(생성 중), isResolved(완료), isRejected(실패)를 관리합니다.isPe..
Log 영속성을 위한 MQ 도입 💡 로그 유실 없는 비동기 로그 수집 아키텍처보안 로그 수집 시스템에서 단일 장애가 발생했을 때 로그 유실 위험이 있다는 문제를 발견했습니다. 기존에는 로그를 바로 DB에 기록하는 동기 구조였습니다. 하지만, 트래픽이 급증하게 되면 다음 문제가 발생할 수 있습니다.DB Connection Pool 고갈DML Lock 경합이를 해결하기 위해 BullMQ 기반의 Queue 시스템과 Redis를 활용한 비동기 아키텍처로 전환하여 DB 부하를 차단하고, 트래픽 버스트를 안정적으로 받아낼 수 있는 비동기 구조로 개선했습니다.Redis의 Eviction 정책, AOF 설정 등 운영 환경에서 고려해야 할 포인트들도 정리했으며, 장애 발생 시 유실 없는 처리를 위해 재처리 및 장애 대응 방안까지 반영했습니다. 이 글..
MySQL에서의 Lock 경합 문제 해결과 성능 개선 💡 MySQL Lock 경합 → Redis + BullMQ 기반 비동기 아키텍처로 해결좋아요 처리 시스템에서 단순 증가 연산만 수행하던 Like 기능이 TPS(초당 처리량)가 증가하면서 MySQL Row-Level Lock 경합을 유발해 시스템 성능 저하가 심화됐습니다.Redis 캐시 도입, Pipeline 최적화, 인덱스 튜닝 등 다양한 성능 개선 시도를 거쳤으나, 결국 DB Connectoin Pool 고갈 및 Lock 경합 현상이 반복 발생되었습니다. 단순 캐시 레벨에서의 해결의 한계가 명확했습니다.BullMQ 기반 비동기 Queue 아키텍처로 전환으로 Lock 경합을 근본적으로 제거했고, 그 결과는 아래와 같습니다. 성능 지표 전환 전 전환 후 개선율 평균 응답 속도580 ms25 ms약 ..
Bullmq Document + CS 관점으로 다시 생각 BullMQ는 왜 Queue로 설계가 되어있을까? Queue는 대표적인 FIFO(First In, First Out) 구조입니다. 비동기 작업처리에 직관적이고 예측이 가능하다는 장점을 갖고 있습니다.장점은 아래와 같습니다. 작업 순서가 명확합니다. 들어오는 순서대로 작업이 처리됩니다. 해당 내용은 큐잉 이론과도 연결됩니다.생산자와 소비자 패턴을 구현할 때 적합합니다. 생산자는 큐에 넣고, 소비자는 큐에서 작업을 빼내서 처리합니다.병렬 처리와 동시성 관리입니다. 여러 소비자가 하나의 큐에서 작업을 꺼내서 처리할 수 있어 병렬 처리가 가능하고, 여러명의 소비자가 하나의 큐에 접근해서 작업을 처리할 수 있어 동시성 관리가 가능합니다.확장성입니다. 큐에 작업이 많이 쌓이면서 Worker를 늘려 처리량을 조절할 ..
MySQL의 기본 -13 B-Tree 인덱스 vs Clustered 인덱스 (클러스터형 인덱스) 차이점 정리 B-Tree 인덱스와 클러스터형 인덱스(Clustered Index)의 차이를 명확히 이해하는 것은 MySQL 등 RDBMS의 성능 최적화에 매우 중요하다. 두 인덱스 모두 B+Tree 구조를 기반으로 하지만, 저장 방식과 역할에서 차이가 크다. B-Tree 인덱스는 균형 잡힌 트리 구조로, 각 노드가 정렬된 키와 포인터를 가진다. 모든 리프 노드는 같은 깊이에 있어 검색 속도가 일정하다. 데이터는 물리적으로 정렬되지 않고, 보조 인덱스는 B-Tree 기반으로 동작한다. 예를 들어 기본 키(id)는 클러스터형 인덱스지만, name 같은 컬럼에 생성된 인덱스는 일반 B-Tree 보조 인덱스다. 클러스터형 인덱스는 데이터 자..
MySQL의 기본 -12 클러스터형 인덱스 클러스터형 인덱스(Clustered Index)에서 페이지 분할이 일어나는 원리에 대해 설명하자면, 클러스터형 인덱스는 기본적으로 B+Tree 구조를 이용해 데이터를 저장하고 정렬한다. 이때 페이지 분할(Page Splitting)은 새로운 레코드를 삽입할 때 해당 페이지가 꽉 차 있으면 발생한다. 예를 들어, 하나의 페이지에 10개의 레코드를 저장할 수 있는데, 이 페이지가 가득 차 있으면 새로운 데이터를 넣을 공간이 없어 기존 데이터를 나누어 새로운 페이지를 생성해야 한다. 특히 클러스터형 인덱스는 기본 키 순서대로 데이터가 정렬되므로, 만약 UUID처럼 랜덤한 값이 기본 키라면 데이터가 중간에 삽입되어야 하는 상황이 자주 발생한다. 이 경우 중간 페이지가 가득 차면 페이지 분할이 ..
MySQL의 기본 -11 체크포인트(Check point)란? 체크포인트(Checkpoint)는 InnoDB가 데이터 무결성을 보장하고, 장애 발생 시 복구 시간을 단축하기 위해 사용하는 핵심 메커니즘이다. MySQL(InnoDB)은 데이터를 디스크에 영구 저장할 때 WAL(Write-Ahead Logging) 방식을 따른다. 이는 데이터 변경 내용을 먼저 로그에 기록한 뒤 나중에 실제 데이터를 디스크에 반영하는 기법으로, 데이터 무결성과 복구를 효율적으로 지원한다. 체크포인트는 특정 시점에서 버퍼 풀(Buffer Pool)에 있는 변경된 데이터를 디스크로 플러시(Flush)하는 작업을 수행한다. 체크포인트가 필요한 이유는 크게 두 가지다. 첫째, 시스템 장애 발생 시 복구 시간을 단축하기 위함이다. InnoDB는 데이터를 ..
멱등성(Idempotency)이란? 멱등성 멱등성(Idempotency)에 관한 이해는 RESTful API 설계에서 매우 중요하다. 멱등성을 만족한다는 것은 같은 요청을 여러 번 반복해서 보내더라도 서버의 최종 상태가 변하지 않는다는 의미다. 예를 들어, ‘좋아요’를 추가하는 API가 멱등성을 지닌다면 PUT 요청을 여러 차례 보내더라도 ‘좋아요’ 상태는 한 번만 반영되어 변하지 않는다. 마찬가지로, DELETE 요청을 여러 번 보내더라도 ‘좋아요 해제’ 상태가 계속 유지된다. RESTful API 원칙에 따르면, PUT 메서드는 리소스를 완전하게 대체하는 역할을 하며, 리소스가 없으면 생성하고 있으면 교체한다. 이러한 특성 덕분에 PUT은 멱등성을 자연스럽게 만족한다. DELETE 역시 멱등성을 가지는데, 리소스가 이미 삭제되었거나 존..