<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>My Site Blog</title>
        <link>https://docs.thunderdev.dev/blog</link>
        <description>My Site Blog</description>
        <lastBuildDate>Fri, 26 Dec 2025 09:47:11 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>ko</language>
        <item>
            <title><![CDATA[ServerSocket으로 이해하는 1요청 1스레드]]></title>
            <link>https://docs.thunderdev.dev/blog/understanding-tomcat-core</link>
            <guid>https://docs.thunderdev.dev/blog/understanding-tomcat-core</guid>
            <pubDate>Fri, 26 Dec 2025 09:47:11 GMT</pubDate>
            <description><![CDATA[톰캣은 단순한 컨테이너가 아니라, 'ServerSocket'을 멀티 스레드로 구현한 거대한 서버 시스템이다. 직접 코드로 구현하며 그 민낯을 파헤쳐보자.]]></description>
            <content:encoded><![CDATA[<p>톰캣은 단순한 컨테이너가 아니라, 'ServerSocket'을 멀티 스레드로 구현한 거대한 서버 시스템이다. 직접 코드로 구현하며 그 민낯을 파헤쳐보자.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-톰캣의-심장-serversocket">1. 톰캣의 심장: ServerSocket<a href="https://docs.thunderdev.dev/blog/understanding-tomcat-core#1-%ED%86%B0%EC%BA%A3%EC%9D%98-%EC%8B%AC%EC%9E%A5-serversocket" class="hash-link" aria-label="1. 톰캣의 심장: ServerSocket에 대한 직접 링크" title="1. 톰캣의 심장: ServerSocket에 대한 직접 링크" translate="no">​</a></h2>
<p>우리가 쓰는 모든 자바 서버의 대문은 <code>ServerSocket</code>이다. 특정 포트(8080)를 열고 손님이 올 때까지 <code>accept()</code>에서 대기(Blocking)하는 것이 시작이다.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-1요청-1스레드-thread-per-request">2. 1요청 1스레드 (Thread-per-Request)<a href="https://docs.thunderdev.dev/blog/understanding-tomcat-core#2-1%EC%9A%94%EC%B2%AD-1%EC%8A%A4%EB%A0%88%EB%93%9C-thread-per-request" class="hash-link" aria-label="2. 1요청 1스레드 (Thread-per-Request)에 대한 직접 링크" title="2. 1요청 1스레드 (Thread-per-Request)에 대한 직접 링크" translate="no">​</a></h2>
<p>톰캣은 손님이 올 때마다 새로운 '알바생(Thread)'을 고용한다. 문지기(Main 스레드)가 손님을 받으면, 실제 응답은 알바생이 처리하게 하여 동시 접속을 가능하게 한다.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">import java.io.*;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">import java.net.*;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public class Main {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    public static void main(String[] args) throws IOException {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        // 8080 포트 오픈</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ServerSocket server = new ServerSocket(8080);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        System.out.println("🚀 8080 포트에서 서버가 대기 중입니다...");</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        int cnt = 0;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        while (true) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // 유저가 들어올 때까지 대기 (Blocking)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            cnt++;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Socket socket = server.accept();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            System.out.println("새로운 연결 요청 발생!" + cnt);</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            // 톰캣 방식: 새 스레드 생성</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            new Thread(() -&gt; {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                try (OutputStream out = socket.getOutputStream()) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    String threadName = Thread.currentThread().getName();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    String msg = "Hello from " + threadName;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    // HTTP 헤더 붙이기</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    String response = "HTTP/1.1 200 OK\r\n" +</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            "Content-Type: text/plain; charset=UTF-8\r\n" +</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            "Content-Length: " + msg.getBytes().length + "\r\n\r\n" +</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                            msg;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    out.write(response.getBytes());</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                } catch (Exception e) {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    e.printStackTrace();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            }).start();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-더-효율적인-관리-스레드-풀-thread-pool">3. 더 효율적인 관리: 스레드 풀 (Thread Pool)<a href="https://docs.thunderdev.dev/blog/understanding-tomcat-core#3-%EB%8D%94-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EA%B4%80%EB%A6%AC-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80-thread-pool" class="hash-link" aria-label="3. 더 효율적인 관리: 스레드 풀 (Thread Pool)에 대한 직접 링크" title="3. 더 효율적인 관리: 스레드 풀 (Thread Pool)에 대한 직접 링크" translate="no">​</a></h2>
<p>요청마다 스레드를 새로 만드는 것은 리소스 낭비다. 그래서 실제 톰캣은 미리 일정 수의 일꾼을 뽑아 대기시키는 '스레드 풀' 기법을 사용한다.</p>
<p>생성 비용 절감: 스레드 생성/소멸은 CPU 자원을 많이 소모한다. 미리 만든 스레드를 재사용하여 응답성을 높인다.</p>
<p>서버 과부하 방지: 무한정 스레드가 늘어나는 것을 막아, 유저가 몰려도 서버가 한꺼번에 뻗는 사태를 방지한다.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-그럼에도-존재하는-blocking의-벽">4. 그럼에도 존재하는 'Blocking'의 벽<a href="https://docs.thunderdev.dev/blog/understanding-tomcat-core#4-%EA%B7%B8%EB%9F%BC%EC%97%90%EB%8F%84-%EC%A1%B4%EC%9E%AC%ED%95%98%EB%8A%94-blocking%EC%9D%98-%EB%B2%BD" class="hash-link" aria-label="4. 그럼에도 존재하는 'Blocking'의 벽에 대한 직접 링크" title="4. 그럼에도 존재하는 'Blocking'의 벽에 대한 직접 링크" translate="no">​</a></h2>
<p>스레드 풀을 써도 결국 1요청 = 1스레드 공식은 유지된다. 만약 200명의 일꾼이 모두 긴 작업(DB 조회 등)을 하느라 붙잡혀 있다면, 201번째 유저는 앞의 작업이 끝날 때까지 무한 대기에 빠진다. 이것이 톰캣 같은 블로킹 서버의 구조적 한계다.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-다음-예고-네티netty와-이벤트-기반-모델">5. 다음 예고: 네티(Netty)와 이벤트 기반 모델<a href="https://docs.thunderdev.dev/blog/understanding-tomcat-core#5-%EB%8B%A4%EC%9D%8C-%EC%98%88%EA%B3%A0-%EB%84%A4%ED%8B%B0netty%EC%99%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EB%AA%A8%EB%8D%B8" class="hash-link" aria-label="5. 다음 예고: 네티(Netty)와 이벤트 기반 모델에 대한 직접 링크" title="5. 다음 예고: 네티(Netty)와 이벤트 기반 모델에 대한 직접 링크" translate="no">​</a></h2>
<p>이러한 '대기(Blocking)' 문제를 해결하기 위해 등장한 것이 바로 이벤트 기반(Event-driven) 통신이다. 다음 글에서는 단 몇 개의 스레드만으로 수만 명의 요청을 쳐내는 **네티(Netty)**의 원리를 파헤쳐보겠다.</p>
<h2>???</h2>
<blockquote>
<p>Q. 그럼 왜 모든 곳에서 네티를 쓰지 않고 톰캣을 기본으로 사용할까?</p>
</blockquote>
<blockquote>
<p>톰캣은 자바 웹 표준(Servlet)을 완벽하게 구현한 '풀 패키지' 서버로, 개발자가 로직에만 집중할 수 있는 생산성을 제공한다. 반면 네티는 성능은 극강이지만 비동기 설계의 복잡도와 디버깅의 어려움이 커서, 초고성능이 필요한 특수 케이스가 아니라면 안정성과 생산성 측면에서 톰캣이 훨씬 유리하기 때문이다.</p>
</blockquote>]]></content:encoded>
            <category>Java</category>
            <category>Network</category>
            <category>Tomcat</category>
            <category>CS</category>
        </item>
    </channel>
</rss>