<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[RSS Feed of LeeJin's Blog]]></title><description><![CDATA['How' 보다는 'Why'에 더 집중하고 있습니다.]]></description><link>https://0pyaq0.github.io</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 10 Oct 2026 23:52:57 GMT</lastBuildDate><item><title><![CDATA[GitHub 비밀값 탐지 전용 모델 도입: 형식 없는 비밀번호도 잡지만 AI Credits 과금은 따로 봐야 한다]]></title><description><![CDATA[GitHub가 10월 7일 유출된 비밀값 탐지에 전용 파인튜닝 모델을 도입했다. 기존 패턴 탐지와 무엇이 다른지, 어떤 기능이 무료이고 어떤 기능이 AI Credits를 쓰는지, 조직 관리자가 먼저 볼 설정을 changelog 기준으로 정리했다.]]></description><link>https://0pyaq0.github.io/github-ai-secret-detection-model/</link><guid isPermaLink="false">https://0pyaq0.github.io/github-ai-secret-detection-model/</guid><pubDate>Sun, 11 Oct 2026 00:05:00 GMT</pubDate><content:encoded>&lt;p&gt;GitHub가 10월 7일 secret scanning에 비밀값 탐지 전용으로 파인튜닝한 모델을 붙였다. 정해진 토큰 형식이 없는 비밀번호처럼 정규식으로는 잡기 어려운 값을, 주변 코드를 읽고 판단해서 찾아낸다. 기존 AI 탐지 비밀번호 알림을 쓰던 곳은 이미 새 모델로 자동 전환됐다. 그런데 같은 발표에 push protection과 Copilot &lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt;로 확장되는 기능이 같이 묶여 있고, 이쪽은 AI Credits를 쓴다. 무료로 계속 쓰는 부분과 돈이 나가는 부분을 나눠서 봐야 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;새 탐지 모델은 무엇을 더 잡아 주고, 조직에서 켜기 전에 비용과 정책은 어떻게 정리해야 하나?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;이 글은 GitHub Changelog의 10월 7일 발표와 10월 5일 탐지 패턴 추가 공지를 읽고 정리했다. AI push protection은 private preview 상태이고 과금 방식도 &quot;앞으로 몇 주 안에&quot; 도입된다고만 적혀 있어서 세부 내용은 바뀔 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-패턴-탐지와-AI-탐지는-잡는-대상이-다르다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-%ED%8C%A8%ED%84%B4-%ED%83%90%EC%A7%80%EC%99%80-AI-%ED%83%90%EC%A7%80%EB%8A%94-%EC%9E%A1%EB%8A%94-%EB%8C%80%EC%83%81%EC%9D%B4-%EB%8B%A4%EB%A5%B4%EB%8B%A4&quot; aria-label=&quot;1 패턴 탐지와 AI 탐지는 잡는 대상이 다르다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;1. 패턴 탐지와 AI 탐지는 잡는 대상이 다르다&lt;/h2&gt;
&lt;p&gt;secret scanning은 원래 형식이 정해진 토큰을 찾는 데 강하다. 접두사와 길이, 문자 구성이 정해져 있으면 패턴 하나로 거의 확실하게 잡는다. 10월 5일에도 이런 패턴이 다섯 개 추가됐다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;제공자&lt;/th&gt;
&lt;th&gt;토큰 타입&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lovable&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;lovable_api_key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pydantic&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;logfire_token&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pydantic&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;pydantic_ai_gateway_api_key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;supabase_oauth_access_token&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;supabase_scoped_personal_access_token&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;문제는 비밀번호다. DB 비밀번호나 내부 서비스 계정 비밀번호는 아무 문자열이나 될 수 있어서 패턴으로는 거의 못 잡는다. 이번 모델은 이 빈자리를 노린다. changelog 표현으로는 주변 코드를 읽어서 자격 증명일 가능성이 높은 값을 찾고, 인식 가능한 토큰 형식이 없는 비밀번호도 포함한다. 코드나 문장을 생성하지 않는 분류 전용 모델이라는 점도 따로 적혀 있다.&lt;/p&gt;
&lt;p&gt;백엔드 코드에서 떠올려 보면 대략 이런 값들이 대상이 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;datasource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; jdbc&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;postgresql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//db.internal&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;5432/orders
    &lt;span class=&quot;token key atrule&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; orders_app
    &lt;span class=&quot;token key atrule&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;평문 비밀번호&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 형식은 없지만 문맥상 비밀번호&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;키 이름이 &lt;code class=&quot;language-text&quot;&gt;password&lt;/code&gt;이고 DB 접속 설정 안에 있다는 문맥이 판단 근거가 되는 종류다. 위 예시는 설명용으로 값을 비워 둔 것이고, 실제로 어떤 값에서 알림이 뜨는지는 확인해 보지 않았다.&lt;/p&gt;
&lt;h2 id=&quot;2-새-모델이-들어가는-세-군데&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-%EC%83%88-%EB%AA%A8%EB%8D%B8%EC%9D%B4-%EB%93%A4%EC%96%B4%EA%B0%80%EB%8A%94-%EC%84%B8-%EA%B5%B0%EB%8D%B0&quot; aria-label=&quot;2 새 모델이 들어가는 세 군데 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;2. 새 모델이 들어가는 세 군데&lt;/h2&gt;
&lt;p&gt;발표에 나온 적용 범위는 세 곳이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;적용 위치&lt;/th&gt;
&lt;th&gt;하는 일&lt;/th&gt;
&lt;th&gt;상태&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;secret scanning 알림&lt;/td&gt;
&lt;td&gt;저장소의 비밀번호를 알림으로 표시&lt;/td&gt;
&lt;td&gt;적용됨, 자동 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;push protection&lt;/td&gt;
&lt;td&gt;push 시점에 비정형 자격 증명 검사&lt;/td&gt;
&lt;td&gt;private preview&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copilot &lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI·앱의 읽기 전용 리뷰에서 검사&lt;/td&gt;
&lt;td&gt;private preview 예정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 중 실무에서 제일 기대되는 건 push protection이다. 알림은 이미 커밋 히스토리에 들어간 뒤에 뜨니까 결국 비밀번호를 바꾸고 히스토리를 정리해야 한다. push 단계에서 걸리면 히스토리에 들어가기 전에 지울 기회가 생긴다. 다만 changelog에는 탐지됐을 때 push를 막는지, 우회가 가능한지는 나오지 않는다. 기존 push protection처럼 동작할 거라고 짐작은 되지만 문서로 확인한 내용은 아니다.&lt;/p&gt;
&lt;h2 id=&quot;3-무료로-남는-것과-과금되는-것&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-%EB%AC%B4%EB%A3%8C%EB%A1%9C-%EB%82%A8%EB%8A%94-%EA%B2%83%EA%B3%BC-%EA%B3%BC%EA%B8%88%EB%90%98%EB%8A%94-%EA%B2%83&quot; aria-label=&quot;3 무료로 남는 것과 과금되는 것 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;3. 무료로 남는 것과 과금되는 것&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI 탐지 비밀번호 알림은 GitHub Secret Protection(GHSP)과 GitHub Advanced Security(GHAS)에 계속 추가 비용 없이 포함된다.&lt;/strong&gt; 지금 쓰고 있다면 바뀌는 건 모델뿐이다.&lt;/p&gt;
&lt;p&gt;새로 생기는 두 검사는 AI Credits를 쓴다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;push protection 사용량은 저장소를 소유한 조직에 청구된다. push를 막지 않은 검사도 크레딧을 쓸 수 있다고 적혀 있다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt; 사용량은 쓰고 있는 Copilot 플랜의 결제 계정에 청구된다.&lt;/li&gt;
&lt;li&gt;청구 항목 이름은 &quot;Secret Protection AI Credits&quot;다.&lt;/li&gt;
&lt;li&gt;과금은 조직이 public preview에 옵트인하고 기능을 켠 뒤부터 시작된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;개인적으로 가장 눈에 걸린 건 push protection 쪽이다. 막지 않은 push도 비용이 될 수 있다는 건 push가 많은 저장소일수록 사용량이 커진다는 뜻이다. 모노레포나 봇이 자주 push하는 저장소가 있는 조직이라면 켜기 전에 예산부터 잡아 두는 게 맞아 보인다.&lt;/p&gt;
&lt;p&gt;플랜별 조건도 갈린다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI push protection: GitHub Enterprise Cloud 또는 GitHub Team에 유료 GHSP·GHAS가 있어야 하고, 관리자가 켜야 한다.&lt;/li&gt;
&lt;li&gt;보안 리뷰 검사: 개인 Copilot 플랜(Free, Pro, Pro+, Max, Student)은 GHSP·GHAS 라이선스 없이도 대상이다. Copilot Business·Enterprise도 대상이지만 push protection에 필요한 GHSP 라이선스를 대신하지는 않는다.&lt;/li&gt;
&lt;li&gt;GitHub Enterprise Server 3.23: AI 탐지 알림만 public preview로 들어가고, AI push protection과 &lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt;는 빠졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-켜기-전에-관리자가-할-일&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-%EC%BC%9C%EA%B8%B0-%EC%A0%84%EC%97%90-%EA%B4%80%EB%A6%AC%EC%9E%90%EA%B0%80-%ED%95%A0-%EC%9D%BC&quot; aria-label=&quot;4 켜기 전에 관리자가 할 일 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;4. 켜기 전에 관리자가 할 일&lt;/h2&gt;
&lt;p&gt;예산은 이 순서로 잡는다고 안내돼 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Billing and licensing에서 Budgets and alerts로 들어간다.&lt;/li&gt;
&lt;li&gt;SKU 단위 예산을 고르고 Advanced Security 아래 Secret Protection AI Credits를 선택한다.&lt;/li&gt;
&lt;li&gt;가능한 경우 &quot;Stop usage when budget limit is reached&quot;를 켠다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;세 번째가 중요하다. 예산 알림만 걸어 두면 사용이 멈추지 않는다. 실제로 상한을 걸려면 이 옵션을 같이 켜야 한다.&lt;/p&gt;
&lt;p&gt;보안 리뷰 검사는 기본으로 꺼져 있고, &lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt; 명령을 실행한다고 켜지지 않는다. 관리자가 정책으로 막아 두면 개인이 옵트인해도 그 정책을 넘어서지 못한다. 이미 private preview로 AI push protection을 쓰고 있다면 과금이 시작된 뒤에도 그대로 크레딧을 쓰게 되니, 원하지 않으면 그 전에 꺼 두라는 안내도 있다.&lt;/p&gt;
&lt;h2 id=&quot;5-우리-조직에서-점검할-것&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-%EC%9A%B0%EB%A6%AC-%EC%A1%B0%EC%A7%81%EC%97%90%EC%84%9C-%EC%A0%90%EA%B2%80%ED%95%A0-%EA%B2%83&quot; aria-label=&quot;5 우리 조직에서 점검할 것 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;5. 우리 조직에서 점검할 것&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;GHSP·GHAS를 쓰고 있다면 AI 탐지 비밀번호 알림이 켜져 있는지, 새 모델 전환 뒤 알림 양이 달라졌는지&lt;/li&gt;
&lt;li&gt;설정 파일에 비밀번호를 직접 넣는 저장소가 남아 있는지, 있다면 환경 변수나 시크릿 매니저로 옮길지&lt;/li&gt;
&lt;li&gt;AI push protection을 켤 조직과 저장소 범위, push가 잦은 저장소를 포함할지&lt;/li&gt;
&lt;li&gt;Secret Protection AI Credits 예산과 사용 중지 옵션&lt;/li&gt;
&lt;li&gt;Copilot &lt;code class=&quot;language-text&quot;&gt;/security-review&lt;/code&gt;의 보안 리뷰 검사를 조직 정책으로 허용할지&lt;/li&gt;
&lt;li&gt;Supabase, Pydantic Logfire 같은 새 패턴 대상 서비스를 쓰고 있다면 기존 알림이 새로 뜨지 않았는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;패턴 탐지는 정확하고 AI 탐지는 넓다. 둘이 겹치지 않는 영역을 맡는 구조라서, 비밀번호를 코드에 넣는 습관이 남아 있는 팀일수록 이번 변화의 영향이 클 것 같다.&lt;/p&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2026-10-07-purpose-built-model-for-leaked-secret-detection&quot;&gt;Purpose-built model for leaked secret detection (GitHub Changelog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2026-10-05-secret-scanning-adds-detectors-for-lovable-supabase-and-more/&quot;&gt;Secret scanning adds detectors for Lovable, Supabase, and more (GitHub Changelog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/code-security/secret-scanning/introduction/supported-secret-scanning-patterns&quot;&gt;Supported secret scanning patterns (GitHub Docs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/billing/how-tos/set-up-budgets&quot;&gt;Set up budgets (GitHub Docs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[JDK 28 Arena.ofConfined() 풀링: 작은 네이티브 할당이 최대 18배 빨라진다]]></title><description><![CDATA[JDK 28에서 Arena.ofConfined()의 작은 할당을 스레드별 메모리 풀로 처리하도록 바뀌었다. 동작 방식, 벤치마크 수치, 가상 스레드에서의 처리, 코드에서 확인할 부분을 Inside.java 글과 OpenJDK PR 기준으로 정리했다.]]></description><link>https://0pyaq0.github.io/jdk-28-pooled-confined-arena/</link><guid isPermaLink="false">https://0pyaq0.github.io/jdk-28-pooled-confined-arena/</guid><pubDate>Sat, 10 Oct 2026 00:05:00 GMT</pubDate><content:encoded>&lt;p&gt;JDK 28부터 &lt;code class=&quot;language-text&quot;&gt;Arena.ofConfined()&lt;/code&gt;에서 64바이트 이하의 작은 할당은 스레드마다 들고 있는 메모리 풀에서 잘라 쓰게 된다. 소스 코드는 하나도 바꿀 필요가 없다. FFM(Foreign Function &amp;#x26; Memory) API로 네이티브 함수를 부를 때마다 confined arena를 열고 닫는 코드라면, 그 오버헤드가 OpenJDK 개발 벤치마크 기준으로 7배에서 18배까지 줄었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;confined arena를 호출마다 새로 여는 패턴은 왜 느렸고, JDK 28에서는 무엇이 바뀌었나?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;이 글은 10월 5일 Inside.java에 올라온 Per-Ake Minborg의 글과 OpenJDK PR #31365 설명을 읽고 정리했다. JDK 28은 아직 정식 출시 전이고, PR 페이지에는 리뷰가 진행 중인 상태로 보여서 세부 동작은 바뀔 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-원래-무엇이-비쌌나&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-%EC%9B%90%EB%9E%98-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%B9%84%EC%8C%8C%EB%82%98&quot; aria-label=&quot;1 원래 무엇이 비쌌나 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;1. 원래 무엇이 비쌌나&lt;/h2&gt;
&lt;p&gt;confined arena는 보통 네이티브 호출 하나를 감싸는 임시 공간으로 쓴다. 결과를 받을 포인터나 &lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt; 하나, &lt;code class=&quot;language-text&quot;&gt;errno&lt;/code&gt; 값, 짧은 문자열 같은 것들이다. 글에 실린 대표 패턴은 이렇다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Arena&lt;/span&gt; arena &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Arena&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ofConfined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;MemorySegment&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arena&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allocate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JAVA_INT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    nativeFunction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;invokeExact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 결과를 segment에 써 준다&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ValueLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JAVA_INT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;문제는 4바이트짜리 &lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt; 하나를 받는 데도 JDK 27까지는 일반 네이티브 할당기를 거치고 정리 작업(cleanup action)까지 등록했다는 점이다. 메모리를 실제로 읽고 쓰는 시간보다 이 부가 작업이 더 오래 걸리는 경우가 생긴다.&lt;/p&gt;
&lt;p&gt;설계의 근거로 든 데이터가 흥미롭다. OpenJDK 테스트 스위트를 계측해 보니 confined arena 중 일부는 네이티브 메모리를 아예 할당하지 않았고, 할당한 arena의 99.99% 이상이 64바이트 미만이었다고 한다. 대부분이 아주 작은 값을 잠깐 쓰고 버리는 용도였던 셈이다.&lt;/p&gt;
&lt;h2 id=&quot;2-풀은-어떻게-동작하나&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-%ED%92%80%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%98%EB%82%98&quot; aria-label=&quot;2 풀은 어떻게 동작하나 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;2. 풀은 어떻게 동작하나&lt;/h2&gt;
&lt;h3 id=&quot;플랫폼-스레드&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%ED%94%8C%EB%9E%AB%ED%8F%BC-%EC%8A%A4%EB%A0%88%EB%93%9C&quot; aria-label=&quot;플랫폼 스레드 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;플랫폼 스레드&lt;/h3&gt;
&lt;p&gt;각 플랫폼 스레드가 작은 풀 캐시를 지연 생성해서 들고 있다. 기본값은 64바이트 풀 최대 4개다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;arena가 처음으로 풀에 들어갈 만한 할당을 할 때만 캐시에서 풀 하나를 가져온다. 할당을 안 하는 arena는 풀을 건드리지 않는다.&lt;/li&gt;
&lt;li&gt;그 풀은 해당 arena 전용이고, 작은 할당은 풀 앞쪽부터 순서대로 잘라 준다.&lt;/li&gt;
&lt;li&gt;풀에 안 들어가는 크기이거나 풀이 맞춰 줄 수 없는 정렬을 요구하면 예전처럼 일반 경로로 간다.&lt;/li&gt;
&lt;li&gt;arena를 닫으면 쓴 부분을 0으로 지우고 풀을 스레드 캐시에 돌려준다. 캐시가 이미 차 있으면 네이티브 할당기에 반납한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;중첩된 confined arena는 각자 자기 풀을 가져가기 때문에 서로 섞이지 않는다.&lt;/p&gt;
&lt;h3 id=&quot;가상-스레드&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B0%80%EC%83%81-%EC%8A%A4%EB%A0%88%EB%93%9C&quot; aria-label=&quot;가상 스레드 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;가상 스레드&lt;/h3&gt;
&lt;p&gt;가상 스레드마다 캐시를 두면 수백만 개 스레드에 캐시가 붙는다. 그래서 가상 스레드는 지금 올라탄 carrier 스레드의 캐시에서 풀을 빌린다. pinning은 캐시에서 풀을 넘겨받는 짧은 순간에만 걸리고, 그 뒤로는 arena가 풀을 소유하니까 arena가 열린 동안 다른 carrier로 옮겨 가도 된다. 닫을 때는 그 시점에 올라탄 carrier의 캐시로 돌아간다.&lt;/p&gt;
&lt;h2 id=&quot;3-벤치마크-수치&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-%EB%B2%A4%EC%B9%98%EB%A7%88%ED%81%AC-%EC%88%98%EC%B9%98&quot; aria-label=&quot;3 벤치마크 수치 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;3. 벤치마크 수치&lt;/h2&gt;
&lt;p&gt;글에 실린 개발 벤치마크 결과다. 기존 지연 시간을 풀링 후 지연 시간으로 나눈 값이라 클수록 좋다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;플랫폼&lt;/th&gt;
&lt;th&gt;5바이트 할당&lt;/th&gt;
&lt;th&gt;20바이트 할당&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linux AArch64&lt;/td&gt;
&lt;td&gt;12.3배&lt;/td&gt;
&lt;td&gt;8.6배&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux x64&lt;/td&gt;
&lt;td&gt;6.8배&lt;/td&gt;
&lt;td&gt;7.8배&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS AArch64&lt;/td&gt;
&lt;td&gt;18.6배&lt;/td&gt;
&lt;td&gt;16.8배&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows x64&lt;/td&gt;
&lt;td&gt;16.8배&lt;/td&gt;
&lt;td&gt;18.9배&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Apple M4에서 잰 ns/op 값을 보면 경계가 어디인지 더 잘 보인다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;할당 크기&lt;/th&gt;
&lt;th&gt;풀링 (ns/op)&lt;/th&gt;
&lt;th&gt;풀링 없음 (ns/op)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5바이트&lt;/td&gt;
&lt;td&gt;1.052&lt;/td&gt;
&lt;td&gt;15.862&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20바이트&lt;/td&gt;
&lt;td&gt;1.138&lt;/td&gt;
&lt;td&gt;18.139&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100바이트&lt;/td&gt;
&lt;td&gt;19.044&lt;/td&gt;
&lt;td&gt;18.856&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500바이트&lt;/td&gt;
&lt;td&gt;26.383&lt;/td&gt;
&lt;td&gt;26.168&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;64바이트를 넘는 100바이트부터는 사실상 차이가 없다. 풀이 64바이트라서 그 위로는 기존 경로를 타기 때문이다. 가상 스레드에서는 5바이트 기준 3.222 대 15.672, 20바이트 기준 2.737 대 18.109로 플랫폼 스레드보다 이득이 조금 작았다. carrier를 다루는 비용이 더해지는 탓이다.&lt;/p&gt;
&lt;p&gt;물론 마이크로벤치마크다. 글에서도 애플리케이션 전체가 이만큼 빨라진다는 뜻은 아니라고 선을 긋는다. 네이티브 호출 자체는 짧고 arena 생성, 할당, 정리가 시간의 대부분을 차지하는 코드에서 효과가 크다.&lt;/p&gt;
&lt;h2 id=&quot;4-바뀌지-않는-것과-조심할-것&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-%EB%B0%94%EB%80%8C%EC%A7%80-%EC%95%8A%EB%8A%94-%EA%B2%83%EA%B3%BC-%EC%A1%B0%EC%8B%AC%ED%95%A0-%EA%B2%83&quot; aria-label=&quot;4 바뀌지 않는 것과 조심할 것 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;4. 바뀌지 않는 것과 조심할 것&lt;/h2&gt;
&lt;p&gt;segment 생명주기와 접근 규칙은 그대로다. arena를 닫은 뒤 segment에 접근하면 예전처럼 예외가 난다. 재사용 전에 풀을 0으로 지우고, cleanup action도 풀을 지우기 전에 실행된다. 스레드가 끝나면 캐시에 있던 풀도 해제된다.&lt;/p&gt;
&lt;p&gt;개인적으로 더 신경 쓰인 건 진단 쪽이다. arena를 닫아도 &lt;code class=&quot;language-text&quot;&gt;free&lt;/code&gt;가 바로 불리지 않고 JDK 캐시로 돌아갈 수 있다. 그래서 &lt;strong&gt;arena 할당과 네이티브 &lt;code class=&quot;language-text&quot;&gt;malloc&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;free&lt;/code&gt; 호출이 1:1로 대응한다고 가정하면 안 된다&lt;/strong&gt;. 네이티브 메모리 추적 도구로 누수를 보거나 &lt;code class=&quot;language-text&quot;&gt;malloc&lt;/code&gt; 횟수를 세는 테스트가 있다면 JDK 28에서 숫자가 달라질 수 있다.&lt;/p&gt;
&lt;p&gt;적용 범위도 정리해 두면 이렇다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;JDK 28 풀링 적용 여부&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Arena.ofConfined()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64바이트 이하, 일반 정렬이면 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64바이트 초과 할당&lt;/td&gt;
&lt;td&gt;기존 경로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그 외 arena 종류&lt;/td&gt;
&lt;td&gt;영향 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;PR 설명에는 풀 크기를 내부용 비공식 시스템 프로퍼티로 조절할 수 있고(8바이트에서 1MiB), 음수를 주면 풀링이 꺼진다고 적혀 있다. 다만 프로퍼티 이름은 확인하지 못했고 지원되는 옵션도 아니라서 운영 설정에 넣을 만한 건 아니다.&lt;/p&gt;
&lt;h2 id=&quot;5-우리-코드에서-볼-부분&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-%EC%9A%B0%EB%A6%AC-%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C-%EB%B3%BC-%EB%B6%80%EB%B6%84&quot; aria-label=&quot;5 우리 코드에서 볼 부분 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;5. 우리 코드에서 볼 부분&lt;/h2&gt;
&lt;p&gt;혜택을 보는 쪽은 꽤 분명하다. 네이티브 호출마다 confined arena를 여는 FFM 바인딩, jextract로 생성한 래퍼, 포인터 out 파라미터나 작은 C 구조체를 주고받는 코드, 짧은 문자열을 네이티브로 넘기는 코드다. 백엔드에서는 JNI 대신 FFM으로 압축, 암호화, 시스템 콜 래퍼를 붙인 라이브러리가 여기에 해당한다.&lt;/p&gt;
&lt;p&gt;JDK 28 EA 빌드로 넘어가 볼 때 확인할 것만 추리면 이렇다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;confined arena를 하나 열어 큰 버퍼와 작은 값을 같이 할당하던 코드는 작은 값만 짧게 쓰는 arena로 나눌지&lt;/li&gt;
&lt;li&gt;호출마다 arena를 재사용하려고 직접 만든 풀이 있다면 JDK 풀과 겹치지 않는지&lt;/li&gt;
&lt;li&gt;네이티브 메모리 누수 테스트가 &lt;code class=&quot;language-text&quot;&gt;malloc&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;free&lt;/code&gt; 횟수에 기대고 있지 않은지&lt;/li&gt;
&lt;li&gt;가상 스레드에서 FFM을 부르는 경로는 플랫폼 스레드와 따로 측정할지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;오히려 arena를 오래 들고 다니며 재사용하려고 애쓰던 코드는 이제 단순하게 &lt;code class=&quot;language-text&quot;&gt;try&lt;/code&gt;로 짧게 여닫는 쪽이 나을 수도 있다. 이건 각자 벤치마크로 확인할 부분이다.&lt;/p&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://inside.java/2026/10/05/confined-pools/&quot;&gt;Making Arena.ofConfined() Even Cheaper in JDK 28 (Inside.java)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.openjdk.org/browse/JDK-8385697&quot;&gt;JDK-8385697: Add a Pooled Confined Arena&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openjdk/jdk/pull/31365&quot;&gt;openjdk/jdk PR #31365&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://download.java.net/java/early_access/jdk28/docs/api/java.base/java/lang/foreign/package-summary.html&quot;&gt;java.lang.foreign 패키지 문서 (JDK 28 EA)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Node.js 26.11 릴리스: 서버 개발자가 챙겨 볼 변경 다섯 가지]]></title><description><![CDATA[10월 7일 나온 Node.js 26.11.0에서 HTTP 헤더 검증 함수, --process-timeout, node:sqlite 클래스 이름 변경, perf_hooks 히스토그램, 권한 모델 보안 수정을 릴리스 노트와 PR 기준으로 정리했다.]]></description><link>https://0pyaq0.github.io/nodejs-26-11-release/</link><guid isPermaLink="false">https://0pyaq0.github.io/nodejs-26-11-release/</guid><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js 26.11.0이 10월 7일 나왔다. 같은 날 문서 빌드 관련 변경을 되돌린 26.11.1이 바로 뒤따라 나왔으니 실제로 올릴 버전은 26.11.1이다. 이번 릴리스는 semver-minor 변경이 많은데, 그중 서버 코드를 짜는 입장에서 실제로 손이 갈 만한 건 다섯 개 정도로 추려졌다. 특히 &lt;code class=&quot;language-text&quot;&gt;node:sqlite&lt;/code&gt;를 쓰고 있다면 클래스 이름이 바뀌었으니 먼저 확인해 두는 게 좋다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;26.11에서 백엔드 코드나 운영 방식에 영향을 주는 변경은 무엇이고, 지금 당장 해야 할 일이 있는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;이 글은 Node.js 공식 릴리스 노트와 각 변경의 GitHub PR 설명을 읽고 정리했다. 26은 Current 라인이라 API 세부 동작은 바뀔 수 있고, 운영 서버는 보통 LTS를 쓰니 이 기능들이 언제 LTS에 들어오는지는 따로 확인해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-한눈에-보는-변경&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-%ED%95%9C%EB%88%88%EC%97%90-%EB%B3%B4%EB%8A%94-%EB%B3%80%EA%B2%BD&quot; aria-label=&quot;1 한눈에 보는 변경 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;1. 한눈에 보는 변경&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;영역&lt;/th&gt;
&lt;th&gt;변경&lt;/th&gt;
&lt;th&gt;영향&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;http&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;isValidHeaderName()&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;isValidHeaderValue()&lt;/code&gt; 추가&lt;/td&gt;
&lt;td&gt;헤더 검증을 예외 없이 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;--process-timeout&lt;/code&gt; 플래그 추가&lt;/td&gt;
&lt;td&gt;멈춘 프로세스를 진단 후 종료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;node:sqlite&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;DatabaseSync&lt;/code&gt; → &lt;code class=&quot;language-text&quot;&gt;Database&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;StatementSync&lt;/code&gt; → &lt;code class=&quot;language-text&quot;&gt;Statement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;기존 코드 이름 점검 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;perf_hooks&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;histogram.snapshot()&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;histogram.diff()&lt;/code&gt; 추가&lt;/td&gt;
&lt;td&gt;구간별 지연 측정이 쉬워짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;권한 모델&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Socket(fd)&lt;/code&gt;로 &lt;code class=&quot;language-text&quot;&gt;--allow-net&lt;/code&gt;을 우회하던 문제 수정&lt;/td&gt;
&lt;td&gt;권한 모델 사용자는 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 밖에 &lt;code class=&quot;language-text&quot;&gt;Buffer.stringLength()&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;process.ref&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;unref&lt;/code&gt; 안정화, Alpine Linux tier 2 승격, OpenSSL 3.5.9 업데이트 같은 변경도 들어갔다.&lt;/p&gt;
&lt;h2 id=&quot;2-HTTP-헤더-검증이-예외-없이-된다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-HTTP-%ED%97%A4%EB%8D%94-%EA%B2%80%EC%A6%9D%EC%9D%B4-%EC%98%88%EC%99%B8-%EC%97%86%EC%9D%B4-%EB%90%9C%EB%8B%A4&quot; aria-label=&quot;2 HTTP 헤더 검증이 예외 없이 된다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;2. HTTP 헤더 검증이 예외 없이 된다&lt;/h2&gt;
&lt;p&gt;기존에도 &lt;code class=&quot;language-text&quot;&gt;http.validateHeaderName()&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;http.validateHeaderValue()&lt;/code&gt;가 있었는데, 둘 다 잘못된 값이면 예외를 던진다. 새로 들어온 &lt;code class=&quot;language-text&quot;&gt;isValidHeaderName()&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;isValidHeaderValue()&lt;/code&gt;는 같은 검사를 하고 결과를 boolean으로 돌려준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; http &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;node:http&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;http&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isValidHeaderValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x-trace-id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;별것 아닌 차이 같지만 PR에 붙은 설명을 보니 이유가 성능이었다. 잘못된 헤더를 거를 때 기존 함수는 에러 객체와 스택 트레이스를 만드느라 몇 마이크로초가 걸리고, boolean 검사는 20ns 정도라고 한다. 사용자 입력을 그대로 헤더에 넣는 프록시나 게이트웨이처럼 잘못된 값이 자주 들어오는 경로라면 차이가 난다. &lt;code class=&quot;language-text&quot;&gt;isValidHeaderValue()&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;http.createServer()&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;httpValidation&lt;/code&gt;과 같은 의미의 &lt;code class=&quot;language-text&quot;&gt;strict&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;relaxed&lt;/code&gt; 옵션도 받는다고 적혀 있다.&lt;/p&gt;
&lt;h2 id=&quot;3---process-timeout-멈춘-프로세스를-이유와-함께-종료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3---process-timeout-%EB%A9%88%EC%B6%98-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EB%A5%BC-%EC%9D%B4%EC%9C%A0%EC%99%80-%ED%95%A8%EA%BB%98-%EC%A2%85%EB%A3%8C&quot; aria-label=&quot;3   process timeout 멈춘 프로세스를 이유와 함께 종료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;3. --process-timeout: 멈춘 프로세스를 이유와 함께 종료&lt;/h2&gt;
&lt;p&gt;개인적으로 이번 릴리스에서 제일 반가웠던 건 이 플래그다. 지정한 시간이 지나면 별도 watchdog 스레드가 메인 스레드를 끊고, 그 시점의 JavaScript 스택과 이벤트 루프를 붙잡고 있는 리소스 목록을 출력한 뒤 종료 코드 124로 끝낸다. 메인 스레드가 네이티브 코드 안에서 멈춰 있어도 종료된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; --process-timeout&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;10s scripts/migrate.js
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$?&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;# 시간 초과면 124&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;CI의 job 타임아웃이나 &lt;code class=&quot;language-text&quot;&gt;timeout&lt;/code&gt; 명령은 프로세스를 죽이기만 하고 무엇에 걸려 있었는지는 알려 주지 않는다. &lt;code class=&quot;language-text&quot;&gt;setTimeout&lt;/code&gt;으로 직접 감시하는 방법도 이벤트 루프가 바쁜 루프에 묶이면 아예 실행되지 않는다. 배치 작업, 마이그레이션 스크립트, 테스트 러너처럼 가끔 영원히 안 끝나는 프로세스가 있는 팀이라면 원인 찾는 시간이 꽤 줄 것 같다. 시간 단위 표기는 PR 예시의 &lt;code class=&quot;language-text&quot;&gt;10s&lt;/code&gt; 형식을 따랐으니 정확한 문법은 CLI 문서를 한 번 더 보자.&lt;/p&gt;
&lt;h2 id=&quot;4-nodesqlite-클래스-이름-변경&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-nodesqlite-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%B4%EB%A6%84-%EB%B3%80%EA%B2%BD&quot; aria-label=&quot;4 nodesqlite 클래스 이름 변경 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;4. node:sqlite 클래스 이름 변경&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;DatabaseSync&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;Database&lt;/code&gt;로, &lt;code class=&quot;language-text&quot;&gt;StatementSync&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;Statement&lt;/code&gt;로 바뀌었다. 릴리스 노트에는 이름 변경만 적혀 있고, PR 설명에는 기존 이름을 alias로 남기고 문서상 deprecated(DEP0210) 처리한다고 돼 있다. 다만 PR 리뷰에서 런타임 경고를 띄울지를 두고 의견이 갈렸던 흔적이 있어서, 올리기 전에 직접 확인해 보는 게 안전하다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;const s = require(&apos;node:sqlite&apos;); console.log(typeof s.Database, typeof s.DatabaseSync)&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;둘 다 &lt;code class=&quot;language-text&quot;&gt;function&lt;/code&gt;이 나오면 기존 코드는 그대로 돌아간다. 새 코드는 처음부터 &lt;code class=&quot;language-text&quot;&gt;Database&lt;/code&gt;를 쓰는 편이 나중에 덜 귀찮다.&lt;/p&gt;
&lt;h2 id=&quot;5-지연-지표를-구간별로-보기&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-%EC%A7%80%EC%97%B0-%EC%A7%80%ED%91%9C%EB%A5%BC-%EA%B5%AC%EA%B0%84%EB%B3%84%EB%A1%9C-%EB%B3%B4%EA%B8%B0&quot; aria-label=&quot;5 지연 지표를 구간별로 보기 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;5. 지연 지표를 구간별로 보기&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;perf_hooks&lt;/code&gt; 히스토그램에 &lt;code class=&quot;language-text&quot;&gt;snapshot()&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;diff()&lt;/code&gt;가 생겼다. &lt;code class=&quot;language-text&quot;&gt;snapshot()&lt;/code&gt;은 지금까지 기록된 값을 복사한 독립 히스토그램을 만들고, &lt;code class=&quot;language-text&quot;&gt;diff()&lt;/code&gt;는 두 시점 사이에 바뀐 부분만 담은 히스토그램을 돌려준다. &lt;code class=&quot;language-text&quot;&gt;monitorEventLoopDelay()&lt;/code&gt;로 이벤트 루프 지연을 재고 있다면 &quot;최근 1분 동안의 p99&quot;를 리셋 없이 뽑을 수 있게 된 셈이다.&lt;/p&gt;
&lt;p&gt;예전에는 &lt;code class=&quot;language-text&quot;&gt;structuredClone()&lt;/code&gt;으로 복사하면 네이티브 히스토그램을 공유해 버려서 &lt;code class=&quot;language-text&quot;&gt;export()&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;importHistogram()&lt;/code&gt;으로 직렬화했다가 다시 읽는 수밖에 없었다. 같은 릴리스에서 &lt;code class=&quot;language-text&quot;&gt;monitorEventLoopDelay()&lt;/code&gt; 해상도가 잘리던 문제도 고쳐졌다. &lt;code class=&quot;language-text&quot;&gt;diff()&lt;/code&gt;의 정확한 인자 형태는 PR 설명에 나오지 않아서 쓰기 전에 API 문서를 확인할 생각이다.&lt;/p&gt;
&lt;h2 id=&quot;6-권한-모델-보안-수정과-올리기-전-점검&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-%EA%B6%8C%ED%95%9C-%EB%AA%A8%EB%8D%B8-%EB%B3%B4%EC%95%88-%EC%88%98%EC%A0%95%EA%B3%BC-%EC%98%AC%EB%A6%AC%EA%B8%B0-%EC%A0%84-%EC%A0%90%EA%B2%80&quot; aria-label=&quot;6 권한 모델 보안 수정과 올리기 전 점검 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;6. 권한 모델 보안 수정과 올리기 전 점검&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;--permission&lt;/code&gt;으로 권한 모델을 켠 상태에서 &lt;code class=&quot;language-text&quot;&gt;new Socket(fd)&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;--allow-net&lt;/code&gt; 검사를 거치지 않았다. 파일 디스크립터에서 소켓을 만들면 네트워크 권한 없이도 통신할 수 있었다는 얘기다. 이번에 검사가 추가됐고 stdio와 IPC는 기존처럼 동작하도록 예외 처리됐다. 권한 모델로 서드파티 스크립트를 가둬 두고 있다면 이 수정 하나만으로도 올릴 이유가 된다.&lt;/p&gt;
&lt;p&gt;올리기 전에 볼 것만 정리하면 이렇다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;설치할 버전은 26.11.0이 아니라 26.11.1&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;node:sqlite&lt;/code&gt;를 쓰면 &lt;code class=&quot;language-text&quot;&gt;DatabaseSync&lt;/code&gt; 사용처와 deprecation 경고 여부&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;--permission&lt;/code&gt;을 쓰는 서비스는 우선 업데이트&lt;/li&gt;
&lt;li&gt;오래 도는 배치나 CI 스크립트에 &lt;code class=&quot;language-text&quot;&gt;--process-timeout&lt;/code&gt;을 붙일지&lt;/li&gt;
&lt;li&gt;헤더를 직접 검증하는 코드가 try/catch로 감싸져 있다면 새 함수로 바꿀지&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v26.11.0&quot;&gt;Node.js 26.11.0 (Current) 릴리스 노트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v26.11.1&quot;&gt;Node.js 26.11.1 (Current) 릴리스 노트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/66334&quot;&gt;http: add isValidHeaderName() and isValidHeaderValue() (nodejs/node#66334)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/66138&quot;&gt;src: add --process-timeout=N (nodejs/node#66138)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/66117&quot;&gt;src: ensure Socket(fd) cannot bypass allow-net permission (nodejs/node#66117)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Aurora PostgreSQL에서 Iceberg·Parquet 직접 조회: 데이터 레이크를 위한 ETL이 하나 줄어든다]]></title><description><![CDATA[Aurora PostgreSQL 17.11, 18.6부터 aurora_analytics 확장으로 S3의 Iceberg·Parquet 데이터를 외부 테이블로 바로 조회하게 됐다. 설정 방법과 쿼리 예시, 운영할 때 볼 부분을 공식 발표 기준으로 정리했다.]]></description><link>https://0pyaq0.github.io/aurora-postgresql-iceberg-parquet/</link><guid isPermaLink="false">https://0pyaq0.github.io/aurora-postgresql-iceberg-parquet/</guid><pubDate>Wed, 07 Oct 2026 23:55:00 GMT</pubDate><content:encoded>&lt;p&gt;AWS가 9월 30일 Aurora PostgreSQL에서 S3에 있는 Apache Iceberg, Parquet 데이터를 직접 조회하는 기능을 발표했다. 운영 DB에 있는 최근 데이터와 데이터 레이크에 쌓인 과거 데이터를 SQL 한 번으로 같이 읽는다. 지금까지는 레이크 데이터를 서비스에서 보여 주려면 배치로 운영 DB에 다시 복사하는 리버스 ETL을 따로 돌리는 경우가 많았는데, 그 파이프라인 일부가 필요 없어지는 변화다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;레이크에 있는 데이터를 서비스 DB로 옮기지 않고, 애플리케이션이 쓰던 PostgreSQL 쿼리 그대로 읽을 수 있을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;이 글은 AWS News Blog 발표 글을 기준으로 정리했다. 아직 상세 문서에 나오지 않은 동작은 쓰지 않았고, 확인이 필요한 부분은 따로 적었다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-무엇이-추가됐나&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-%EB%AC%B4%EC%97%87%EC%9D%B4-%EC%B6%94%EA%B0%80%EB%90%90%EB%82%98&quot; aria-label=&quot;1 무엇이 추가됐나 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;1. 무엇이 추가됐나&lt;/h2&gt;
&lt;p&gt;새로 생긴 건 &lt;code class=&quot;language-text&quot;&gt;aurora_analytics&lt;/code&gt;라는 확장이다. 이 확장을 켜면 S3의 Parquet 파일이나 Iceberg 테이블을 PostgreSQL 외부 테이블(foreign table)로 만든다. 발표 글에 따르면 Aurora 안에 DuckDB 엔진이 내장돼 있고, 쿼리 처리는 Aurora 안에서 끝나서 별도 네트워크 홉이 생기지 않는다.&lt;/p&gt;
&lt;p&gt;지원 버전과 데이터 소스는 다음과 같다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;엔진 버전&lt;/td&gt;
&lt;td&gt;Aurora PostgreSQL 17.11 이상, 18.6 이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;카탈로그&lt;/td&gt;
&lt;td&gt;AWS Glue Data Catalog로 관리하는 Iceberg 테이블&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;저장 위치&lt;/td&gt;
&lt;td&gt;Amazon S3의 Parquet·Iceberg, S3 Tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;외부 연동&lt;/td&gt;
&lt;td&gt;Iceberg REST Catalog 호환 카탈로그 (Glue 페더레이션 경유)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비용&lt;/td&gt;
&lt;td&gt;기능 자체는 무료, Aurora 컴퓨팅과 S3 요청 비용만 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;리전&lt;/td&gt;
&lt;td&gt;모든 상용 리전과 GovCloud (US)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;버전 조건이 꽤 최신이라 17.11 아래 마이너 버전을 쓰고 있다면 업그레이드부터 해야 한다.&lt;/p&gt;
&lt;h2 id=&quot;2-설정은-세-단계&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-%EC%84%A4%EC%A0%95%EC%9D%80-%EC%84%B8-%EB%8B%A8%EA%B3%84&quot; aria-label=&quot;2 설정은 세 단계 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;2. 설정은 세 단계&lt;/h2&gt;
&lt;p&gt;발표 글에 나온 순서를 그대로 옮기면 이렇다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Aurora PostgreSQL 클러스터를 만든다(또는 지원 버전으로 올린다).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuroraAnalytics&lt;/code&gt; 기능으로 IAM 역할을 클러스터에 연결한다. 이 역할이 S3와 Glue Data Catalog 접근 권한을 준다.&lt;/li&gt;
&lt;li&gt;DB에서 확장을 켠다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; EXTENSION aurora_analytics&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그다음 외부 테이블을 만든다. Parquet 파일 하나를 붙이는 예시는 이렇다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FOREIGN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; transaction_history &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
SERVER aurora_analytics_server
OPTIONS &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    location &lt;span class=&quot;token string&quot;&gt;&apos;s3://&amp;lt;my-bucket&gt;/finance/transaction_history.parquet&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    format &lt;span class=&quot;token string&quot;&gt;&apos;parquet&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;컬럼 목록이 비어 있는 게 의도된 부분이다. Parquet 메타데이터에서 스키마를 읽어 오기 때문에 컬럼을 직접 적지 않아도 된다. 테이블이 많으면 &lt;code class=&quot;language-text&quot;&gt;IMPORT FOREIGN SCHEMA&lt;/code&gt; 한 번으로 Glue 데이터베이스에 있는 Iceberg·Parquet 테이블을 전부 외부 테이블로 만든다고 한다. 다만 발표 글에는 이 문장의 정확한 문법이 나오지 않아서, 실제로 쓸 때는 Aurora 사용자 가이드를 확인하는 게 맞겠다.&lt;/p&gt;
&lt;h2 id=&quot;3-운영-데이터와-레이크-데이터를-한-쿼리로&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-%EC%9A%B4%EC%98%81-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EB%A0%88%EC%9D%B4%ED%81%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%ED%95%9C-%EC%BF%BC%EB%A6%AC%EB%A1%9C&quot; aria-label=&quot;3 운영 데이터와 레이크 데이터를 한 쿼리로 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;3. 운영 데이터와 레이크 데이터를 한 쿼리로&lt;/h2&gt;
&lt;p&gt;발표 글의 예시가 이 기능을 왜 만들었는지 잘 보여 준다. 최근 7일 거래는 Aurora 테이블에, 5년치 이력은 S3 Parquet에 있는 상황이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; merchant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transaction_date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;recent&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; source
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; recent_transactions
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; customer_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;C-1001&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;UNION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; merchant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; category&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; amount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transaction_date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;historical&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; source
&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; transaction_history
&lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; customer_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;C-1001&apos;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; transaction_date &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CURRENT_DATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTERVAL&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;5 years&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; transaction_date &lt;span class=&quot;token keyword&quot;&gt;DESC&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;애플리케이션 입장에서는 그냥 테이블 두 개를 &lt;code class=&quot;language-text&quot;&gt;UNION ALL&lt;/code&gt; 한 쿼리다. 고객 거래 내역 화면처럼 &quot;최근 것은 빠르게, 오래된 것도 가끔은 보여 줘야 하는&quot; API에서 지금까지 따로 두던 아카이브 조회 경로를 하나로 합치게 된다. 발표 글에는 커밋되지 않은 운영 쪽 쓰기까지 같은 쿼리에서 보인다는 설명도 있다.&lt;/p&gt;
&lt;h2 id=&quot;4-자주-읽는-데이터는-Aurora로-가져온다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-%EC%9E%90%EC%A3%BC-%EC%9D%BD%EB%8A%94-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%8A%94-Aurora%EB%A1%9C-%EA%B0%80%EC%A0%B8%EC%98%A8%EB%8B%A4&quot; aria-label=&quot;4 자주 읽는 데이터는 Aurora로 가져온다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;4. 자주 읽는 데이터는 Aurora로 가져온다&lt;/h2&gt;
&lt;p&gt;외부 테이블은 매번 S3를 읽는다. 자주 조회하는 범위라면 Aurora 테이블로 옮겨 두는 편이 낫다. 문법은 평소 쓰던 PostgreSQL 그대로다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법&lt;/th&gt;
&lt;th&gt;쓰임새&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;CREATE TABLE AS SELECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;레이크 데이터로 새 테이블 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;INSERT INTO ... SELECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;기존 테이블에 범위 단위로 적재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;MERGE INTO&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경분을 기존 테이블에 반영&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;여기서 하나 걸리는 게 인스턴스 역할이다. 이런 적재 명령은 Aurora에 쓰기를 하니까 writer 인스턴스에서만 돌아간다. 반대로 외부 테이블 조회는 read replica를 포함한 아무 인스턴스에서나 된다. 분석성 스캔을 replica로 보내면 writer 부하를 건드리지 않고 레이크를 읽는다는 뜻이고, 개인적으로는 이 부분이 실무에서 제일 쓸모 있어 보였다.&lt;/p&gt;
&lt;h2 id=&quot;5-성능과-비용은-어디서-보나&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-%EC%84%B1%EB%8A%A5%EA%B3%BC-%EB%B9%84%EC%9A%A9%EC%9D%80-%EC%96%B4%EB%94%94%EC%84%9C-%EB%B3%B4%EB%82%98&quot; aria-label=&quot;5 성능과 비용은 어디서 보나 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;5. 성능과 비용은 어디서 보나&lt;/h2&gt;
&lt;p&gt;발표 글에서 언급한 최적화는 세 가지다. 필터 조건을 스캔 단계로 내려보내는 predicate pushdown, 필요한 컬럼만 읽는 column pruning, 그리고 자주 읽는 데이터를 인스턴스에 캐시하는 것이다. 그래서 &lt;code class=&quot;language-text&quot;&gt;WHERE&lt;/code&gt; 조건 없이 큰 Parquet을 통째로 읽는 쿼리는 여전히 비싸다.&lt;/p&gt;
&lt;p&gt;쿼리별로 얼마나 읽었는지는 함수로 확인한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; aurora_analytics_stat_statements&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;스캔한 행 수, S3에서 읽은 바이트, 캐시 적중 같은 지표가 나온다고 한다. 기능 자체는 추가 요금이 없지만 S3 요청 비용과 Aurora 컴퓨팅 사용량은 그대로 붙기 때문에, 도입 초기에 이 지표로 무거운 쿼리를 먼저 찾아 두는 게 좋겠다.&lt;/p&gt;
&lt;h2 id=&quot;6-도입-전에-확인할-것&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-%EB%8F%84%EC%9E%85-%EC%A0%84%EC%97%90-%ED%99%95%EC%9D%B8%ED%95%A0-%EA%B2%83&quot; aria-label=&quot;6 도입 전에 확인할 것 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;6. 도입 전에 확인할 것&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클러스터 버전이 17.11 또는 18.6 이상인지&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuroraAnalytics&lt;/code&gt; IAM 역할이 읽어야 할 버킷과 Glue 데이터베이스로만 좁혀져 있는지&lt;/li&gt;
&lt;li&gt;외부 테이블 조회가 replica로 가도록 커넥션 라우팅이 나뉘어 있는지&lt;/li&gt;
&lt;li&gt;자주 읽는 범위는 &lt;code class=&quot;language-text&quot;&gt;INSERT INTO ... SELECT&lt;/code&gt;로 옮길지, 외부 테이블로 둘지&lt;/li&gt;
&lt;li&gt;기존 리버스 ETL 배치 중 이 기능으로 없앨 수 있는 게 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;레이크와 서비스 DB 사이를 잇던 배치가 많은 팀일수록 얻는 게 크다. 반대로 레이크 데이터를 거의 안 읽는 서비스라면 굳이 버전을 올려 가며 쓸 이유는 아직 없어 보인다.&lt;/p&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/aws/amazon-aurora-postgresql-now-supports-direct-querying-of-apache-iceberg-and-parquet-data-in-your-data-lake/&quot;&gt;Amazon Aurora PostgreSQL now supports direct querying of Apache Iceberg and Parquet data in your data lake (AWS News Blog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/aws/aws-weekly-roundup-amazon-bedrock-managed-agents-powered-by-openai-q3-service-availability-updates-kiro-workflows-and-more-october-5-2026/&quot;&gt;AWS Weekly Roundup, October 5, 2026 (AWS News Blog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/&quot;&gt;Amazon Aurora PostgreSQL 사용자 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[GitHub 비동기 머지 API 정식 출시: 머지 봇이 타임아웃을 기다리지 않아도 된다]]></title><description><![CDATA[10월 1일 GA가 된 GitHub async merge API를 공식 문서 기준으로 정리했다. 기존 동기 머지 엔드포인트와 무엇이 다르고, 자동화 코드를 어떻게 바꾸면 되는지 적었다.]]></description><link>https://0pyaq0.github.io/github-async-merge-api/</link><guid isPermaLink="false">https://0pyaq0.github.io/github-async-merge-api/</guid><pubDate>Wed, 07 Oct 2026 10:45:00 GMT</pubDate><content:encoded>&lt;p&gt;GitHub가 10월 1일 PR을 비동기로 머지하는 REST API를 정식(GA)으로 열었다. 요청을 던지면 바로 UUID를 돌려받고, 실제 머지는 백그라운드에서 끝난다. 머지 봇이나 배포 파이프라인에서 &lt;code class=&quot;language-text&quot;&gt;PUT .../merge&lt;/code&gt;를 호출하고 응답을 붙잡고 있던 코드라면 한 번 볼 만하다. changelog에서는 이 API를 기존 동기 REST·GraphQL 머지 엔드포인트의 권장 대체재로 소개하고 있다.&lt;/p&gt;
&lt;h2 id=&quot;기존-방식에서-걸리던-부분&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EA%B8%B0%EC%A1%B4-%EB%B0%A9%EC%8B%9D%EC%97%90%EC%84%9C-%EA%B1%B8%EB%A6%AC%EB%8D%98-%EB%B6%80%EB%B6%84&quot; aria-label=&quot;기존 방식에서 걸리던 부분 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;기존 방식에서 걸리던 부분&lt;/h2&gt;
&lt;p&gt;지금까지 자동화에서 PR을 머지하는 방법은 보통 &lt;code class=&quot;language-text&quot;&gt;PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge&lt;/code&gt; 하나였다. 호출하면 그 자리에서 머지를 시도하고 결과를 돌려준다. 단순해서 좋지만 저장소가 바쁠수록 문제가 생긴다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;머지가 복잡하면 응답이 늦어지고 타임아웃이 난다.&lt;/li&gt;
&lt;li&gt;일시적인 실패도 그냥 실패로 떨어져서 재시도 로직을 직접 짜야 한다.&lt;/li&gt;
&lt;li&gt;머지 큐를 쓰는 저장소에서는 &quot;바로 머지&quot;와 &quot;큐에 넣기&quot;를 따로 처리해야 했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;새 API는 이 부분을 GitHub 쪽으로 넘긴다. 공식 문서 설명을 그대로 옮기면 백그라운드에서 머지하기 때문에 일부 오류는 재시도될 수 있고, 복잡한 머지에서 타임아웃 위험을 피할 수 있다고 한다.&lt;/p&gt;
&lt;h2 id=&quot;엔드포인트-두-개가-전부다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%97%94%EB%93%9C%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EB%91%90-%EA%B0%9C%EA%B0%80-%EC%A0%84%EB%B6%80%EB%8B%A4&quot; aria-label=&quot;엔드포인트 두 개가 전부다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;엔드포인트 두 개가 전부다&lt;/h2&gt;
&lt;p&gt;요청과 조회, 이렇게 두 개다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge-async
GET /repos/{owner}/{repo}/pulls/{pull_number}/merge-async/{uuid}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;PUT 바디에 넣을 수 있는 값은 다음과 같다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;파라미터&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;commit_title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;자동 생성되는 머지 커밋 제목&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;commit_message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;커밋 메시지 뒤에 붙일 내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;sha&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PR head가 이 SHA와 같을 때만 머지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;merge_method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;merge&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;squash&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;rebase&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;merge_action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;default&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;direct_merge&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;merge_queue&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;눈여겨본 건 &lt;code class=&quot;language-text&quot;&gt;merge_action&lt;/code&gt;이다. &lt;code class=&quot;language-text&quot;&gt;direct_merge&lt;/code&gt;는 머지 큐를 거치지 않고 바로 머지하고, &lt;code class=&quot;language-text&quot;&gt;merge_queue&lt;/code&gt;는 큐에 넣는다. &lt;code class=&quot;language-text&quot;&gt;default&lt;/code&gt;는 GitHub가 상황에 맞는 쪽을 고른다. 머지 큐 도입 여부에 따라 봇 코드를 둘로 나눌 필요가 없어진 셈이다.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;sha&lt;/code&gt;도 동작이 조금 다르다. 값을 안 넣으면 요청 시점의 PR head를 기준으로 잡는데, 요청과 실제 실행 사이에 누가 push를 하면 머지가 취소된다. 리뷰가 끝난 커밋만 머지되도록 하는 장치로 쓸 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;응답과-상태-코드&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9D%91%EB%8B%B5%EA%B3%BC-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C&quot; aria-label=&quot;응답과 상태 코드 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;응답과 상태 코드&lt;/h2&gt;
&lt;p&gt;PUT이 새 요청을 받아들이면 202와 함께 이런 응답이 온다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pending&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;details&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;merge_method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;squash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;merge_action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;expected_head_sha&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;status&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;pending&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;merged&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;enqueued&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;failed&lt;/code&gt; 넷 중 하나다. GET으로 조회해도 같은 모양이 온다. 상태 코드는 동기 API보다 경우가 많다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;코드&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;이미 머지됐거나 큐에 들어가 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;202&lt;/td&gt;
&lt;td&gt;새 요청 접수, 백그라운드 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;닫혔거나 draft라서 머지 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;409&lt;/td&gt;
&lt;td&gt;이미 진행 중인 비동기 머지 요청이 있음 (기존 UUID 반환)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;422&lt;/td&gt;
&lt;td&gt;검증 실패&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;409가 오류가 아니라 &quot;이미 있다&quot;는 뜻이라는 점이 재미있다. 같은 PR에 머지 요청을 두 번 보내도 기존 UUID를 돌려받으니, 봇이 재시작되면서 요청을 중복으로 보내도 크게 문제 될 게 없다. 그리고 결과는 마지막 업데이트 후 24시간만 보관된다. 하루 넘게 지난 UUID로 조회하면 404가 온다.&lt;/p&gt;
&lt;h2 id=&quot;스택-PR은-이-API로만-머지된다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%8A%A4%ED%83%9D-PR%EC%9D%80-%EC%9D%B4-API%EB%A1%9C%EB%A7%8C-%EB%A8%B8%EC%A7%80%EB%90%9C%EB%8B%A4&quot; aria-label=&quot;스택 PR은 이 API로만 머지된다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;스택 PR은 이 API로만 머지된다&lt;/h2&gt;
&lt;p&gt;이번 발표에서 가장 큰 변화는 사실 여기다. 문서에는 스택으로 쌓인 PR을 머지할 때는 이 엔드포인트가 필수라고 적혀 있다. 스택의 중간 PR을 지정하면 그 아래 PR부터 지정한 PR까지 전부 base 브랜치로 머지된다. 기존 &lt;code class=&quot;language-text&quot;&gt;/merge&lt;/code&gt;로는 이걸 못 한다.&lt;/p&gt;
&lt;p&gt;스택 PR을 쓰는 팀이라면 머지 자동화를 이쪽으로 옮겨야 한다는 뜻이고, 아직 안 쓰는 팀이라도 나중에 스택 PR을 도입할 때 봇을 다시 고칠 필요가 없도록 지금 넘어가 두는 게 편해 보인다.&lt;/p&gt;
&lt;h2 id=&quot;자동화-코드는-이렇게-바뀐다&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%9E%90%EB%8F%99%ED%99%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%9D%B4%EB%A0%87%EA%B2%8C-%EB%B0%94%EB%80%90%EB%8B%A4&quot; aria-label=&quot;자동화 코드는 이렇게 바뀐다 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;자동화 코드는 이렇게 바뀐다&lt;/h2&gt;
&lt;p&gt;curl로 흐름만 보면 이렇다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 1. 머지 요청&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; PUT &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Authorization: Bearer &lt;span class=&quot;token variable&quot;&gt;$GITHUB_TOKEN&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Accept: application/vnd.github+json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;X-GitHub-Api-Version: 2026-03-10&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  https://api.github.com/repos/OWNER/REPO/pulls/123/merge-async &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;merge_method&quot;:&quot;squash&quot;,&quot;sha&quot;:&quot;&amp;lt;리뷰한 head SHA&gt;&quot;}&apos;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 2. 응답의 details.uuid로 상태 조회&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Authorization: Bearer &lt;span class=&quot;token variable&quot;&gt;$GITHUB_TOKEN&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Accept: application/vnd.github+json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;X-GitHub-Api-Version: 2026-03-10&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  https://api.github.com/repos/OWNER/REPO/pulls/123/merge-async/&lt;span class=&quot;token variable&quot;&gt;$UUID&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;옮길 때 신경 쓸 부분은 몇 가지다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;응답을 받았다고 머지가 끝난 게 아니다. &lt;code class=&quot;language-text&quot;&gt;status&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;merged&lt;/code&gt;나 &lt;code class=&quot;language-text&quot;&gt;enqueued&lt;/code&gt;가 될 때까지 조회하고, &lt;code class=&quot;language-text&quot;&gt;failed&lt;/code&gt;면 &lt;code class=&quot;language-text&quot;&gt;details.message&lt;/code&gt;를 로그에 남긴다.&lt;/li&gt;
&lt;li&gt;폴링 간격은 넉넉하게 잡는다. 동기 API 문서에도 너무 빠르게 호출하면 secondary rate limit에 걸릴 수 있다고 적혀 있다.&lt;/li&gt;
&lt;li&gt;409를 실패로 처리하던 기존 에러 핸들링이 있다면 고친다. 비동기 API에서는 진행 중인 요청의 UUID를 받는 정상 경로다.&lt;/li&gt;
&lt;li&gt;리뷰한 커밋만 머지하고 싶다면 &lt;code class=&quot;language-text&quot;&gt;sha&lt;/code&gt;를 꼭 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;changelog에는 적절한 권한이 있으면 머지 규칙을 우회하는 옵션도 있다고 나오는데, 이건 자동화에 기본으로 켜 둘 기능은 아니라고 본다. 우회가 필요한 봇이라면 토큰 권한부터 따로 관리하는 게 맞다.&lt;/p&gt;
&lt;h2 id=&quot;참고-자료&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot; aria-label=&quot;참고 자료 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;15&quot; height=&quot;15&quot; viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M6.188 8.719c.439-.439.926-.801 1.444-1.087 2.887-1.591 6.589-.745 8.445 2.069l-2.246 2.245c-.644-1.469-2.243-2.305-3.834-1.949-.599.134-1.168.433-1.633.898l-4.304 4.306c-1.307 1.307-1.307 3.433 0 4.74 1.307 1.307 3.433 1.307 4.74 0l1.327-1.327c1.207.479 2.501.67 3.779.575l-2.929 2.929c-2.511 2.511-6.582 2.511-9.093 0s-2.511-6.582 0-9.093l4.304-4.306zm6.836-6.836l-2.929 2.929c1.277-.096 2.572.096 3.779.574l1.326-1.326c1.307-1.307 3.433-1.307 4.74 0 1.307 1.307 1.307 3.433 0 4.74l-4.305 4.305c-1.311 1.311-3.44 1.3-4.74 0-.303-.303-.564-.68-.727-1.051l-2.246 2.245c.236.358.481.667.796.982.812.812 1.846 1.417 3.036 1.704 1.542.371 3.194.166 4.613-.617.518-.286 1.005-.648 1.444-1.087l4.304-4.305c2.512-2.511 2.512-6.582.001-9.093-2.511-2.51-6.581-2.51-9.092 0z&quot;/&gt;&lt;/svg&gt;&lt;/a&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/changelog/2026-10-01-github-async-merge-api-generally-available/&quot;&gt;GitHub async merge API generally available (GitHub Changelog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/rest/pulls/pulls?apiVersion=2026-03-10#merge-a-pull-request-asynchronously&quot;&gt;REST API endpoints for pull requests: Merge a pull request asynchronously (GitHub Docs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[블로그를 다시 시작합니다]]></title><description><![CDATA[dlog 재오픈 안내]]></description><link>https://0pyaq0.github.io/hello-dlog/</link><guid isPermaLink="false">https://0pyaq0.github.io/hello-dlog/</guid><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;블로그를 새로 정비했습니다. 앞으로 백엔드 개발과 기술 이야기를 이곳에 꾸준히 기록하려고 합니다.&lt;/p&gt;</content:encoded></item></channel></rss>