<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ops Insights – 런타임</title><link>https://docs.makgol.com/runtime/</link><description>Recent content in 런타임 on Ops Insights</description><generator>Hugo -- gohugo.io</generator><language>ko-KR</language><copyright>© 2026 Mont</copyright><lastBuildDate>Sat, 29 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://docs.makgol.com/runtime/index.xml" rel="self" type="application/rss+xml"/><item><title>JVM vs GraalVM</title><link>https://docs.makgol.com/runtime/01-jvm-graalvm/</link><pubDate>Sat, 29 Aug 2026 00:00:00 +0000</pubDate><guid>https://docs.makgol.com/runtime/01-jvm-graalvm/</guid><description>
&lt;h1&gt;01 · JVM vs GraalVM — 시동을 사면 무엇으로 값을 치르나&lt;/h1&gt;&lt;div class="hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-blue-200 hx:bg-blue-100 hx:text-blue-900 hx:dark:border-blue-200/30 hx:dark:bg-blue-900/30 hx:dark:text-blue-200"&gt;
&lt;div class="hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2"&gt;&lt;svg height=1.2em class="hx:inline-block hx:align-middle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"&gt;&lt;path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/&gt;&lt;/svg&gt;&lt;/div&gt;
&lt;div class="hx:w-full hx:min-w-0 hx:leading-7"&gt;
&lt;div class="hx:mt-6 hx:leading-7 hx:first:mt-0"&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;지도가 2025년 9월에 바뀌었습니다.&lt;/strong&gt; Graal JIT은 Oracle JDK 24가 마지막이고 JDK 25에서 빠졌습니다. Native Image도 Java SE 구독의 지원 범위에서 제외됐고 Oracle은 같은 목표를 &lt;strong&gt;Project Leyden&lt;/strong&gt;으로 가져갔습니다. 기술이 죽은 건 아니지만 &amp;ldquo;중간 지대&amp;quot;였던 Graal JIT은 실제로 사라졌습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;Native Image가 C2보다 빠르다&amp;quot;는 유료 전제 위에 서 있습니다.&lt;/strong&gt; Oracle의 Petclinic 수치(13,075 vs 12,488 req/s)는 PGO와 G1을 켠 조합인데 &lt;strong&gt;둘 다 Community Edition에는 빠져 있습니다.&lt;/strong&gt; CE + Serial GC + PGO 없음이라는 실제 오픈소스 조합의 공개 수치는 어느 벤더 자료에도 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CE Native Image는 Serial GC 고정입니다.&lt;/strong&gt; 기본 최대 힙이 물리 메모리의 &lt;strong&gt;80%&lt;/strong&gt;(G1은 25%)이고 문서가 &amp;ldquo;GC 중 RSS가 최대 힙의 2배까지 일시 증가할 수 있어 컨테이너에서 문제가 된다&amp;quot;고 직접 경고합니다. &lt;code&gt;-Xmx&lt;/code&gt;를 지정하지 않으면 컨테이너에서 터집니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;동시성 논쟁의 실제 변수는 실행 모델이 아니라 acceptor입니다.&lt;/strong&gt; 6만 연결 실측에서 Tomcat은 CPU 20%인 채로 2만에서 99.9% 실패했습니다. TCP 연결을 받아들이는 쪽이 먼저 막혔고 처리 능력은 남아 있었습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;리액티브가 메모리에 유리하다는 통념은 조건부입니다.&lt;/strong&gt; 같은 실측에서 1.6KB 응답으로 바꾸자 WebFlux는 GC에 108초를 쓰며 P50이 1.17초로 무너졌고 가상 스레드가 31% 더 처리했습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;시동만 문제라면 런타임을 안 바꾸는 답이 생겼습니다.&lt;/strong&gt; JDK 24/25의 AOT 캐시는 Spring PetClinic 시동을 4.486초에서 2.604초로 줄이면서(&lt;strong&gt;42%&lt;/strong&gt;) JIT을 그대로 둡니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;회사에서 런타임을 바꿔보자는 말이 나오는 이유는 대개 비슷합니다. 시동이 느리다, 메모리를 많이 먹는다, 오토스케일이 붙을 때마다 처음 몇 초가 아프다. 그래서 GraalVM을 꺼내 봅니다.&lt;/p&gt;</description></item><item><title>Python 워커 16개 vs 워커 2 + 스레드 32</title><link>https://docs.makgol.com/runtime/02-python-worker-thread/</link><pubDate>Sat, 29 Aug 2026 00:00:00 +0000</pubDate><guid>https://docs.makgol.com/runtime/02-python-worker-thread/</guid><description>
&lt;h1&gt;02 · 워커 16개 vs 워커 2개 + 스레드 32개 — 무엇이 정말 달라지나&lt;/h1&gt;&lt;div class="hx:overflow-x-auto hx:mt-6 hx:flex hx:rounded-lg hx:border hx:py-2 hx:ltr:pr-4 hx:rtl:pl-4 hx:contrast-more:border-current hx:contrast-more:dark:border-current hx:border-blue-200 hx:bg-blue-100 hx:text-blue-900 hx:dark:border-blue-200/30 hx:dark:bg-blue-900/30 hx:dark:text-blue-200"&gt;
&lt;div class="hx:ltr:pl-3 hx:ltr:pr-2 hx:rtl:pr-3 hx:rtl:pl-2"&gt;&lt;svg height=1.2em class="hx:inline-block hx:align-middle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"&gt;&lt;path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/&gt;&lt;/svg&gt;&lt;/div&gt;
&lt;div class="hx:w-full hx:min-w-0 hx:leading-7"&gt;
&lt;div class="hx:mt-6 hx:leading-7 hx:first:mt-0"&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--threads 32&lt;/code&gt;를 주는 순간 워커 클래스가 통째로 바뀝니다.&lt;/strong&gt; gunicorn 문서가 명시합니다 — &amp;ldquo;If you try to use the &lt;code&gt;sync&lt;/code&gt; worker type and set the &lt;code&gt;threads&lt;/code&gt; setting to more than 1, the &lt;code&gt;gthread&lt;/code&gt; worker type will be used instead.&amp;rdquo; &amp;ldquo;동기 워커에 스레드를 붙였다&amp;quot;는 표현부터 성립하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;최대 처리량은 거의 같습니다.&lt;/strong&gt; 같은 CPU limit 아래에서 두 배치의 상한은 둘 다 &lt;code&gt;limit ÷ 요청당 CPU 시간&lt;/code&gt;입니다. 달라지는 건 그 상한에 &lt;strong&gt;어떻게&lt;/strong&gt; 도달하는지, 상한을 넘긴 부하가 &lt;strong&gt;어디에 쌓이는지&lt;/strong&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;스레드 32개가 실제로 겹치는 건 GIL을 놓는 구간뿐입니다.&lt;/strong&gt; DB 대기와 외부 HTTP는 GIL 밖이고 ORM이 행을 객체로 바꾸는 순간부터 직렬화·템플릿까지는 전부 GIL 안입니다. 그래서 이득은 &lt;strong&gt;요청 시간에서 대기가 차지하는 비중&lt;/strong&gt;에 정비례합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--timeout&lt;/code&gt;의 의미가 달라집니다.&lt;/strong&gt; 동기 워커에서는 사실상 요청 상한이지만 gthread에서는 &amp;ldquo;프로세스가 살아 있다&amp;quot;는 신호일 뿐입니다. 옮겨 심지 않으면 요청 상한이 사라집니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;ldquo;느린 요청 하나가 그 워커의 후속을 막는다&amp;quot;는 서술은 기본 설정에서 틀렸습니다.&lt;/strong&gt; 커널 accept 큐가 하나라 워커에 미리 배정된 후속 요청이 없습니다. 오히려 gthread가 커넥션을 미리 집어가면서 그 한 줄을 워커 수만큼 쪼갭니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;장애 반경이 16배 차이 납니다.&lt;/strong&gt; 워커 하나가 죽을 때 잃는 것은 (A)에서 요청 1개, (B)에서 최대 32개 + 그 워커가 물고 있던 keep-alive 커넥션 전부입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;스레드는 동시성을 늘리지 durability를 만들지 않습니다.&lt;/strong&gt; Celery의 대체재가 아닙니다. 순서가 반대입니다 — Celery로 무거운 작업을 빼야 (B)가 유리해지는 조건이 만들어집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;같은 파드, 같은 CPU limit에서 두 배치를 놓고 고민하는 상황입니다.&lt;/p&gt;</description></item></channel></rss>