본문 바로가기

분류 전체보기

(28)
Kafka를 제대로 쓰고 싶어서 MSA로 전환한 이야기 개인 프로젝트 bowchat을 모놀리식으로 시작해서 MSA로 전환했다.단순히 서비스를 쪼개는 게 목적이 아니었다.Kafka를 제대로 써보고 싶었고, 서비스 간 데이터 정합성 문제를 직접 해결해보고 싶었다.이번 글에서는왜 전환했는지전환하면서 어떤 문제를 만났는지각 문제를 어떻게 해결했는지를 중심으로 정리해보려 한다.왜 전환했는가처음엔 모놀리식에 Kafka를 붙였다.입찰 이벤트를 Kafka로 발행하고 Consumer가 처리하는 구조였는데, 실제로 써보니 이상했다.[모놀리식 + Kafka]같은 서비스 안에서Producer → Kafka → Consumer결국 DB도 같고, 코드도 같고→ 그냥 메서드 호출이랑 다를 게 없는 구조Kafka의 핵심은 "이벤트를 발행하면 구독한 서비스들이 각자 독립적으로 반응"하는 ..
Kafka Consumer Lag 600을 0으로 만든 방법 (k6 + Prometheus +Grafana) 개요 Kafka 기반 실시간 경매 시스템 부하 테스트 및 병목 개선 (k6 + Prometheus + Grafana)개인 프로젝트로 Kafka를 기반으로 한 실시간 경매·채팅 플랫폼을 직접 설계하고 배포했다.이 서비스는 WebSocket을 통해 실시간으로 입찰 및 채팅 이벤트를 Kafka로 전송하고,여러 Consumer들이 메시kimmangtae.tistory.com Kafka 기반 경매 입찰 시스템에 대해 트래픽 테스트를 진행하고, Consumer Lag가 급격히 증가하는 현상을 관찰했다.이번 글에서는왜 Lag가 발생했는지어떤 설정이 병목을 만들었는지실제 배포 환경(CPU 2 코어)에서 어디까지 늘리는 게 합리적인지그리고 개선 후 지표가 어떻게 달라졌는지를 중심으로 정리해보려 한다.테스트 환경 요약배포..
Thread.sleep()은 왜 위험할까? Kafka DLQ로 안전하게 재시도 처리하기 문제의 시작: 왜 Thread.sleep()을 넣었을까?실시간 경매 시스템을 개발하면서 동시성 문제에 직면했다. 여러 사용자가 동시에 같은 경매에 입찰할 때, 낙관적 락(@Version)을 사용해 데이터 정합성을 보장하고 있었다.@Entitypublic class Auction { @Version private Long version; // 낙관적 락 private Long currentPrice; // ...}하지만 문제가 있었다. 동시 입찰이 발생하면 OptimisticLockingFailureException이 발생하고, 입찰이 실패했다. 사용자 입장에서는 "입찰 실패" 메시지만 보게 되는 것이다.첫 번째 시도: 수동 재시도 로직"그럼 재시도하면 되지 않을까?" 라는 생각으로..
로컬에서 Spring Boot 서버 2개 띄워 HAProxy로 트래픽 분산해보기 개요회사 면접을 준비하다가 HAProxy 라는 키워드를 접하게 되었다. 단순히 개념으로만 이해하기보다는, 직접 동작을 확인해보고 싶어서로컬 환경에서 간단한 Spring Boot 서버 두 개를 띄우고 HAProxy를 이용해 트래픽을 분산시키는 실습을 진행했다.이를 통해 “리버스 프록시”가 실제로 어떤 역할을 하는지 직접 체감해볼 수 있었다.리버스 프록시란리버스 프록시란 클라이언트와 웹 서버 간의 중개자 역할을 하는 서버로,클라이언트로부터의 요청을 대신 받아 웹 서버에 전달하고, 웹 서버의 응답을 클라이언트에게 전달하는 역할을 한다.이를 통해 리버스 프록시는 웹 서버의 부하를 분산시키고, 보안을 강화하는 등 다양한 기능을 수행할 수 있다.기본 작동 원리는 클라이언트가 리버스 프록시에 요청을 보내면, 리버스 ..
Kafka 기반 실시간 경매 시스템 부하 테스트 및 병목 개선 (k6 + Prometheus + Grafana) 개인 프로젝트로 Kafka를 기반으로 한 실시간 경매·채팅 플랫폼을 직접 설계하고 배포했다.이 서비스는 WebSocket을 통해 실시간으로 입찰 및 채팅 이벤트를 Kafka로 전송하고,여러 Consumer들이 메시지를 처리하여 PostgreSQL과 Redis에 결과를 반영하는 구조로 되어 있다.실제 서비스 운영 환경을 가정해 1000명의 사용자가 동시에 입찰 요청을 보냈을 때의 시스템 부하를 검증해 보고자,EC2 상에 배포된 서버에 대해 k6를 이용한 부하 테스트를 진행했다.테스트는 실시간 입찰 마감 상황(수 초 내 동시 요청)을 재현하여 Kafka, Redis, PostgreSQL의 처리 성능을 관찰하는 것이 목적이었다. 테스트 환경 및 시나리오 구성실험 환경은 AWS EC2(c7i-flex.large..
Copilot + JUnit 테스트 코드 자동 생성 환경 구성 솔직히 테스트 코드 작성이 귀찮았다.같은 패턴을 계속 반복하다 보니, ‘어차피 코파일럿 자주 쓰는데, 주석만 통일해서 비슷한 코드가 자동으로 나오게 하면 되지 않을까??’ 싶었다. 그래서 Copilot을 커스터마이징해서 주석만 치면 테스트가 만들어지는 구조를 만들어보았다. 세팅1. Copilot 플러그인 설치IntelliJ → Preferences → Plugins → “GitHub Copilot” → 설치로그인하고 “Enable for all languages” 체크.단축키는 Alt + \ (Mac은 Option + ) 2. Copilot 규칙 파일 추가프로젝트 루트에 copilot-instructions.md 파일을 하나 만든다.이 파일이 Copilot한테 “테스트는 이렇게 만들어라”를 알려주는 가이..
Monitor(모니터) 개념과 자바 예제 Monitor개요오늘은 Monitor(모니터)에 대해 알아보고자 한다. Monitor(모니터)는 동기화를 위한 고수준 추상화 도구이다.앞서 살펴본 SpinLock, Mutex, Semaphore는 프로그래머가 직접 락(lock)과 해제(unlock)을 신경 써야 했지만, 스핀락(spinlock) 뮤텍스(mutex) 세마포(semaphore) 각각 특징과 차이개요동기화를 위한 여러 전략과 각각의 특징과 차이에 대해 알아보려고 한다.본격적으로 살펴보기 전에 알아두어야 할 개념이 있다.racecondition(경쟁조건)여러 프로세스/스레드가 동시에 같은 데kimmangtae.tistory.com 모니터는 이 과정을 자동으로 관리해준다. 쉽게 말하면, 락(lock) + 조건 변수(condi..
스핀락(spinlock) 뮤텍스(mutex) 세마포(semaphore) 각각 특징과 차이 개요동기화를 위한 여러 전략과 각각의 특징과 차이에 대해 알아보려고 한다.본격적으로 살펴보기 전에 알아두어야 할 개념이 있다.racecondition(경쟁조건)여러 프로세스/스레드가 동시에 같은 데이터를 조작할 때 타이밍이나 접근 순서에 따라 결과가 달라질 수 있는 상황.synchronization(동기화)여러 프로세스/스레드를 동시에 실행해도 공유 데이터의 일관성을 유지하는 것critical section(임계 영역)공유 데이터의 일관성을 보장하기 위해 하나의 프로세스/스레드만 진입해서 실행 가능한 영역 이라 한다.이와 같이 하나만 접근 가능하도록 하는 것을 mutual exclusion이라고 한다. 이제 이러한 문제를 해결하기 위해 어떤 동기화 전략들이 있는지 살펴보자. 하나의 프로세스/스레드만 진입..