이번 주는 클라우드 네이티브 개념으로 출발했다. 클라우드 네이티브는 단순히 클라우드 환경에서 돌아가는 애플리케이션이 아니라, 확장성(Scalability), 회복성(Resilience), 느슨한 결합(Loose Coupling), 관측 가능성(Observability) 등을 전제로 한 설계 철학이다. 이 철학은 시스템이 장애에 강하고, 확장 가능하며, 유연하게 설계될 수 있도록 돕는다.
이 개념을 이해한 뒤, 자바의 동기 I/O 구조를 직접 실습해보았다. 전통적인 Java I/O는 요청마다 새로운 스레드를 생성하거나, accept() 단계에서 서버가 블로킹되는 구조다. 이 방식은 요청당 스레드 모델로서 간단하지만, 클라이언트 수가 많아지면 다음과 같은 문제를 일으킨다.
이를 개선하기 위해 Thread Pool 모델이 도입되었지만, 이 또한 동시 접속 수가 제한되며 완전한 해결책은 아니다.
이러한 문제를 해결하기 위해 등장한 것이 Java NIO (New I/O). 핵심 아이디어는 "하나의 스레드가 여러 클라이언트를 처리하는 입출력 다중화"이며, 그 구조는 다음과 같다:
이 구조를 통해 I/O 바운드는 줄일 수 있지만, 내부적으로는 여전히 동기적 로직과 폴링 기반 구조를 갖고 있으며, CPU 바운드를 줄이지 못한다는 단점도 있다. 결국 실무에선 코드 작성이 복잡하고, 유지보수가 어렵다는 점에서 한계를 가진다.
Netty는 Java NIO의 복잡한 저수준 처리를 추상화해주는 이벤트 기반 고성능 네트워크 프레임워크다. 내부적으로는 Reactor 패턴을 사용하며, 다음과 같은 구성 요소를 중심으로 동작한다:
public class MyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 수신 처리
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 예외 처리
}
}
Netty는 포트 바인딩, 예외 처리, 데이터 디코딩 등 복잡한 작업들을 추상화된 API로 제공하며, 소켓 통신을 이벤트 흐름으로 표현할 수 있어 코드량이 줄고 유지보수도 쉬워진다. 실습에서는 Netty 기반 서버를 구성해보고, 클라이언트 요청을 비동기적으로 받아 처리하는 과정을 체험했다.
메시지 큐(MQ)는 서비스 간 비동기 통신과 느슨한 결합을 가능하게 하는 구조다. 이번 실습에서는 RabbitMQ를 활용해 Producer → Exchange → Queue → Consumer 구조를 직접 구현해보았다.
*.confirmed, reservation.* 등 패턴 기반 전달실습에서는 reservation.confirmed 같은 키로 메시지를 발행하고, 바인딩 키가 reservation.*인 큐에서 이를 받아 처리했다. 메시지 흐름은 명확히 분리되며, ACK 설정, Durable 설정 등을 통해 신뢰성 있는 통신을 실현할 수 있었다.
리액티브 프로그래밍은 데이터 흐름을 비동기 스트림으로 처리하는 방식이다. Publisher → Subscriber 구조로 동작하며, Spring에서는 WebFlux 프레임워크로 이를 구현한다.
리액티브 스트림은 단순히 데이터를 감싸는 것이 아니라, 시간을 기준으로 순차적으로 흘러가는 데이터를 선언적으로 조작할 수 있도록 한다. 또한 .map(), .flatMap(), .filter() 등을 통해 데이터 흐름을 체이닝하며, .subscribe()가 호출되어야 흐름이 실제로 시작된다.
실습에서는 예약 기능을 WebFlux로 구현하며, Mono/Flux를 이용한 요청 수신과 응답 흐름을 체험했다. 비동기 스트림이 어떻게 연결되고, subscribe가 어떻게 흐름을 트리거하는지를 직접 확인할 수 있었다.
금요일에는 실제 마이크로서비스 아키텍처 구성 실습을 진행했다. 각 서비스는 독립적으로 동작하고, 설정은 중앙에서 관리하며, 메시지는 RabbitMQ를 통해 비동기로 전달된다.
Config Server로부터 주입받음spring:
cloud:
function:
definition: dispatchReservation
stream:
bindings:
dispatchReservation-in-0:
destination: reservation-dispatched
dispatchReservation은 Consumer 함수로 정의되며, Flux를 입력받아 WebFlux 방식으로 메시지를 처리reservation-dispatched 큐에 들어오고, 함수가 이를 소비.subscribe()를 호출해 비동기 흐름을 실행이 구조를 통해, 예약이 확정되면 자동으로 스케줄링 서비스에 이벤트가 전송되고, 그에 따라 일정이 생성되는 전체 흐름을 구현할 수 있었다. 실습을 통해 MSA에서의 서비스 간 연동과 메시지 기반 이벤트 흐름을 구체적으로 익혔다.
이번 주는 새롭고 어려운 개념들이 대거 등장한 한 주였다. 실습 중간중간 잠깐이라도 놓치면 따라가기 어려운 순간들이 있었지만, 회고 겸 복습하면서 다시 곱씹어보니 이해가 두 배, 세 배로 깊어졌다. 어렵게만 느껴졌던 WebFlux, MSA, Spring Cloud, Netty 같은 기술들을 짧은 시간 안에 실습을 통해 여기까지 끌어올려주신 강사님의 설명이 정말 인상 깊었다.
기술을 단순히 배우는 걸 넘어서, 이제는 "이걸 어떻게 프로젝트에 적용할 수 있을까"를 고민하게 되는 수준까지 왔다. 다양한 기술을 조합해볼 수 있다는 게 기쁘고, 다음 프로젝트 설계 시 어떤 선택을 할지 생각해보는 좋은 계기가 된 한 주였다.