본문 바로 가기

전체 글28

톰캣 NIOConnector는 어떻게 수많은 요청을 처리할까? (feat. Acceptor, Poller) 들어가며많은 Java 웹 애플리케이션, 특히 스프링 부트(Spring Boot)를 사용할 때 기본적으로 내장되어 동작하는 톰캣(Tomcat)은 어떻게 수많은 동시 요청을 효율적으로 처리할 수 있을까요? 그 비밀의 핵심에는 바로 커넥터(Connector)가 있습니다. 이번 글에서는 톰캣의 여러 커넥터 중에서도, 오늘날 사실상 표준으로 사용되는 NIOConnector의 내부 동작 원리를 심층적으로 파헤쳐보겠습니다. NIOConnector는 Java NIO(New I/O) 기반의 I/O 멀티플렉싱(Multiplexing) 방식을 사용하며, Linux 환경에서는 주로 epoll을 활용합니다. 이 글을 읽기 전에 제가 이전에 작성한 epoll의 내부 동작 방식 글을 먼저 참고하시면 NIOConnector의 동작 ..
[Linux] epoll의 내부 동작 방식 들어가며전통적인 select나 poll 방식은 감시할 파일 디스크립터(FD)가 많아질수록 성능이 저하되는 O(N)의 한계를 가집니다. 하지만 epoll은 이러한 단점을 극복하고, 감시 대상의 수에 관계없이 O(1)의 시간 복잡도로 이벤트 발생을 감지할 수 있게 해줍니다. 이번 시간에는 리눅스의 대표적인 I/O 멀티플렉싱 메커니즘, epoll의 내부 동작 원리를 함께 살펴보겠습니다. 먼저 recv()는 어떻게 잠들고 깨어날까? 를 보고 오시면 비슷한 메커니즘 이기때문에, 더 잘이해가 갈 수 있습니다. 커널 코드의 모든 세부사항을 다루기보다는, epoll이 어떤 아이디어로 설계되었고, 주요 함수들이 어떻게 상호작용하는지 명확하게 이해하는 것을 목표로 합니다.😃 이론: epoll, 무엇이 다른가?epoll의..
[자바] ReentrantLock : NonFairSync의 lock() 동작 원리 들어가며최근 많은 자바 프로젝트, 특히 Spring 프레임워크 기반의 애플리케이션에서 동시성 제어를 위해 synchronized 키워드 대신 ReentrantLock을 사용하는 사례가 늘고 있습니다. ReentrantLock은 synchronized에 비해 더 유연하고 강력한 기능을 제공하며, 섬세한 락 제어가 가능하기 때문입니다. 이번 글에서는 ReentrantLock의 핵심 동작 원리, 그중에서도 특히 비공정(Nonfair) 방식의 lock() 메서드가 어떻게 내부적으로 동작하는지 상세히 살펴보고자 합니다.환경- JDK 17🐋 ReentrantLock의 전체 구조: 핵심은 AQSReentrantLock의 내부를 들여다보면, 그 핵심에는 AbstractQueuedSynchronizer(AQS)가 자리..
스프링 직접 구현하기 #4: DispatcherServlet v2, 그리고 실제 스프링과의 비교 들어가며지난 글에서 직접 DispatcherServlet을 v1, v2로 발전시켜 보면서 OCP 원칙의 중요성과 인터페이스 기반 설계의 이점을 체감했습니다. 이번에는 그 경험을 바탕으로, 실제 Spring Framework의 DispatcherServlet은 어떻게 구성되어 있고, 제가 만든 방식과 어떤 점이 다른지, 그리고 왜 그렇게 설계되었는지 심층적으로 알아보겠습니다.환경- JDK 17- Spring Framework 6.2.6🚀 핵심 차이점: 책임의 분리 수준제가 만든 v2 DispatcherServlet은 경로에 따라 적절한 Handler 객체를 찾아 실행하는 구조였습니다. PathContextInitiator가 스캔 시점에 경로와 Handler 객체(실행 방식 포함)를 미리 매핑해두었죠. 이..
[Linux] recv()는 어떻게 잠들고 깨어날까? 들어가며소켓 프로그래밍에 대해 공부를 하다 recv 함수의 동작 방식에 대해 궁금증이 생겼습니다. recv 를 하는 아래와 같은 코드를 한번 봅시다.while ((str_len = recv(client_sock, buffer, BUFFER_SIZE - 1, 0)) > 0) { buffer[str_len] = '\0'; printf("Received from client: %s\n", buffer);}이 코드를 실행하면, recv() 함수는 CPU를 전부 점유하며 무한 루프를 돌지 않습니다. 기본적으로 블로킹(blocking) 상태로 동작하며, CPU를 점유하지 않고 마치 "잠들어" 있는 것처럼 대기합니다. 그러다가 소켓에 데이터가 도착하면, recv() 함수는 "깨어나서" 데이터를 읽어 st..
[Linux] 네트워크 커널 스택: 리눅스 커널 네트워크 패킷 수신 여정 #3 들어가며이전 글에서는 NAPI(New API)를 통해 네트워크 인터페이스 카드(NIC)에서 수신한 패킷이 커널의 네트워크 스택으로 본격적으로 진입하기 직전까지의 과정을 살펴보았습니다. 이번 글에서는, 패킷이 커널 네트워크 스택의 상위 계층으로 전달되어 최종적으로 TCP 애플리케이션 레벨 소켓의 수신 버퍼(receive buffer)에 안착하기까지의 여정을 상세히 추적해 보겠습니다.리눅스 커널의 실제 소스 코드를 기반으로 설명하지만, 방대한 코드를 모두 담을 수는 없어 많은 부분을 생략하고 개념적으로 추상화했습니다. 따라서 각 함수나 로직의 더욱 깊은 내부 동작이 궁금하시다면, 본문에 링크된 소스 코드를 직접 보시는 것을 강력히 추천합니다.환경- 커널: 리눅스 5.15- 프로토콜: TCP/IPv4- 상황:..
[Linux] Ring Buffer 에서 NAPI: 리눅스 커널 네트워크 패킷 수신 여정 #2 들어가며지난 글에서는 NIC로 들어온 패킷이 CPU와 직접 통신하지 않고 Ring Buffer라는 중간 저장소로 먼저 전송되는 과정에 대해 이야기했습니다. 이번 글에서는 Ring Buffer에 도착한 패킷이 어떤 과정을 거쳐 리눅스 커널의 네트워크 스택으로 전달되는지 그 여정을 함께 따라가 보겠습니다.리눅스 커널 코드를 직접 살펴보며 그 흐름을 파악할 것이지만, 방대한 코드의 모든 세부 사항을 다루기보다는 핵심적인 흐름을 이해하는 데 초점을 맞출 예정입니다. 따라서 많은 생략과 추상화가 포함되어 있음을 미리 알려드립니다. 글을 읽으시면서 더 깊은 의문이나 궁금증이 생긴다면, 직접 커널 코드를 추적 해보시는 것을 강력히 추천합니다!환경- NIC : Intel X710 시리즈- 커널 : Linux 5.15 ..
[Linux] NIC에서 링 버퍼까지: 리눅스 커널 네트워크 패킷 수신 여정 #1 들어가며우리가 매일 사용하는 서버 애플리케이션은 수많은 네트워크 요청을 처리합니다. 그렇다면 이 요청들, 즉 네트워크 패킷은 서버의 네트워크 카드(NIC)에 도착해서부터 우리가 작성한 애플리케이션 코드까지 어떤 경로를 거쳐 전달될까요?위 그림은 패킷이 NIC에서 애플리케이션까지 도달하는 전체 여정을 추상화한 것입니다. 이번 글에서는 첫 번째 관문, NIC에서 커널 메모리의 링 버퍼(Ring Buffer)까지 데이터가 이동하는 과정에 대해 자세히 살펴보겠습니다.환경- NIC : Intel X710 시리즈- 커널 : Linux 5.15☕️ 핵심 구성 요소: NIC, DMA, 그리고 링 버퍼데이터 수신 과정을 이해하기 위해 먼저 세 가지 핵심 구성 요소를 알아야 합니다.NIC (Network Interface..