반응형

async 9

3편. 분산 환경에서 traceId는 왜 항상 중간에 사라질까

2편에서 Trace와 Span을 통해 요청 하나의 흐름을 연결해서 볼 수 있다는 이야기를 했다. 그런데 실제 환경에서는 이런 경험을 자주 하게 된다.“분명 트레이싱을 붙였는데, 서비스 A까지만 보이고 서비스 B부터는 trace가 끊긴다.”이 문제의 핵심은 Trace도 Span도 아니다. Context Propagation이다.traceId는 왜 저절로 이어지지 않을까흔히 하는 오해가 있다. “같은 요청이면 traceId는 자동으로 따라다니는 것 아닌가?”하지만 분산 시스템에서 요청은 하나의 프로세스-하나의 스레드 안에서 끝나지 않는다.HTTP 요청으로 들어왔다가다른 서비스로 HTTP 또는 gRPC 호출을 하고비동기 작업이나 메시지 큐를 거치고다시 다른 스레드에서 처리된다이 경계들을 넘는 순간, 아무 작업..

CompletableFuture - 비동기와 병렬은 다르다

Thread Pool을 사용하다 보면 자연스럽게 이런 요구가 생긴다. “이 작업이 끝난 뒤, 다음 작업을 이어서 실행하고 싶다” Java는 이를 위해 CompletableFuture를 제공한다.하지만 CompletableFuture는 종종 “비동기 마법 도구”처럼 사용되고, 그 결과는 예상과 다른 성능 저하나 복잡한 동시성 버그로 이어진다.이 글에서는 CompletableFuture가 무엇을 보장하는지, 그리고 무엇을 보장하지 않는지를 공식 문서 기준으로 정리한다.1. 비동기와 병렬은 같은 개념이 아니다CompletableFuture를 이해하기 전에 반드시 구분해야 할 개념이 있다.비동기(Asynchronous)병렬(Parallel)비동기는 “작업이 끝날 때까지 기다리지 않는다” 는 의미다.병렬은 “여러..

Thread Pool은 왜 문제를 만드는가? - ExecutorService의 책임

멀티스레드 환경에서 스레드를 직접 생성하고 관리하는 것은 거의 항상 잘못된 선택이다.그래서 Java는 Thread Pool과 ExecutorService를 제공한다.하지만 아이러니하게도, 실무에서 발생하는 많은 동시성 장애의 원인은 바로 이 Thread Pool이다.이 글에서는 Thread Pool이 왜 필요한지부터, 왜 문제가 되기 쉬운지, 그리고 ExecutorService가 무엇을 보장하고 무엇을 보장하지 않는지를 공식 문서 기준으로 정리한다.1. 왜 Thread Pool이 필요한가?Thread를 요청마다 생성하는 모델은 다음과 같은 문제를 가진다.Thread 생성 비용이 크다동시에 생성 가능한 Thread 수에는 한계가 있다OS 자원을 쉽게 고갈시킨다Thread Pool의 목적은 단순하다. 미리 ..

7편. SecurityContext - 인증 정보는 어디에 저장되는가

이 글은 Spring Security 공식 문서를 기반으로, 인증이 끝난 후 생성된 Authentication이 어디에 저장되고, 어떻게 전파되는지를 SecurityContext 중심으로 설명합니다.SecurityContext를 이해하지 못하면, 비동기 처리, 멀티스레드 환경, 배치 작업에서 보안 이슈를 피할 수 없습니다.들어가며Spring Security를 사용하다 보면 한 번쯤은 이런 코드를 보게 됩니다.Authentication authentication = SecurityContextHolder.getContext().getAuthentication();이 코드는 단순해 보이지만, 그 뒤에는 중요한 질문이 숨어 있습니다.이 Authentication은 어디에서 온 것일까?이 질문에 답하는 것..

[Spring 공식 문서 기반] Transaction 14. 트랜잭션 이벤트는 왜 AFTER_COMMIT일까

13편에서는 트랜잭션과 비동기가“같은 실행 흐름을 공유할 수 없는 이유”를 ThreadLocal 기반 구조로 설명했습니다.그 논의의 끝에는 항상 다음 질문이 남습니다.“그럼 트랜잭션이 끝난 뒤에 무언가를 안전하게 실행하려면 어떻게 해야 할까?”이 질문에 대한 Spring의 공식적인 답이 바로트랜잭션 이벤트(Transaction Event)입니다.1. 트랜잭션 이벤트는 무엇을 해결하려고 등장했을까다음과 같은 요구는 실무에서 매우 흔합니다.주문이 성공적으로 저장된 뒤 알림 발송결제가 확정된 뒤 통계 집계회원 가입이 완료된 뒤 환영 메일 발송이 작업들의 공통점은:“트랜잭션이 성공했을 때만 실행돼야 한다”는 점입니다.하지만 단순히 메서드 끝에서 실행하면,아직 커밋되지 않았거나곧 롤백될 수도 있는 상태에서 외부 ..

[Spring 공식 문서 기반] Transaction 13. 트랜잭션과 비동기는 왜 충돌할까

12편에서는 @Transactional(readOnly = true)가“쓰기 방지 규칙이 아니라 의도를 표현하는 힌트”라는 점을 살펴봤습니다.이제 트랜잭션 시리즈에서 가장 많은 실무 사고를 만드는 조합,트랜잭션 + 비동기로 넘어가겠습니다.많은 개발자가 다음과 같은 코드를 자연스럽게 작성합니다.@Transactionalpublic void process() { saveOrder(); asyncService.sendMessage(); // @Async}그리고 이렇게 기대합니다.“비동기 작업도 같은 트랜잭션 안에서 실행되겠지?”하지만 이 기대는거의 항상 틀립니다.1. 충돌의 출발점: ThreadLocal1편에서 다뤘듯이, Spring Transaction은ThreadLocal을 기반으로 동작합니다...

[Spring 공식문서 정리] 36. 비동기 처리로 Web 병목 넘기기

35편에서는 Servlet Thread-per-request 모델의 구조적 한계를 살펴봤습니다.이번 글에서는 그 한계를 넘기 위한 Spring MVC의 해법,“비동기 요청 처리(Async Request)”를 요청 흐름 기준으로 정리해보겠습니다.핵심 질문은 이것입니다.“Thread를 더 늘리지 않고 동시에 더 많은 요청을 처리할 수 있을까?”1. Spring MVC 비동기 처리의 핵심 아이디어비동기 처리의 본질은 단순합니다.오래 걸리는 작업 동안 Servlet Thread를 점유하지 않는다즉,요청을 받자마자 Thread를 반환하고작업은 다른 실행 단위에서 처리결과가 준비되면 응답을 재개하는 구조입니다.이 방식은 35편에서 봤던“Thread가 묶여 있는 문제”를 직접적으로 해결합니다.2. 동기 vs 비동기 ..

[Kotlin 공식 문서 정리] 13. 코루틴 비동기 작업 조합 패턴

[Kotlin 공식 문서 정리] 13. 코루틴 비동기 작업 조합 패턴코루틴을 어느 정도 쓰다 보면 단일 비동기 작업보다는 여러 비동기 작업을 어떻게 조합할 것인가가 더 중요한 문제가 됩니다.Kotlin 공식 문서에서는 이 주제를 Composing suspending functions라는 이름으로 다룹니다. 이 글에서는 그 내용을 바탕으로, 실무에서 가장 많이 사용하는 조합 패턴을 정리합니다.1. 순차 실행 기본 패턴가장 단순한 형태는 suspend 함수를 순서대로 호출하는 방식입니다.suspend fun loadUser(): User { delay(500) return User("John")}suspend fun loadOrders(user: User): List { delay(500) ..

Backend Core/Kotlin 2025.12.30

[Kotlin 공식 문서 정리] 09. Coroutine 기본 개념

[Kotlin 공식 문서 정리] 09. Coroutine 기본 개념Kotlin을 사용하다 보면 비동기 처리나 병렬 작업을 어떻게 표현해야 할지 한 번쯤 고민하게 됩니다.Kotlin에서는 이런 문제를 해결하기 위해 코루틴(Coroutine)이라는 개념을 제공합니다. 코루틴은 비동기 코드를 동기 코드처럼 읽히게 만드는 것을 목표로 합니다.이 글에서는 Kotlin 공식 문서를 기준으로 코루틴의 기본 개념과, 처음 접할 때 반드시 이해해야 할 핵심 요소들을 정리합니다.1. 코루틴은 무엇을 해결하려고 등장했을까?전통적인 비동기 코드는 콜백이 중첩되면서 흐름을 따라가기 어려워지는 문제가 있었습니다.// 콜백 기반 비동기 코드 (개념 예시)fetchUser { user -> fetchOrder(user) { o..

Backend Core/Kotlin 2025.12.29
반응형