주제 허브
프레임워크 뒤에서 무슨 일이 벌어지는지 설명할 수 있나
Spring과 JVM 백엔드
빈 생명주기와 프록시, 트랜잭션 이벤트, 배치 청크와 힙 덤프, ArchUnit으로 세운 가드레일. 스프링을 쓰는 글이 아니라 스프링이 왜 그렇게 동작하는지 파헤친 글을 모은다.
먼저 읽을 글
직접 만들고 재 본 것 spring-internals-lab로 다시 읽는 Spring 1 - 이 프로젝트는 무엇을 검증하려는가 직접 만들고 재 본 것 Heap Dump가 가리킨 곳은 데이터가 아니라 영속성 컨텍스트였다: Tasklet에서 Chunk로, XSSF에서 SXSSF로 직접 만들고 재 본 것 위반 480건 위에 아키텍처 규칙을 도입하기: 신규 코드는 100% 강제, 레거시는 점진 정리 직접 만들고 재 본 것 왜 이벤트가 안 먹히지? @TransactionalEventListener가 무시되는 이유와 해결법 기술 블로그 리뷰 네이버 D2 「@RequestCache: HTTP 요청 범위 캐싱을 위한 커스텀 애너테이션 개발기」 리뷰 — 캐시의 수명을 '요청 하나'로 맞추면 TTL 고민이 사라진다, 그리고 @RequestScope가 안 되는 이유 기술 블로그 리뷰 우아한형제들 「Spring Batch와 Querydsl」 리뷰 — offset을 버린 Reader가 21분을 4분으로 만든 이유, 그리고 그 Reader가 답하지 않는 두 가지 컨퍼런스 발표 리뷰 SLASH 22 리뷰 - Java Native Memory Leak 원인을 찾아서: RSS와 NMT의 2GB 차이, jemalloc 프로파일, C2 컴파일러, Graal JIT
직접 만들고 재 본 것
73편- spring-internals-lab로 다시 읽는 Spring 1 - 이 프로젝트는 무엇을 검증하려는가
- Heap Dump가 가리킨 곳은 데이터가 아니라 영속성 컨텍스트였다: Tasklet에서 Chunk로, XSSF에서 SXSSF로
- 위반 480건 위에 아키텍처 규칙을 도입하기: 신규 코드는 100% 강제, 레거시는 점진 정리
- 왜 이벤트가 안 먹히지? @TransactionalEventListener가 무시되는 이유와 해결법
- 무너지는 Spring 서버 1 - CPU는 놀고 있는데 API가 느리다: 업스트림 하나가 무관한 엔드포인트를 죽이는 과정을 thread dump 세 장으로 읽기
- 커넥션과 세션 - 커넥션 풀이 실제로 아끼는 것
- 클래스 로딩과 기동 시간 - 리플렉션의 비용과 AOT가 바꾸는 것
- spring-internals-lab로 다시 읽는 Spring 2 - BeanDefinition과 등록 단계
- spring-internals-lab로 다시 읽는 Spring 5 - Bean lifecycle과 후처리기
- spring-internals-lab로 다시 읽는 Spring 4 - 의존성 주입과 후보 선택
- spring-internals-lab로 다시 읽는 Spring 8 - DispatcherServlet과 MVC 요청 흐름
- spring-internals-lab로 다시 읽는 Spring 6 - 프록시와 AOP
- spring-internals-lab로 다시 읽는 Spring 3 - refresh()와 Bean 생성 파이프라인
- spring-internals-lab로 다시 읽는 Spring 9 - Spring Boot는 무엇을 자동으로 조립하는가
- spring-internals-lab로 다시 읽는 Spring 7 - @Transactional의 실체
- 리액티브와 백프레셔 - WebFlux가 해결하는 것과 옮기는 것
- JIT 컴파일 - 계층 컴파일, 인라이닝, 역최적화
- spring-lite로 이해하는 Spring 구현 5 - MiniSpringApplication과 자동 설정 조립 방식
- 모듈러 모놀리스 - 경계를 코드로 강제하는 방법
- spring-lite로 이해하는 Spring 구현 4 - DispatcherServlet과 MVC 요청 처리 파이프라인
- spring-lite로 이해하는 Spring 구현 3 - ProxyFactory, @Transactional, JdbcTemplate 연결
- spring-lite로 이해하는 Spring 구현 2 - AnnotationConfigApplicationContext로 보는 IoC와 생명주기
- spring-lite로 이해하는 Spring 구현 1 - 프로젝트 구조와 설계 범위
- 시크릿 관리 - 로테이션과 주입 경로
- 가상 스레드를 켜서 37배 느려진 엔드포인트 - 핀닝과 상한 없는 admission을 재다
- Security 필터 체인 - 인증과 인가는 실제로 어디에 꽂히는가
- G1과 ZGC가 p99에 남기는 차이 - 300배 짧은 pause가 꼬리의 11%를 가져갔다
- GC 알고리즘 비교 - G1, ZGC, Shenandoah가 각자 무엇을 포기하는가
- 모듈식 모놀리스를 선택한 이유 — MSA의 유혹을 거부하기
- Spring Batch의 구조 - 청크, 파티셔닝, 재시작과 메타데이터
- 가상 스레드의 내부 - 스케줄러와 캐리어, 핀닝, 그리고 쓰지 않아야 할 때
- 프록시의 한계 - self-invocation, final, JDK와 CGLIB의 선택
- 동시성 도구의 비용 - synchronized, ReentrantLock, CAS가 경쟁에서 갈리는 지점
- ParityPay로 검증하는 결제 정합성 2 - 잠금을 필요 이상으로 오래 쥐고 있었다: 추론을 측정으로 바꾼 기록
- JWT의 구조와 검증 - 서명 알고리즘, 만료, 그리고 폐기의 한계
- 트랜잭션 전파 7종 - 각 옵션이 커넥션과 롤백에 남기는 결과
- 자바 메모리 모델 - happens-before, volatile, 그리고 final의 안전 공개
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 1 - 시스템을 압박하기 시작한 배치
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 2 - 전체 삭제 후 전체 등록 구조의 위험성
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 3 - 청크 분할과 병렬 처리로 재설계하기
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 4 - 분산 락이 있어도 레이스가 발생한 이유
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 5 - 배타적 락과 조건부 해제로 순서를 보장하기
- 대량 배치 안정성을 높이기 위한 구조 개선: Part 0 - 왜 이 배치는 가끔 터질까?
- Shadow Release로 조회를 옮기기: MyBatis 결과와 QueryDSL 결과를 나란히 비교하며 전환한 기록
- 모든 도메인이 100% 정합성을 요구하지는 않는다: Post-Commit 이벤트와 재시도 3회 정책을 정한 기준
- 폴링 배치를 SQS 이벤트 파이프라인으로 바꾼 이유: 재시도, DLQ, 메시지 ID 멱등
- 정산이 진행되는 동안 기준 데이터 수정을 막는 방법: 상태 플래그와 AOP로 만든 경량 락
- @RestController는 무엇을 의미하는가
- @SpringBootApplication은 실제로 무엇을 하는가
- Spring Boot DevTools를 언제 써야 하는가
- Java의 Garbage Collection을 어떻게 이해해야 할까
- Spring Bean Lifecycle 정리
- 대용량 지분율 데이터 처리 성능 개선과 동시성 제어 전략
- JSP 기반 시스템의 구조적 문제를 해결한 아키텍처 전환기: MyBatis와 JPA 공존 환경의 데이터 정합성 전략
- 백엔드 시스템 로깅 베스트 프랙티스
- @TransactionalEventListener 빠른 체크 노트
- Spring에서 이해해야 할 JPA 아키텍처
- Spring에서 Java 21을 도입할 때 체크할 것
- JVM은 무엇을 하는가
- Statement와 PreparedStatement는 무엇이 다른가
- Spring AOP 핵심 정리
- @ControllerAdvice와 @RestControllerAdvice 정리
- Spring Data JPA에서 동적 쿼리를 다루는 방법
- Spring 예외 처리 전략 정리
- Spring 애플리케이션에서 예외를 설계하는 방법
- Filter, Interceptor, AOP의 차이와 선택 기준
- Spring과 JPA에서 Race Condition을 다루는 방법
- Spring의 IoC와 DI를 어떻게 이해할 것인가
- Spring 애플리케이션에서 페이지네이션을 설계하는 방법
- Querydsl을 사용하는 이유와 기본 패턴
- Connection Pool
- GraphQL with Spring Boot
- Spring Boot에서 외부 API 연동을 설계할 때 보는 것
기술 블로그 리뷰
9편- 네이버 D2 「@RequestCache: HTTP 요청 범위 캐싱을 위한 커스텀 애너테이션 개발기」 리뷰 — 캐시의 수명을 '요청 하나'로 맞추면 TTL 고민이 사라진다, 그리고 @RequestScope가 안 되는 이유
- 우아한형제들 「Spring Batch와 Querydsl」 리뷰 — offset을 버린 Reader가 21분을 4분으로 만든 이유, 그리고 그 Reader가 답하지 않는 두 가지
- 컬리 「컬리의 입고 시스템이 외부 인입 데이터를 안전하게 동기화하는 방법」 리뷰 — 145회 재시도가 맞는 도메인과 재시도를 금지한 도메인, 그리고 발행부와 수신부가 각자 책임지는 구조
- 카카오 「잃어버린 리포트를 찾아서: 카카오 메시징 시스템의 경쟁 조건 문제와 안티 패턴 제거 과정」 리뷰 — 벤더가 8ms 만에 리포트를 보냈고, 우리는 101ms짜리 트랜잭션 안에 있었다
- 카카오 「메시징 서버의 스트레스 테스트 노하우와 AI가 덜어 준 부분」 리뷰 — 지표를 네 층으로 내려가 읽는 법, 그리고 LLM에게 맡긴 것과 맡기지 못한 것
- 야놀자 「RESTful API validation 자동화 하기」 리뷰 — 인터페이스 하나에서 검증·문서·타입을 뽑는 이유, 그리고 자동화가 없으면 누락이 필연이라는 문장
- 네이버 D2 「스마트스토어센터 Oracle에서 MySQL로의 무중단 전환기」 리뷰 — 두 DB에 동시에 쓰되 한쪽 실패는 무시하고, 읽기 트래픽을 복제해 성능을 재고, 6개월간 불일치를 0으로 만든 과정
- 네이버 D2 「CDC 복제 이후 오라클이 느려졌다? child cursor 폭증이 만든 예상치 못한 문제」 리뷰 — 같은 SQL인데 바인딩 타입이 다르면 Oracle은 다른 쿼리로 본다
- 카카오 「추가배포 없이 API의 case 통일시키기」 리뷰 — 받는 쪽이 자기 케이스에 맞춰 알아서 읽게 하면 배포 순서가 사라진다
컨퍼런스 발표 리뷰
11편- SLASH 22 리뷰 - Java Native Memory Leak 원인을 찾아서: RSS와 NMT의 2GB 차이, jemalloc 프로파일, C2 컴파일러, Graal JIT
- TMC 25 리뷰 - '주식모으기' 서비스로 살펴보는 대용량 트래픽 처리 노하우: 200만 주문을 3,000건으로 접는 풀링 주문과 그 대가
- SLASH 24 리뷰 - 대규모 사용자 기반의 마이데이터 서비스 안정적으로 운영하기: 클러스터 단위 서킷 코디네이터, 웹소켓 얼리 리턴, 7일 배치 분산
- SLASH 24 리뷰 - Next 코어뱅킹, MSA와 MySQL로 여는 평생 무료 환전 시대: Oracle을 버린 이유, 30ms 환전, 자정에도 멈추지 않는 잔액 대사
- SLASH 23 리뷰 - 프로파일러로 시스템 성능 향상시키기: Pinpoint, 힙 덤프, jemalloc, async-profiler, strace, 그리고 커널 버전
- SLASH 23 리뷰 - 연결되면 비로소 보이는 것들: Pinpoint 코루틴 플러그인을 만들기 위해 코루틴 바이트코드를 읽다
- SLASH 23 리뷰 - 토스뱅크의 모던 FEP: 전문을 Kotlin 어노테이션으로, 리플렉션 코덱, Netty 논블로킹, Redis 폴링으로 액티브-액티브
- SLASH 22 리뷰 - 토스뱅크의 완전히 새로운 대출 시스템: Flyway + Hibernate validate, 대외기관 파이프라인, 연동 서킷과 대기열
- SLASH 21 리뷰 - 토스 서비스를 구성하는 서버 기술: 두 데이터센터 사이의 트래픽 이동, Istio 도입 후 남은 것, Kafka 두 클러스터
- SLASH 21 리뷰 - 테스트 커버리지 100%: 두 달의 비용, 1600개 테스트를 6초로, 그리고 100%여도 남는 버그
- SLASH 21 리뷰 - SRE 사례 소개: Redis 리밸런싱 ASK 에러, Memcached 재분배 실패, Prometheus가 바꾼 GC 패턴