본문 바로가기

WIL

[WIL] 10주차 회고 루퍼스 10주차 WIL - (Spring Batch 기반 주간/월간 랭킹 시스템 구현) 이번 10주차에 배운 것Round 9에서 만든 실시간 일간 랭킹 위에, Spring Batch로 주간/월간 집계를 얹는 작업이었다. 일간은 Redis로 실시간 계산되지만, 7일·30일치를 매번 계산하면 DB가 버티지 못한다. 그래서 새벽에 배치를 한 번 돌려 TOP 100만 뽑아 별도 테이블(Materialized View)에 박아두고, API는 그걸 읽기만 하게 했다.Spring Batch는 이번에 처음 써봤는데, 알고 보니 이전 실무에서 MyBatis ResultHandler로 10만 건짜리 엑셀 만들던 작업이랑 거의 똑같은 일이었다. 그때 내가 직접 짰던 청크 처리, 크론 스케줄, 실패 파일 정리 같은 게 Spr.. 더보기
[WIL] 9주차 회고 루퍼스 9주차 WIL - (이벤트 기반 실시간 상품 랭킹 시스템) 이번 9주차에 배운 것Kafka로 흘러나오는 이벤트를 Redis ZSET에 점수로 누적시켜서 실시간 랭킹을 만드는 작업이었다. 조회 0.1, 좋아요 0.2, 주문 0.7 식으로 이벤트마다 가중치만 다르게 줘서 점수로 환산하는데, 이렇게 단순한 방식으로 "인기 상품"이 자연스럽게 만들어지는 게 신기했다. ZSET 하나만으로 점수 누적(INCRBY), Top-N 조회(ZREVRANGE), 일자 간 합산(ZUNIONSTORE)까지 다 해결되니까 직접 짜야 할 코드가 확 줄어든다는 걸 체감했다.키는 일별로 끊고(ranking:all:yyyyMMdd) TTL을 2일로 잡아서 스토리지를 단순하게 유지했다. 자정이 지나면 어제 점수가 그대로 사라지는.. 더보기
[WIL] 8주차 회고 루퍼스 8주차 WIL - (Redis 기반 대기열 시스템 구현) 이번 8주차에 배운 것블랙프라이데이처럼 트래픽이 폭증하는 상황에서 Rate Limiting(즉시 거절)이 아니라 "대기"라는 선택지가 있다는 것을 배웠다. DB 커넥션 풀 50개, 주문 처리 200ms 기준으로 이론적 최대 250 TPS인데, 비주문 API 트래픽까지 고려하면 실효175 TPS라는 숫자를 직접 산출해보면서 "시스템이 감당 가능한 속도"를 역산하는 사고방식이 생겼다. Redis Sorted Set으로 대기열을 만들고, 스케줄러가 100ms마다 18명씩 토큰을 발급하고, Interceptor에서 토큰을 검증하는 파이프라인을 구현했다. 처음에는 1초에 175명을 한꺼번에 발급하려 했는데, 그러면 175명이 동시에 주문 API를.. 더보기
[WIL] 7주차 회고 루퍼스 7주차 WIL - (이벤트 기반 아키텍처 및 Kafka 파이프라인 구현) 이번 7주차에 배운 것하나의 @Transactional 에 핵심 로직과 부가 로직을 전부 묶어 두면, 외부 API 지연이 DB 커넥션 점유로 이어져 서비스 전체에 영향을 준다는 것을 배웠다."이 로직이 실패하면 주문 자체를 롤백해야 하는가?" 라는 질문 하나로 핵심 트랜잭션과 후속 처리를 나눌 수 있었다.트랜잭션을 분리한 뒤에는 이벤트 유실 문제가 따라왔기때문에 이걸 해결하기 위해 Transactional Outbox Pattern 을 도입했다.이런 고민이 있었어요파티션 키를 누구 기준으로 잡을 것인가의 고민이 있었다. 파티션 키를 이벤트를 생성하는 주체(orderId)가 아니라 상태를 변경하는 대상(productId) 기.. 더보기
[WIL] 6주차 회고 루퍼스 6주차 WIL - (PG 연동 및 장애복구) 이번 6주차에 배운 것외부 시스템(PG)과 연동할 때는 "성공/실패" 두 가지만 있는 게 아니라, "모르는상태(PENDING)"가 가장 다루기 어렵다는걸 체감했다. 타임아웃이 터지거나 서킷브레이커가 열리면 PG에서 실제로 결제가 됐는지 안 됐는지 알 수 없는데, 이때 섣불리 성공이나 실패로 처리하면 중복결제나 누락이 발생한다.서킷브레이커는 예외(실패)만 카운트하면 부족하다는 것을 배웠다. Slow Call 감지를 별도로 설정해야 느린 응답도 장애로 인식할 수 있다.이런 고민이 있었어요PG 요청이 타임아웃으로 실패했는데, PG 쪽에서는 결제가 완료된 경우를 어떻게 처리할지 고민이 있었다.즉시 getPaymetByOrderId() 로 PG 상태를 조회해서 .. 더보기
[WIL] 5주차 회고 루퍼스 5주차 WIL - (index 최적화 & 캐시 설계) 이번 5주차에 배운 것인덱스는 무조건 많은 게 좋은 게 아니라, 추가할수록 쓰기(Insert/Update) 성능과의 트레이드오프가 발생한다는걸 알게되었다.다양한 캐시 읽기/쓰기 전략(Cache Aside, Write Through 등)의 쓰임과 목적을 테스트하면서 체감하였다.인덱스를 걸 때 카디널리티(Cardinality, 중복도가 낮고 고유값이 많은 정도)가 높은 순서대로 복합 인덱스를 구성해야 성능이 극대화된다는걸 경험했다.이런 고민이 있었어요목록 API 응답에 likeCount 가 포함되어 있는데, 좋아요를 누를 때마다 목록 캐시를 evict 하려면 어떤 목록 키에 해당 상품이 들어 있는지 특정할 수 없는 구조였다. 그럼 목록에서 like.. 더보기