이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Non-blocking Async Event Loop 기본에서 붙잡아야 할 핵심 판단 기준은 무엇인가?
  • event loop는 막히면 전체 연결 처리가 밀린다라는 기준은 어떤 JVM/OS 신호로 확인되는가?
  • Java/Spring 코드에서 Non-blocking Async Event Loop 기본 판단 기준은 어떤 장애 신호로 드러나는가?

개요

이 문서의 주제는 Non-blocking Async Event Loop 기본이다. Event loop와 async callback이 적은 thread로 많은 I/O를 다루는 원리를 정리한다.

먼저 붙잡을 기준은 다음 문장이다. event loop는 막히면 전체 연결 처리가 밀린다. 이 문서는 이 기준을 Java/Spring 실행 흐름, JVM/OS 관찰 지표, 장애 판단 순서로 연결한다.

핵심 모델

  • 판단 기준: non-blocking은 대기 방식을 바꾸지만 작업량을 없애지 않는다.
  • Event loop는 적은 thread로 많은 연결을 다루는 대신 loop 안의 blocking 작업에 매우 민감하다.
  • Async는 호출자와 실행자를 분리하지만 queue와 executor capacity 문제가 남는다.
  • CPU 작업이 길면 non-blocking I/O 구조에서도 event loop latency가 증가한다.
  • Backpressure가 없으면 빠른 생산자가 느린 소비자를 밀어붙여 memory와 지연을 키운다.

문서별 핵심 구분

  • event loop는 적은 thread로 많은 I/O 상태를 관리한다.
  • loop 안에서 blocking 호출을 하면 관련 연결 처리가 같이 밀린다.
  • async는 대기를 없애지 않고 실행 위치와 queue를 바꾼다.

원리

Non-blocking I/O는 결과가 아직 준비되지 않았을 때 thread를 붙잡지 않고 나중에 다시 처리하는 모델이다. OS의 readiness 알림, selector, event loop가 핵심 역할을 한다.

Event loop는 적은 수의 thread로 많은 연결 상태를 순회한다. 이 장점은 loop 안의 작업이 짧고 blocking을 하지 않는다는 전제에서만 유지된다.

Async는 대기를 없애지 않는다. 호출자 thread와 실행 위치를 분리하고, 완료 알림과 callback, queue 위치를 바꾼다. backpressure가 없으면 빠른 생산자가 느린 소비자를 압도한다.

Non-blocking Async Event Loop 기본 관점에서 중요한 점은 event loop를 공용 실행 경로로 보는 것이다. loop 안에서 blocking JDBC 호출, 큰 JSON 변환, 압축, 긴 CPU 계산을 하면 관련 연결 전체가 같이 밀린다.

Java/Spring 연결

  • WebFlux handler에서 blocking JDBC나 .block()을 호출하면 event loop를 막을 수 있다.
  • Reactor scheduler를 분리해도 boundedElastic queue와 timeout을 함께 봐야 한다.
  • Netty event loop thread 이름과 stack을 보면 loop가 I/O 대기인지 CPU 작업인지 구분할 수 있다.
  • Non-blocking client를 써도 downstream capacity와 retry 폭주는 사라지지 않는다.
  • MVC에서 WebFlux로 바꾸는 결정은 동시 연결 수, blocking dependency, 팀 디버깅 능력을 함께 봐야 한다.

코드와 설정 예시

@GetMapping("/orders/{id}")
public Mono<OrderDto> find(@PathVariable Long id) {
    return webClient.get()
        .uri("/orders/{id}", id)
        .retrieve()
        .bodyToMono(OrderDto.class)
        .map(this::lightTransform);
}

예시는 event loop 위에서 I/O 완료와 짧은 변환을 이어 붙이는 흐름을 보기 위한 것이다. lightTransform이 blocking 호출이나 긴 CPU 작업으로 바뀌면 non-blocking 모델의 장점이 바로 사라진다.

관찰 명령

jcmd <pid> Thread.print | grep -i event
top -H -p <pid>
ss -tan state established | wc -l

Non-blocking Async Event Loop 기본 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.

지표 해석

신호먼저 의심할 것다음 확인
Tomcat busy thread가 max 근처blocking I/O 또는 긴 요청 처리thread dump와 endpoint별 latency
executor queue가 계속 증가worker 부족 또는 downstream 지연active/queued/rejected 지표
event loop thread CPU가 높음loop 안 CPU 작업 또는 blocking 호출JFR, thread name, stack trace
timeout 후 retry 급증backpressure 실패retry 로그와 downstream error rate

Non-blocking Async Event Loop 기본에서는 핵심 신호와 보조 지표를 같은 시간축에서 맞춘다. 먼저 변한 신호와 뒤따라 포화된 신호를 분리해야 원인과 결과를 구분할 수 있다.

장애 상황에서 보는 순서

  1. event loop thread stack에 blocking call이 있는지 확인한다.
  2. Reactor scheduler queue와 pending 작업 증가를 본다.
  3. CPU 작업, JSON 변환, logging이 loop에서 오래 실행되는지 확인한다.
  4. downstream 지연과 retry가 non-blocking 요청 수를 키우는지 본다.
  5. blocking 구간은 별도 scheduler나 MVC 경계로 격리할지 판단한다.

이 순서는 non-blocking 구조가 실제로 thread 점유를 줄이고 있는지 확인하기 위한 루틴이다.

실전 팁

  • event loop thread 이름과 stack을 평소에 알아 둔다.
  • loop 안에서는 blocking JDBC, file I/O, Thread.sleep, 큰 CPU 변환을 하지 않는다.
  • 느린 consumer가 있을 때 queue가 어디에 쌓이는지 backpressure 기준을 둔다.
  • publishOn이나 별도 executor를 쓰면 병목이 이동한 위치를 metric으로 확인한다.
  • p99 latency가 튀면 event loop thread의 CPU와 stack을 먼저 맞춰 본다.

주니어 팁

  • Non-blocking Async Event Loop 기본 주제는 용어 정의보다 장애 때 어떤 증거로 확인할지까지 연결해 익힌다.
  • 정상 상태에서 이 문서의 관찰 명령을 실행해 Non-blocking Async Event Loop 기본 기준선을 남긴다.
  • 장애 시에는 Non-blocking Async Event Loop 기본 신호가 평소 기준선에서 벗어난 시각과 방향을 먼저 본다.

시니어 팁

  • Non-blocking Async Event Loop 기본 주제의 영향이 pool, queue, retry, timeout으로 번지는 경로를 설계 리뷰에 포함한다.
  • Non-blocking Async Event Loop 기본 runbook에는 실행 명령, 정상 범위, 해석 기준, 금지할 대응을 같이 둔다.
  • Non-blocking Async Event Loop 기본 판단이 container, LB, 다중 인스턴스 환경에서도 같은 의미인지 확인한다.

Guru급 팁

  • Non-blocking Async Event Loop 기본 주제는 단일 snapshot보다 변화 방향이 중요하다. 같은 명령을 간격을 두고 실행해 상태가 증가, 유지, 회복 중 어디인지 본다.
  • 고급 도구는 Non-blocking Async Event Loop 기본 가설을 좁힐 때만 사용하고 기본 지표와 모순되는지 먼저 확인한다.
  • Non-blocking Async Event Loop 기본 조치 후에는 CPU, memory, socket, disk, pool 중 다음 포화 지점이 어디로 이동했는지 확인한다.

위험 신호!

  • event loop thread stack에 JDBC, file I/O, blocking HTTP client가 보인다.
  • event loop CPU가 높고 모든 reactive endpoint의 p99가 같이 오른다.
  • block() 호출이 reactive 흐름 중간에 섞여 있다.
  • backpressure 없이 queue나 buffer가 계속 커진다.
  • non-blocking으로 바꿨다는 이유로 timeout과 bulkhead를 생략한다.

확인 질문

확인 질문

  • Non-blocking Async Event Loop 기본 주제를 장애 중 확인할 때 Application 로그만으로 부족한 이유는 무엇인가?
    • 로그는 코드 경로를 보여 주지만 Non-blocking Async Event Loop 기본의 JVM/OS 자원 상태, 대기 위치, 포화 방향은 별도 지표로 확인해야 하기 때문이다.
  • Non-blocking Async Event Loop 기본 관련 설정이나 pool 크기를 바꾸기 전에 확인할 것은 무엇인가?
    • 먼저 변한 신호, 하위 자원 capacity, 변경이 완화인지 증폭인지 판단할 기준을 Non-blocking Async Event Loop 기본 지표로 확인해야 한다.
  • Non-blocking Async Event Loop 기본 재발을 막기 위해 장애 기록에 무엇을 남겨야 하는가?
    • 발생 시간, 영향 범위, 사용한 명령, Non-blocking Async Event Loop 기본 핵심 지표, 원인 판단, 완화 조치, 근본 수정, 남은 리스크를 남긴다.

참고 문서