전체 글
-
루퍼스 10주차 후기카테고리 없음 2026. 4. 24. 14:03
벌써 10주차가 끝났다. 처음 루퍼스에 합류할 때만 해도 이만큼 올 줄 몰랐다. 매주 꾸역꾸역 해내는 느낌이었는데, 돌아보니 그 꾸역꾸역이 쌓여서 지금의 내가 된 것 같다.이번 10주는 유난히 마음에 남는 게 많았다. 기술적으로도 그렇고, 사람들 사이에서 느낀 것들도 그렇다. 휘발되기 전에 남겨두고 싶어서 글을 쓴다.사고의 주도권을 빼앗기지 않는다는 것요즘 내가 가장 많이 되뇌이는 말이 있다. 사고의 주도권을 빼앗기지 않는 것.개발이라는 일이 결국 뭘까를 계속 생각하게 된다. 기술은 변한다. 지금 내가 붙잡고 있는 프레임워크, 라이브러리, 아키텍처 패턴들은 5년, 10년 뒤에는 또 다른 이름으로 대체될 것이다. 그런데 변하지 않는 게 하나 있다면, 사고하는 능력 그 자체라고 생각한다. 이 산업은 그런 산..
-
실시간 랭킹에 Spring Batch 붙이기카테고리 없음 2026. 4. 17. 16:15
들어가며지난번에는 Kafka Consumer와 Redis ZSET으로 일간 랭킹을 만들었다. 이벤트가 들어오면 점수를 계산해서 ZSET에 밀어넣고, 일간 랭킹 API는 Redis만 조회하면 끝나는 단순한 구조였다.이번에 요구사항이 늘었다. 주간, 월간 랭킹도 제공해야 한다.처음엔 "일간이랑 똑같이 Redis 키만 기간별로 더 만들면 되겠네"라고 생각했는데, 며칠 고민해보니 이건 분명 배치의 영역이었다. 이 글은 그 과정에서 내린 결정들과, Spring Batch로 실제 어떻게 풀어냈는지를 기록한 것이다.1. 왜 배치인가 — 실시간의 한계를 마주할 때1-1. "Redis 키만 더 만들면 되지 않나?"일간이 잘 돌아가니까 주간/월간도 Redis ZSET으로 확장하고 싶은 유혹이 있었다. 키 이름만 ranki..
-
설명은 나중에 할테니 일단 타! - Kafka카테고리 없음 2026. 3. 27. 15:14
TL;DR: "나중에 할게"라는 말이 진짜 지켜지려면 세 가지가 필요하다. 적어야 잊지 않고, 누군가 꺼내서 해야 하고, 같은 일을 두 번 하면 안 된다. 분산 시스템에서 비동기 처리도 마찬가지다. 트랜잭셔널 아웃박스로 기록의 원자성을 잡고, 카프카로 전달과 순서를 보장하고, 멱등성 테이블로 중복 실행을 막는다. 이 글에서는 카프카의 핵심 구조부터 프로듀서/컨슈머 설정값, 그리고 이벤트 발행의 신뢰성을 확보하기 위한 설계가 어떤것들이 있는지 알아본다. 모르는 아저씨가 다가와서 "히히히 과자 줄게, 여기 타"라고 하면 미친 사람인줄 알고 도망가겠지만, 어디서 람보르기니가 드리프트를 하면서 멈추며 차 문을 열고 "드디어 찾았다....! 설명은 나중에 할 테니 얼른 타!"라고 하면 왠지 모르게 본능에 이끌려..
-
식당으로 이해하는 Thread의 진화 - 발표 회고!카테고리 없음 2026. 3. 22. 13:05
바쁜 식당은 어떻게 진화했는가이번 주에 오픈톡 발표를 준비하면서 자바의 스레딩 모델과 I/O 전략이 어떻게 진화해왔는지를 좀 더 공부해봤다. Green Thread부터 Virtual Thread까지, 흐름을 정리하면서 그동안 애매하게 알고 있던 것들이 많았구나 싶었다. 발표 준비 과정에서 배운 것들을 회고 겸 정리해본다. 왜 이 주제를 골랐나회사에서 서버를 운영하면서 동시 요청 처리 문제를 일상적으로 마주한다. 피크 시간에 요청이 몰리면 스레드 풀이 바닥나는 경험을 해봤다. CPU 사용률은 40%인데 응답 시간이 30초를 넘기는, 자원은 남는데 서비스가 죽는 상황.이 문제를 이해하려면 결국 자바가 스레드를 어떻게 다뤄왔는지를 알아야 했다. 그래서 이번 주 공부 주제로 잡았고, 발표 자료를 만들면서 "식당..
-
가라앉지 않는 배를 만드는 법 - Resilience4j카테고리 없음 2026. 3. 19. 23:17
TL;DR: 배가 구멍이 뚫려도 가라앉지 않는 건 격벽 덕분이다. 소프트웨어도 마찬가지다. Resilience4j는 외부 API 장애가 서비스 전체로 퍼지지 않도록 Retry · CircuitBreaker · RateLimiter · Bulkhead · TimeLimiter 다섯 가지 보호 장치를 제공한다. 전화 다시 걸기, 두꺼비집 차단기, 놀이공원 입장 제한등 일상 속 비유로 감을 잡으려고 쓴다.배는 왜 가라앉지 않는가대부분의 배는 침몰하지 않는다.배 밑바닥에 구멍이 뚫려 물이 들어와도, 격벽(Bulkhead)이 침수를 한 구획 안에 가둬버리기 때문이다. 현대 선박은 선체 내부를 여러 개의 수밀 구획으로 나눠서, 한두 개 구획이 침수되더라도 나머지 구획의 부력으로 배 전체가 떠 있을 수 있도록 설계된..
-
조회의 성능을 좌우하는것은?카테고리 없음 2026. 3. 13. 17:55
TL;DR: 10만 권의 책이 쌓인 도서관에서 원하는 책을 빠르게 찾으려면, 책을 어떤 기준으로 정리해두느냐가 전부다. DB 인덱스도 같은 문제다. 복합 인덱스의 컬럼 순서를 결정하는 과정 — 선두 컬럼 선택, brand_id 분리, deleted_at 제외 — 을 EXPLAIN ANALYZE로 확인하며 정리했다.도서관에서 책을 찾는 법10만 권의 책이 있는 도서관을 상상해보자.책이 아무 기준 없이 쌓여 있다면, 원하는 책을 찾으려면 1번 선반부터 끝까지 전부 훑어야 한다. 10만 권을 하나씩. 이게 Full Table Scan이다.그런데 출판사별로 선반을 나눠두면 어떨까. "A출판사 책 찾아줘"라는 요청에는 해당 선반만 보면 된다. 10만 권 대신 1,000권만 훑으면 끝이다. 하지만 "전체에서 평점 ..
-
동시성 제어, 격리 수준, 락 전략카테고리 없음 2026. 3. 6. 17:43
락이나 격리 수준 개념 자체는 알고 있었다. 근데 막상 왜 티케팅에 낙관적 락을 쓰면 안 되는가, 일반 Atomic UPDATE로 안 되는 케이스는 뭔가" 같은 질문을 받으면 머릿속에서 정리가 안 됐다. 아는 것과 이해의 차이 같아서 이번 기회에 제대로 정리해봤다.ACID — 트랜잭션이 뭘 보장해주는지부터동시성 얘기 전에 트랜잭션이 뭘 약속하는지 짚고 넘어가야 한다.Atomicity (원자성): 전부 성공하거나, 전부 실패하거나. 재고는 빠졌는데 주문이 안 만들어지는 상황은 없어야 한다.Consistency (일관성): 트랜잭션 전후로 비즈니스 규칙이 깨지면 안 된다. 재고가 음수가 되면 안 된다는 것.Isolation (격리성): 동시에 도는 트랜잭션끼리 서로 간섭하지 않아야 한다. 여기서 "어느 정도..
-
레이어 책임 경계를 고민한 기록카테고리 없음 2026. 2. 27. 17:38
시작은 위화감이었다이커머스 프로젝트에서 Brand, Product, Like, Order 4개 도메인을 구현하고 나서, 코드를 다시 읽는데 뭔가 찜찜했다.// BrandRemover.kt (Domain Layer)@Componentclass BrandRemover( private val brandReader: BrandReader, private val brandRepository: BrandRepository, private val productReader: ProductReader, // ← 이게 왜 여기에?) { fun remove(id: Long) { if (productReader.existsSellingByBrandId(id)) { thro..