웹 개발 데일리 브리핑 — 2026-10-14
Soshy·

기준 시점: 2026-10-14 06:00 KST
조사 범위: 2026-10-13 06:00 ~ 2026-10-14 06:00 KST
추천 글 범위: 기준 시점 당시 최근 7일
1️⃣ 프론트엔드
Cloudflare Web Analytics, LCP·INP 세부 지표 지원 — 실제 사용자의 성능 저하 원인을 단계별로 분석
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: Cloudflare Web Analytics의 Real User Monitoring(RUM)
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-13-core-web-vital-subparts/
Cloudflare가 Web Analytics의 Real User Monitoring에 LCP와 INP의 세부 측정 지표를 추가했다.
기존 Core Web Vitals는 웹페이지의 로딩 속도, 시각적 안정성, 사용자 입력에 대한 반응성을 평가하는 데 사용됐다.
하지만 하나의 종합 지표만으로는 성능이 나쁜 원인을 정확하게 찾기 어렵다.
예를 들어 어떤 페이지의 LCP가 4초라고 가정해 보자.
서버에서 HTML을 늦게 반환해서 발생한 문제인지, 브라우저가 주요 이미지를 늦게 발견한 것인지, 이미지를 다운로드하는 데 시간이 오래 걸린 것인지, 다운로드 이후 렌더링이 지연된 것인지에 따라 해결 방법은 완전히 달라진다.
이번 변경은 하나의 성능 지표를 구성하는 시간을 여러 단계로 분해해 실제 사용자의 환경에서 측정할 수 있도록 한다.
LCP를 네 단계로 분리
LCP(Largest Contentful Paint)는 초기 화면에서 가장 큰 콘텐츠 요소가 렌더링되는 시점을 측정하는 Core Web Vitals 지표다.
일반적으로 주요 이미지나 큰 텍스트 블록이 측정 대상이 된다.
Cloudflare는 LCP를 다음 네 단계로 나눴다.
| 세부 지표 | GraphQL 필드 | 의미 |
|---|---|---|
| Time to First Byte | timeToFirstByte | 브라우저가 HTML 문서의 첫 번째 바이트를 받기까지 걸린 시간 |
| Resource Load Delay | lcpResourceLoadDelay | 문서 수신 이후 LCP 리소스를 발견하고 로딩을 시작하기까지 걸린 시간 |
| Resource Load Duration | lcpResourceLoadTime | LCP 리소스를 다운로드하는 데 걸린 시간 |
| Element Render Delay | lcpElementRenderDelay | 리소스 다운로드 이후 실제 요소가 화면에 나타나기까지 걸린 시간 |
이 구분은 성능 문제를 분석하는 방식을 바꾼다.
예를 들어 timeToFirstByte가 크다면 서버 응답, CDN 캐시, 서버 측 데이터 조회 등이 영향을 주고 있을 수 있다.
반면 lcpResourceLoadDelay가 크다면 HTML이 도착한 이후에도 브라우저가 주요 리소스를 늦게 발견하고 있다는 뜻이다.
이 경우 중요한 이미지가 JavaScript 실행 이후에야 DOM에 추가되거나, 낮은 우선순위로 요청되거나, CSS 내부에서 뒤늦게 발견되는 구조 등을 검토할 수 있다.
lcpResourceLoadTime이 크다면 이미지 파일 크기, 네트워크 전송, 리소스 압축 및 전달 방식과 관련이 있을 수 있다.
마지막으로 lcpElementRenderDelay가 크다면 리소스는 이미 다운로드됐지만 브라우저가 해당 요소를 화면에 표시하지 못하고 있다는 의미다.
JavaScript 실행, 스타일 계산, 렌더링을 차단하는 작업 등이 원인일 수 있다.
따라서 이번 기능은 LCP 점수 자체를 개선하는 새로운 최적화 기능이 아니라 LCP가 나빠진 원인을 더 구체적으로 구분하기 위한 관측 기능이다.
INP를 세 단계로 분리
INP(Interaction to Next Paint)는 사용자가 클릭, 터치, 키보드 입력 등을 수행했을 때 화면이 실제로 반응하기까지의 시간을 측정한다.
이번 업데이트에서는 INP를 다음 세 단계로 나눴다.
| 세부 지표 | GraphQL 필드 | 의미 |
|---|---|---|
| Input Delay | inpInputDelay | 사용자 입력이 발생한 뒤 이벤트 처리를 시작하기까지의 대기 시간 |
| Processing Duration | inpProcessingDuration | 이벤트 핸들러를 실행하는 데 걸린 시간 |
| Presentation Delay | inpPresentationDelay | 이벤트 핸들러가 종료된 뒤 다음 화면을 표시하기까지 걸린 시간 |
예를 들어 버튼을 클릭했을 때 화면이 늦게 반응한다고 가정해 보자.
이벤트 핸들러 내부의 작업이 매우 짧더라도, 브라우저가 다른 JavaScript 작업을 처리하고 있다면 클릭 이벤트를 처리하기까지 대기 시간이 발생할 수 있다.
이 경우 문제가 되는 것은 inpProcessingDuration보다 inpInputDelay일 가능성이 크다.
반대로 클릭 이벤트가 즉시 실행되지만 이벤트 핸들러에서 복잡한 데이터 변환을 수행한다면 inpProcessingDuration이 증가한다.
이벤트 핸들러가 빠르게 종료됐는데 화면 업데이트가 오래 걸리는 경우에는 inpPresentationDelay가 커질 수 있다.
React 애플리케이션을 예로 들면, 이벤트 핸들러 이후 많은 컴포넌트가 업데이트되거나 복잡한 DOM 변경이 발생하는 상황을 생각할 수 있다.
하지만 Presentation Delay가 높다고 해서 원인을 곧바로 React의 리렌더링으로 단정해서는 안 된다.
브라우저의 스타일 계산, 레이아웃, 페인팅과 다른 메인 스레드 작업도 해당 지연에 영향을 줄 수 있기 때문이다.
이번 세부 지표는 사용자 입력이 느린 현상과 실제로 시간이 소비되는 실행 단계를 연결하는 데 사용할 수 있다.
TCP 연결과 TLS 핸드셰이크도 분리
Cloudflare는 페이지 로딩 과정에서 측정하는 연결 시간도 세분화했다.
기존에는 네트워크 연결과 TLS 협상에 걸린 시간이 하나의 지표로 제공됐다.
이번 변경으로 다음 두 항목을 별도로 확인할 수 있다.
connectionTimeWithoutTLS: TLS를 제외한 연결 설정 시간tlsTime: TLS 핸드셰이크에 걸린 시간
예를 들어 특정 지역의 사용자가 웹페이지에 접속할 때 연결 시간이 길어진다면 네트워크 경로 문제인지, TLS 협상 과정에 시간이 많이 소요되는지 구분할 수 있다.
기존의 connectionTime 필드는 계속 유지된다.
따라서 해당 필드를 사용하는 기존 GraphQL 분석 시스템이 반드시 새 필드로 변경해야 하는 것은 아니다.
GraphQL API와 측정 단위
새 지표는 Cloudflare Dashboard뿐 아니라 GraphQL Analytics API에서도 사용할 수 있다.
LCP와 INP의 세부 지표는 rumWebVitalsEventsAdaptiveGroups에서 조회한다.
연결 설정과 TLS 시간은 rumPerformanceEventsAdaptiveGroups에서 제공된다.
각 지표에는 다음 백분위수가 지원된다.
- P25
- P50
- P75
- P90
- P95
- P99
- P999
예를 들어 lcpResourceLoadDelayP50은 측정된 LCP 리소스 로딩 지연 시간의 중앙값을 나타낸다.
inpInputDelayP75를 이용하면 전체 측정값 가운데 75번째 백분위수의 입력 지연 시간을 확인할 수 있다.
모든 값의 단위는 마이크로초(μs)다.
또한 데이터가 없는 경우에는 음수 값이 반환된다.
따라서 GraphQL 결과를 직접 처리하는 애플리케이션에서는 음수 값을 실제 성능 측정값으로 해석하지 않도록 주의해야 한다.
이번 업데이트는 Core Web Vitals의 공식 정의나 브라우저의 성능 측정 API를 변경하지 않는다.
이미 수집 중인 실제 사용자 성능 데이터를 더욱 세밀하게 분석할 수 있도록 Cloudflare Web Analytics의 기능을 확대한 것이다.
2️⃣ 웹 플랫폼·브라우저
이번 조사 범위에서 포함할 만한 주요 신규 발표를 확인하지 못했습니다.
3️⃣ 백엔드·인프라
Cloudflare Agents SDK, 영속적인 브라우저 세션 지원 — 에이전트의 탭과 로그인 상태를 여러 대화에 걸쳐 유지
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 버전: Agents SDK 0.28.0 이상
- 적용 대상: Cloudflare Agents SDK, Browser Run
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-13-persistent-browser/
Cloudflare가 Agents SDK에 여러 대화 차례에 걸쳐 브라우저 세션을 재사용할 수 있는 browserTool을 추가했다.
기존에 AI 에이전트가 브라우저를 이용해 웹사이트를 탐색할 때는 브라우저 실행과 상태 관리가 중요한 문제였다.
예를 들어 사용자가 에이전트에게 특정 웹사이트에 로그인하도록 요청했다고 가정해 보자.
에이전트는 로그인 화면을 열고 인증 과정을 수행한 뒤 필요한 페이지로 이동한다.
이후 사용자가 추가 작업을 요청했을 때 기존 브라우저 세션이 사라졌다면 에이전트는 다시 로그인해야 한다.
또한 기존에 열어 두었던 탭이나 현재 페이지 위치를 복구해야 할 수도 있다.
이번 기능은 브라우저의 실행 상태를 에이전트가 여러 대화 차례에 걸쳐 재사용하는 구조를 제공한다.
브라우저 실행 방식
browserTool은 Cloudflare Browser Run을 이용해 실제 브라우저를 실행한다.
에이전트가 브라우저를 조작할 때는 Chrome DevTools Protocol(CDP)을 사용한다.
CDP는 Chromium 계열 브라우저의 페이지 탐색, DOM 검사, JavaScript 실행, 네트워크 분석, 스크린샷 수집 등을 제어할 수 있는 프로토콜이다.
이번 통합에서는 모델이 브라우저를 조작하기 위한 코드를 생성하고, 해당 코드가 CDP를 통해 실행된다.
스크린샷은 이미지 형태로 반환된다.
따라서 이미지를 처리할 수 있는 모델은 실제 웹페이지의 화면을 확인할 수 있고, 애플리케이션은 필요하다면 해당 이미지를 사용자 UI에도 표시할 수 있다.
이는 웹페이지의 HTML만 가져오는 문서 수집 도구와 다르다.
JavaScript 실행, 사용자 상호작용, 로그인 상태 등이 필요한 웹사이트에서도 작업할 수 있도록 실제 브라우저 실행 환경을 사용하는 방식이다.
Durable Objects와 브라우저 수명주기
Cloudflare는 이번 기능을 Durable Objects 기반 에이전트에 연결한다.
공식 예제에서는 agents/browser에서 Browser와 browserRun을 가져온다.
이후 Browser 인스턴스를 생성하고 Lifecycle에 등록한다.
Pi Durable을 사용하는 에이전트에서는 browserTool을 확장 레지스트리에 등록해 모델이 해당 도구를 호출할 수 있도록 한다.
중요한 부분은 브라우저가 에이전트의 일반적인 단일 요청 실행과 별도의 수명주기를 가질 수 있다는 것이다.
Durable Object가 Hibernation 상태에 들어가더라도 브라우저 세션은 유지될 수 있다.
따라서 사용자가 잠시 대화를 중단했다가 다시 요청하더라도 기존 세션을 재사용할 수 있다.
그러나 여기서 말하는 영속성은 브라우저가 무기한 유지된다는 의미가 아니다.
기본 유휴 타임아웃은 10분이다.
브라우저 세션이 만료되거나 실행 과정에서 충돌이 발생하면 도구는 새로운 브라우저를 생성한다.
이때 응답에는 restarted: true가 포함된다.
새로 생성된 브라우저에는 이전에 열어 두었던 탭과 로그인 정보가 남아 있지 않다.
따라서 브라우저 상태를 반드시 보존해야 하는 작업이라면 브라우저의 실행 상태만을 유일한 저장소로 사용해서는 안 된다.
진행 중인 작업 단계나 필요한 데이터를 별도의 지속 저장소에 보관하는 방식이 필요할 수 있다.
탭은 분리되지만 쿠키는 공유된다
이번 기능에서 주의해야 할 부분은 세션의 격리 범위다.
Pi Durable에서는 기본적으로 대화마다 독립적인 활성 탭을 사용한다.
하지만 쿠키와 로그인 정보는 동일한 브라우저 안에서 공유된다.
즉 대화마다 별도의 탭이 생성된다고 해서 인증 상태까지 완전히 분리되는 것은 아니다.
예를 들어 서로 다른 사용자의 작업을 하나의 브라우저 인스턴스로 처리하는 애플리케이션에서는 이러한 공유 구조가 문제가 될 수 있다.
한 사용자가 로그인한 사이트의 쿠키가 다른 사용자의 대화에서도 사용될 가능성을 고려해야 하기 때문이다.
따라서 여러 사용자의 브라우저 작업을 처리하는 서비스에서는 탭 분리만으로 충분한 격리가 이루어졌다고 가정해서는 안 된다.
브라우저 인스턴스와 인증 상태를 어떤 사용자 또는 세션에 연결할지를 애플리케이션 설계에서 별도로 결정해야 한다.
다른 AI 프레임워크와의 연결
이번 기능은 Pi Durable에서만 사용할 수 있는 것은 아니다.
Cloudflare는 AI SDK와 TanStack AI를 위한 어댑터도 제공한다.
또한 공개된 Browser API와 CDP API를 이용하면 다른 에이전트 실행 환경에서도 영속적인 브라우저를 사용할 수 있다.
이번 변경은 새로운 브라우저 엔진이나 웹 표준을 발표한 것이 아니다.
AI 에이전트가 실제 브라우저를 조작하면서 탭, 쿠키, 로그인 상태를 재사용할 수 있도록 실행 환경과 수명주기 관리를 통합한 기능이다.
Cloudflare API MCP 서버, Workers 오류를 MCP Events로 전달 — 에이전트가 장애를 자동으로 감지하는 구조 지원
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: Cloudflare API MCP Server, Workers Issues
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-13-cloudflare-mcp-events/
Cloudflare가 Workers에서 발생한 오류를 MCP Events 형식으로 외부 에이전트에 전달하는 기능을 추가했다.
기존 AI 에이전트는 외부 시스템의 상태를 확인하려면 직접 API를 호출하거나 주기적으로 정보를 조회해야 하는 경우가 많았다.
예를 들어 운영 중인 Worker에서 오류가 발생했는지 확인하려면 에이전트가 일정한 간격으로 로그나 모니터링 API를 조회해야 한다.
이러한 Polling 방식은 구현이 단순하지만 한계가 있다.
오류가 발생하지 않았더라도 계속 API를 호출해야 하며, 확인 주기가 길다면 실제 장애가 발생한 뒤 이를 발견하기까지 시간이 걸릴 수 있다.
이번 업데이트는 오류가 발생했을 때 Cloudflare가 에이전트에게 이벤트를 직접 전달하도록 한다.
Workers Issues와 MCP Events의 결합
Workers Issues는 Cloudflare Workers의 실행 오류를 수집하고 관련된 오류를 하나의 Issue로 묶는 기능이다.
애플리케이션에 별도의 오류 모니터링 SDK를 설치하거나 코드에 전용 Wrapper를 추가하지 않아도 사용할 수 있다.
Cloudflare는 이번에 Workers Issues의 이벤트를 MCP 서버를 통해 외부로 전달할 수 있도록 했다.
현재 지원하는 이벤트 이름은 다음과 같다.
cloudflare.alert.workers_observability_real_time_issue
MCP 클라이언트는 events/list를 호출해 사용 가능한 이벤트를 확인한다.
이후 events/subscribe를 통해 필요한 이벤트를 구독한다.
구독 범위는 Cloudflare 계정 전체 또는 특정 Worker 하나로 지정할 수 있다.
Workers Issues에서 새로운 문제가 발생하거나 기존 문제가 다시 발생하면 Cloudflare의 MCP 서버가 해당 이벤트를 클라이언트의 Webhook으로 전달한다.
전달되는 이벤트에는 서명이 포함돼 있다.
따라서 이벤트를 수신하는 시스템에서는 서명을 검증해 신뢰할 수 있는 발신자로부터 전달된 요청인지 확인할 수 있다.
에이전트 기반 장애 조사 흐름
이벤트를 구독한 애플리케이션에서는 오류가 발생했을 때 AI 에이전트를 자동으로 실행하는 흐름을 만들 수 있다.
예를 들어 다음과 같은 구조다.
- 운영 중인 Worker에서 오류가 발생한다.
- Workers Issues가 오류를 수집하고 관련 Issue를 생성한다.
- Cloudflare MCP 서버가 등록된 Webhook으로 이벤트를 전달한다.
- 애플리케이션이 이벤트 서명을 검증한다.
- 에이전트가 해당 Worker의 로그와 관련 정보를 조회한다.
- 에이전트가 오류의 원인과 영향을 분석한다.
이때 중요한 점은 MCP Events 자체가 장애를 자동으로 수정하는 기능은 아니라는 것이다.
이벤트는 에이전트가 조사를 시작할 수 있도록 하는 신호다.
실제 로그 조회, 코드 분석, 복구 작업은 클라이언트와 에이전트가 사용할 수 있는 도구 및 권한에 따라 달라진다.
사용 조건과 제한사항
이번 기능을 사용하려면 먼저 대상 Worker에서 Workers Issues를 활성화해야 한다.
Cloudflare API MCP 서버의 주소는 다음과 같다.
https://mcp.cloudflare.com/mcp
또한 클라이언트에는 다음 권한이 필요하다.
- Notifications Write
- Workers Observability Write
클라이언트가 MCP Events Webhook을 지원해야 한다는 조건도 있다.
MCP 프로토콜을 지원하는 모든 클라이언트에서 자동으로 이벤트를 수신할 수 있는 것은 아니다.
현재 Cloudflare가 제공하는 이벤트는 Workers Issues 관련 이벤트 하나다.
따라서 Cloudflare의 모든 모니터링 지표나 보안 이벤트가 MCP Events로 제공된다고 해석해서는 안 된다.
이번 변경은 MCP를 단순히 에이전트가 도구를 호출하는 인터페이스로 사용하는 것을 넘어 외부 시스템에서 발생한 이벤트가 에이전트의 작업을 시작하도록 하는 구조를 지원한다는 점이 특징이다.
Cloudflare Workers, BYOIP 대상 내부 요청의 원본 사용자 정보 보존 — 잘못된 WAF 차단과 봇 판정 문제 개선
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: Cloudflare Workers에서 BYOIP 기반 호스트로 전달하는 하위 요청
- 원문: https://developers.cloudflare.com/changelog/post/2026-10-13-byoip-workers-subrequest-context/
Cloudflare가 Workers에서 BYOIP(Bring Your Own IP)를 사용하는 Cloudflare 프록시 호스트로 요청을 전달할 때 원본 요청의 문맥을 유지하도록 변경했다.
BYOIP는 고객이 소유한 IP 주소를 Cloudflare 네트워크에서 사용할 수 있도록 하는 기능이다.
일반적으로 Workers는 외부 API나 다른 웹서비스에 fetch()를 이용해 요청을 보낼 수 있다.
이러한 요청을 Subrequest라고 한다.
문제는 Workers가 다시 Cloudflare를 사용하는 다른 호스트로 요청을 보낼 때 발생할 수 있다.
외부 사용자에게서 들어온 요청을 Worker가 처리한 뒤 또 다른 Cloudflare 호스트로 전달한다면, 실제 원본 사용자의 연결과 Cloudflare 내부에서 발생한 연결은 서로 다르다.
기존에는 일부 BYOIP 대상 Subrequest에서 원래 Worker의 문맥과 사용자 연결 정보가 손실되는 문제가 있었다.
이 경우 목적지의 보안 규칙이 요청을 일반적인 외부 인터넷 요청으로 판단할 수 있었다.
또한 Bot Management가 실제 사용자 대신 Cloudflare 서비스 사이의 내부 연결을 분석하는 문제가 발생할 수 있었다.
이로 인해 정상적인 요청이 잘못 차단되거나 HTTP 403 응답이 발생할 수 있었다.
Worker 실행 문맥 유지
이번 변경 이후에는 BYOIP 대상 Subrequest에서도 다음 정보가 보존된다.
CF-Worker헤더cf.worker.upstream_zone필드
이 정보는 해당 요청이 Cloudflare Worker를 거쳐 전달됐다는 사실과 상위 Worker의 Zone 정보를 표현하는 데 사용된다.
이를 통해 목적지에서도 요청이 단순한 외부 연결이 아니라 Cloudflare 내부 서비스 사이의 통신이라는 사실을 파악할 수 있다.
같은 Zone 안에서 발생한 요청과 서로 다른 Zone 사이의 요청에서 보다 일관된 보안 규칙을 적용할 수 있도록 한 것이다.
Bot Management의 판정 정보 수정
Bot Management가 사용하는 정보도 개선됐다.
영향을 받는 BYOIP Subrequest에서는 다음 항목이 원래 최종 사용자의 연결 정보를 반영하도록 변경됐다.
- Bot Score
- Verified Bot 여부
- JA3 Fingerprint
- JA4 Fingerprint
JA3와 JA4는 TLS 및 연결 특성을 이용해 클라이언트를 식별하고 분석하는 데 사용하는 Fingerprint다.
기존에는 일부 상황에서 실제 브라우저나 클라이언트가 아니라 Cloudflare 서비스 사이의 내부 연결 특성이 반영될 수 있었다.
이러한 값이 사용되면 보안 시스템은 잘못된 입력을 바탕으로 요청의 위험도를 판단할 수 있다.
이번 변경은 해당 입력을 원본 사용자 연결 기준으로 유지하도록 한다.
Cloudflare는 이를 통해 보안 규칙의 일관성과 Bot Management 결과의 정확성을 개선하고, 잘못된 403 오류를 줄일 수 있다고 설명한다.
다만 모든 403 오류가 해결된다는 의미는 아니다.
실제로 보안 정책에 위반되는 요청이나 다른 원인으로 차단되는 요청은 여전히 발생할 수 있다.
이번 개선은 Cloudflare Workers에서 Cloudflare가 프록시하는 BYOIP 호스트로 요청을 전달하는 특정 경로에 적용된다.
모든 Workers 요청이나 일반적인 외부 API 호출의 동작이 변경되는 것은 아니다.
별도의 설정 변경 없이 자동으로 적용된다.
4️⃣ 개발 도구 및 보안
GitHub Secret Scanning, Anthropic API Key의 Push 기본 차단 지원 — Salesforce·Cloudsmith 탐지 범위도 확대
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: GitHub Secret Scanning, Push Protection
- 원문: https://github.blog/changelog/2026-10-13-secret-scanning-blocks-anthropic-keys-by-default-adds-salesforce/
GitHub가 Anthropic API Key를 Git Push 시점에 기본적으로 차단하는 기능을 확대하고, Salesforce와 Cloudsmith의 새로운 인증 정보 탐지 유형을 추가했다.
애플리케이션을 개발할 때 외부 서비스의 API Key나 Access Token을 사용하는 경우가 많다.
정상적인 프로젝트에서는 이러한 인증 정보를 환경 변수나 별도의 비밀 정보 저장소에 보관해야 한다.
하지만 개발자가 설정 파일에 API Key를 임시로 작성하거나 테스트 과정에서 사용한 값을 제거하지 않은 채 Commit하는 문제가 발생할 수 있다.
이 정보가 공개 저장소에 업로드되면 제3자가 해당 Key를 이용해 API를 호출하거나 서비스에 접근할 가능성이 생긴다.
GitHub Secret Scanning은 저장소에 포함된 인증 정보를 탐지하는 기능이다.
Push Protection은 여기에 한 단계를 더해 민감한 인증 정보가 포함된 변경 사항이 저장소에 Push되기 전에 차단할 수 있도록 한다.
Anthropic API Key의 기본 차단
이번 업데이트에서는 다음 두 종류의 Anthropic 인증 정보가 기본 Push Protection 대상에 추가됐다.
anthropic_service_api_keyanthropic_user_api_key
이 유형의 인증 정보가 포함된 Commit을 Push하면 GitHub가 해당 Push를 자동으로 차단할 수 있다.
적용 대상에는 Secret Scanning이 활성화된 저장소가 포함되며, 무료 공개 저장소도 해당 범위에 포함된다.
다만 GitHub의 모든 비공개 저장소에서 별도의 조건 없이 자동으로 차단 기능이 활성화된다는 의미는 아니다.
저장소에 적용된 Secret Scanning 및 Push Protection 설정에 따라 실제 동작이 달라질 수 있다.
이번 변경은 Anthropic API Key를 사용하는 개발자가 실수로 인증 정보를 Commit했을 때 저장소에 업로드되기 전에 문제를 발견할 수 있는 범위를 확대한 것이다.
Salesforce가 Secret Scanning 파트너에 추가
GitHub는 Salesforce를 새로운 Secret Scanning 파트너로 추가했다.
새로 지원하는 Secret 유형은 다음과 같다.
salesforce_marketing_cloud_api_oauth2_token
GitHub가 공개 저장소에서 파트너사의 인증 정보를 발견하면 해당 제공업체에 정보를 전달할 수 있다.
제공업체는 전달받은 정보를 이용해 노출된 Credential을 폐기하거나 교체하는 대응을 수행할 수 있다.
이는 단순히 저장소 사용자에게 경고를 표시하는 것과 다르다.
인증 정보를 실제로 발급한 서비스 제공업체가 노출 사실을 인지하고 대응할 수 있도록 하는 구조다.
Cloudsmith 탐지 지원
패키지 관리 및 아티팩트 저장소 서비스인 Cloudsmith의 API Key 탐지도 추가됐다.
지원 유형은 다음과 같다.
cloudsmith_api_key
Cloudsmith는 패키지 저장소와 소프트웨어 배포 과정에서 사용될 수 있기 때문에 API Key가 노출되면 패키지 접근이나 배포 권한에 영향을 줄 가능성이 있다.
이번 변경으로 GitHub는 해당 인증 정보를 자동으로 탐지할 수 있게 됐다.
이미 노출된 인증 정보는 별도 대응이 필요
Push Protection은 새로운 인증 정보 노출을 줄이기 위한 기능이다.
하지만 인증 정보가 과거 Commit이나 다른 경로로 이미 노출됐다면 Push Protection을 활성화하는 것만으로 문제가 해결되지 않는다.
이 경우에는 해당 Credential을 폐기하거나 교체해야 한다.
Git 기록에서 문자열을 제거하더라도 이미 외부에 노출된 Key의 사용 가능성이 자동으로 사라지는 것은 아니기 때문이다.
이번 업데이트는 기존에 GitHub가 제공하던 AI 기반 비밀 정보 탐지 기능의 새로운 모델 발표와는 별개의 변경이다.
구체적인 API Key 형식에 대한 탐지 지원을 확대하고, Anthropic Key의 기본 Push 차단 범위를 넓힌 보안 업데이트다.
GitHub Dependabot, 철회된 보안 경고를 별도 상태로 식별 — Webhook에 withdrawn 추가, REST API는 410 반환
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: github.com 전체 저장소
- GitHub Enterprise Server: 3.24부터 포함 예정
- 원문: https://github.blog/changelog/2026-10-13-improved-detection-for-withdrawn-dependabot-alerts/
GitHub가 Dependabot 보안 경고가 철회된 상황을 Webhook과 REST API에서 명확하게 구분할 수 있도록 변경했다.
Dependabot은 프로젝트가 사용하는 라이브러리와 패키지의 의존성을 분석해 알려진 보안 취약점이 발견되면 경고를 생성한다.
예를 들어 특정 npm 패키지의 취약점이 공개되면 해당 패키지를 사용하는 저장소에 보안 경고가 표시될 수 있다.
하지만 모든 보안 권고가 끝까지 유효한 것은 아니다.
처음 보고된 취약점이 실제로 존재하지 않는 것으로 확인되거나, 해당 패키지에 영향을 주지 않는 것으로 밝혀지면 보안 권고가 철회될 수 있다.
이러한 상황에서 Dependabot은 기존 경고를 철회하고 제거한다.
문제는 외부 도구에서 이를 정확하게 파악하기 어려웠다는 점이다.
예를 들어 REST API로 이전에 존재하던 경고를 조회했는데 HTTP 404가 반환됐다면 두 가지 가능성이 존재한다.
처음부터 존재하지 않았던 경고일 수도 있고, 한때 존재했지만 이후 철회된 경고일 수도 있다.
두 상황은 보안 관리 측면에서 의미가 다르다.
이번 업데이트는 이 차이를 구분한다.
Webhook에 withdrawn 이벤트 추가
Dependabot의 dependabot_alert Webhook에 새로운 Action이 추가됐다.
withdrawn
경고를 생성했던 보안 권고가 더 이상 유효하지 않은 것으로 판단돼 철회되면 해당 이벤트가 전달된다.
Webhook Payload에는 경고가 삭제되기 전에 확인할 수 있었던 식별 정보가 포함된다.
주요 정보는 다음과 같다.
- Dependabot Alert 번호
- GHSA 식별자
- CVE 식별자
- 영향을 받는 패키지
- Manifest 파일 경로
이 정보는 외부 보안 대시보드나 알림 시스템이 기존 경고와 철회 이벤트를 연결하는 데 사용할 수 있다.
예를 들어 조직 내부 시스템이 Dependabot Alert를 별도로 저장하고 있다면, withdrawn 이벤트를 수신했을 때 해당 경고를 철회 상태로 변경할 수 있다.
중요한 점은 기존에 dependabot_alert Webhook을 구독하고 있는 애플리케이션에도 새로운 이벤트가 자동으로 전달된다는 것이다.
따라서 Webhook 처리 코드가 알 수 없는 Action을 무시하거나 오류로 처리하는 구조라면 새로운 withdrawn 값을 정상적으로 처리할 수 있는지 확인해야 한다.
REST API에서 404와 410 구분
REST API의 응답도 변경됐다.
기존에는 철회된 경고를 조회하거나 수정하려고 할 때 HTTP 404가 반환될 수 있었다.
이제는 HTTP 410 Gone이 반환된다.
HTTP 404 Not Found는 요청한 리소스를 찾을 수 없다는 의미다.
반면 HTTP 410 Gone은 해당 리소스가 더 이상 존재하지 않으며 제거된 상태라는 의미를 표현하는 데 사용된다.
이번 변경에서는 410 응답을 이용해 철회된 보안 경고와 처음부터 존재하지 않았던 경고를 구분한다.
이 차이는 자동화된 보안 시스템에서 중요하다.
예를 들어 경고가 404를 반환했다는 이유만으로 데이터를 단순히 삭제하면 실제로는 철회된 경고라는 기록을 잃을 수 있다.
반면 410을 별도로 처리하면 외부 시스템에서 경고가 철회됐다는 이력을 유지할 수 있다.
또한 보안 취약점이 실제로 수정돼 경고가 해결된 상황과 취약점 자체가 유효하지 않아 경고가 철회된 상황도 구분할 수 있다.
이번 변경은 github.com의 모든 저장소에 적용된다.
GitHub Enterprise Server에는 3.24 버전부터 포함될 예정이다.
새로운 취약점 탐지 엔진이나 보안 분석 알고리즘을 추가한 기능은 아니다.
이미 생성된 보안 경고의 상태와 수명주기를 외부 시스템이 정확하게 이해할 수 있도록 API와 Webhook의 의미를 개선한 업데이트다.
GitHub Copilot, 기업 관리 정책의 최신 상태 확인 강제 — 오래된 설정으로 에이전트가 실행되는 문제 방지
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 적용 대상: GitHub Copilot CLI, VS Code, GitHub Copilot App
- 원문: https://github.blog/changelog/2026-10-13-enterprise-managed-settings-enforcement-updates/
GitHub가 Copilot의 기업 관리 정책을 시작 시점에 다시 확인하도록 강제할 수 있는 설정을 추가했다.
기업에서 AI 코딩 에이전트를 사용할 때는 개인 개발자의 설정뿐 아니라 조직 전체의 보안 정책도 중요하다.
예를 들어 어떤 디렉터리에 접근할 수 있는지, 네트워크 통신을 허용할지, 로컬 샌드박스를 반드시 사용해야 하는지 등을 조직 차원에서 제한할 수 있다.
문제는 관리 정책이 변경됐더라도 개발자의 Copilot 클라이언트가 이전에 받아 둔 설정을 계속 사용할 수 있다는 점이다.
일반적인 애플리케이션에서는 캐시가 시작 속도를 높이고 네트워크 장애에 대한 복원력을 제공한다.
하지만 보안 정책에서는 오래된 캐시가 문제가 될 수 있다.
조직 관리자가 특정 권한을 제한했는데 클라이언트가 이전 정책으로 실행된다면 현재 조직이 요구하는 제한이 적용되지 않을 수 있기 때문이다.
이번 업데이트는 이를 해결하기 위해 forceRemoteSettingsRefresh 설정을 추가했다.
시작 시점에 관리 정책 새로고침
기업 관리자는 다음 설정을 사용할 수 있다.
forceRemoteSettingsRefresh: true
설정은 다음 경로를 통해 전달할 수 있다.
- 서버에서 관리하는 설정
- MDM(Mobile Device Management) 관리 설정
- 파일 기반 설정
이 값이 활성화되면 지원되는 Copilot 클라이언트는 시작 시점에 최신 관리 정책을 확인해야 한다.
기존에 저장된 캐시만으로는 정책 확인을 완료한 것으로 인정하지 않는다.
예를 들어 사용자가 Copilot CLI를 실행했는데 네트워크 문제로 기업의 현재 정책을 가져오지 못했다고 가정해 보자.
기존 방식에서는 캐시된 정책을 사용해 계속 실행할 수 있었다.
하지만 새 설정이 활성화된 환경에서는 최신 정책을 확인할 수 없다면 실행을 허용하지 않는 Fail Closed 방식이 적용된다.
이는 가용성보다 보안 정책의 일관성을 우선하는 선택이다.
설정 전달 방식별 차이
MDM 또는 파일 기반으로 정책을 전달하면 사용자가 Copilot에 처음 로그인하기 전부터 최신 정책 확인을 강제할 수 있다.
반면 서버에서만 관리하는 설정은 클라이언트가 해당 설정을 최소 한 번 받아야 이후 시작 시점부터 새로고침을 강제할 수 있다.
즉 서버 관리 정책은 첫 실행 이전에는 클라이언트가 해당 규칙의 존재 자체를 알지 못할 수 있다.
따라서 조직이 처음 실행하는 단계부터 엄격한 정책 확인을 요구한다면 정책 전달 방식도 함께 고려해야 한다.
기본값은 기존 방식과 동일하다.
forceRemoteSettingsRefresh를 활성화하지 않은 환경에서는 일반적인 관리 설정 캐시가 계속 사용된다.
따라서 이번 발표로 모든 Copilot 사용자가 시작할 때마다 반드시 네트워크 정책 조회에 성공해야 하는 것은 아니다.
샌드박스 정책에 최소 클라이언트 버전 적용
이번 업데이트에는 sandbox 관리 설정의 최소 클라이언트 버전 강제 기능도 포함됐다.
GitHub는 앞서 Copilot의 로컬 샌드박싱 기능을 정식 출시했다.
로컬 샌드박싱은 AI 코딩 에이전트가 실행하는 명령의 파일시스템과 네트워크 접근을 운영체제 수준에서 제한하는 기능이다.
하지만 사용자가 오래된 Copilot 버전을 고정해서 사용한다면 새로운 관리 정책을 제대로 적용하지 못할 수 있다.
이번 변경으로 sandbox 관리 설정에는 필요한 최소 클라이언트 버전이 적용된다.
해당 정책이 활성화된 조직에서 오래된 Copilot 클라이언트를 사용하는 개발자는 Copilot을 계속 사용하기 전에 업데이트해야 한다.
이는 단순히 최신 기능을 사용할 수 있도록 권장하는 것과 다르다.
필수 보안 정책을 구현하지 못하는 오래된 클라이언트의 실행을 제한한다는 의미다.
다만 이번 기능은 관리 정책에 최소 버전 요구사항이 포함된 경우에 적용된다.
모든 Copilot 사용자가 일괄적으로 특정 버전 이상으로 업데이트해야 한다는 뜻은 아니다.
이번 발표는 새로운 AI 모델이나 코딩 기능이 아니라 기업 환경에서 AI 에이전트의 실행 권한과 정책 적용 시점을 더 엄격하게 관리할 수 있도록 하는 보안·운영 기능이다.
GitHub Copilot, Gemini 4 Argon 정식 지원 — 복잡한 코딩 작업을 위한 신규 모델 선택지 추가
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 안정화 단계: Generally Available, 점진적 배포
- 적용 대상: GitHub Copilot Pro+, Max, Business, Enterprise
- 원문: https://github.blog/changelog/2026-10-13-gemini-4-argon-in-github-copilot/
GitHub가 Google의 Gemini 4 Argon 모델을 GitHub Copilot에서 정식으로 사용할 수 있도록 지원한다고 발표했다.
이번 모델은 복잡한 코딩 작업, 여러 단계의 도구 호출, 추론이 필요한 개발 작업을 대상으로 제공된다.
기존 Copilot에서도 여러 AI 모델 가운데 하나를 선택할 수 있었지만, 이번 업데이트로 Gemini 4 Argon이 새로운 선택지에 추가됐다.
지원 개발 환경
Gemini 4 Argon은 다음 환경에서 사용할 수 있다.
- Visual Studio Code
- Visual Studio
- GitHub Copilot CLI
- GitHub Copilot Coding Agent
- GitHub Copilot App
- JetBrains IDE
- Xcode
- Eclipse
단순한 IDE 채팅뿐 아니라 CLI와 코딩 에이전트에서도 같은 모델 계열을 선택할 수 있다는 점이 특징이다.
GitHub는 이번 모델이 복잡한 코딩 및 에이전트 작업에 맞춰 설계됐다고 설명한다.
예를 들어 코드베이스를 분석하고 여러 파일을 수정하거나, 작업 이후 테스트를 실행하고 결과를 확인하는 종류의 작업을 대상으로 한다.
GitHub의 초기 테스트에서는 기존 Gemini 모델보다 여러 코딩 Benchmark에서 더 많은 작업을 해결했다고 밝혔다.
특히 Copilot CLI에서 개선 폭이 컸다고 설명한다.
하지만 이번 발표에는 모델별 상세 점수나 독립적으로 재현할 수 있는 측정 결과가 제공되지 않았다.
따라서 기존 모델보다 항상 정확하다거나 모든 프로젝트에서 더 빠르다고 단정할 수는 없다.
모델의 성능은 작업의 유형, 코드베이스의 크기, 사용 가능한 도구, 입력 문맥과 평가 방식에 따라 달라질 수 있다.
사용 대상과 과금
Gemini 4 Argon은 Copilot Pro+, Max, Business, Enterprise 사용자에게 제공된다.
모델은 사용량 기반 과금 방식에서 제공업체의 공개 가격표 기준으로 청구된다.
따라서 기존 Copilot의 모든 모델과 동일한 비용으로 사용할 수 있다고 가정해서는 안 된다.
GitHub는 모델별 가격과 사용량을 공식 가격 문서에서 확인하도록 안내한다.
모델은 점진적으로 배포된다.
정식 출시 발표 이후에도 사용자의 모델 선택 목록에 즉시 표시되지 않을 수 있다.
기업 및 조직 관리자는 Copilot 설정의 모델 정책에서 해당 모델의 사용 가능 여부를 관리할 수 있다.
기본 모델 활성화 정책을 사용하는 조직에서는 새 모델이 자동으로 활성화될 수 있다.
반대로 관리자가 기본 활성화 정책을 해제하거나 Gemini 4 Argon을 명시적으로 비활성화하면 조직 구성원이 모델을 선택할 수 없게 된다.
이번 발표는 GitHub Copilot 자체의 코드 실행 권한이나 보안 정책을 변경하는 것이 아니다.
기존 Copilot 개발 환경에서 사용할 수 있는 모델 선택지를 확대한 업데이트다.
GitHub Code Security, AI Scan 결과를 조직 단위로 분석하는 지표 공개 — 취약점 탐지와 실제 수정률 구분
- 발표일: 2026-10-13 — 정확한 게시 시각 미확인
- 안정화 단계: Public Preview
- 적용 대상: GitHub Code Security 또는 GitHub Advanced Security 고객
- 원문: https://github.blog/changelog/2026-10-13-code-scanning-ai-scan-metrics-in-security-overview/
GitHub가 AI Scan으로 발견한 코드 보안 문제와 실제 수정 현황을 조직 및 Enterprise 단위에서 확인할 수 있는 지표를 공개했다.
AI Scan은 PR의 코드 변경을 분석해 잠재적인 보안 문제를 찾아내는 기능이다.
그러나 AI 코드 리뷰 도구가 발견한 경고의 개수만으로 보안 효과를 판단하기는 어렵다.
경고가 많이 발생한다는 사실이 실제 코드의 보안 수준이 낮다는 의미일 수도 있지만, 탐지 범위가 넓어졌다는 의미일 수도 있기 때문이다.
또한 발견한 문제를 개발자가 실제로 수정하지 않는다면 경고가 많이 생성되더라도 운영상 효과는 제한적일 수 있다.
이번 업데이트는 이러한 차이를 구분하기 위해 탐지 수와 해결 수, 수정률, 자동 수정 제안의 사용 현황을 함께 제공한다.
추가된 지표
조직 및 Enterprise 관리자에게 제공되는 주요 정보는 다음과 같다.
- AI Scan으로 생성된 Finding 수
- 해결된 Finding 수
- 전체 Finding 대비 수정률
- Finding이 생성된 Repository
- 선택한 기간의 변화 추이
- 개발자가 Autofix 제안을 적용한 빈도
예를 들어 특정 조직에서 AI Scan이 많은 문제를 발견했지만 실제 수정률은 낮을 수 있다.
이 경우 관리자는 단순히 탐지 기능을 더 많이 실행하는 것보다 현재 발견된 문제가 개발자의 작업으로 연결되고 있는지 검토할 수 있다.
반대로 발견된 문제의 상당수가 실제로 수정되고 있다면 조직 차원에서 기능의 운영 결과를 파악할 수 있다.
보안 개요 화면 변경
기존의 CodeQL Pull Requests 페이지는 Code Scanning on Pull Requests로 이름이 변경됐다.
해당 페이지에는 CodeQL과 AI Scan을 구분하는 탭이 추가됐다.
기존 CodeQL 지표는 CodeQL 탭에서 계속 확인할 수 있다.
AI Scan 탭에서는 발견된 문제의 총개수와 Autofix 제안이 포함된 문제 및 포함되지 않은 문제의 수를 구분할 수 있다.
이를 통해 조직 관리자는 개별 PR을 하나씩 열어보지 않고도 AI Scan의 사용 현황과 개발자의 대응 상태를 파악할 수 있다.
다만 이러한 지표는 AI Scan이 발견한 문제를 기준으로 계산된다.
AI Scan이 탐지하지 못한 보안 취약점까지 포함한 전체 코드베이스의 보안 수준을 나타내는 것은 아니다.
또한 수정률이 높더라도 수정 내용이 실제로 올바른지에 대한 독립적인 검증은 별개로 필요하다.
이번 기능은 github.com과 GitHub Enterprise Cloud에서 Public Preview로 제공된다.
GitHub Code Security 또는 GitHub Advanced Security 고객이 대상이다.
GitHub Enterprise Server는 이번 Preview의 지원 대상이 아니다.
이번 업데이트는 새로운 취약점 탐지 모델을 발표한 것이 아니라 기존 AI 기반 보안 분석의 결과를 조직 차원에서 관찰하고 관리할 수 있도록 지표를 추가한 기능이다.
📚 추천 글
CSS transform-origin and Animation Timing: Why the Pivot Changes the Speed
- 저자: Roan Vesper / Art of Styleframe
- 게시일: 2026-10-13
- 원문: https://artofstyleframe.com/blog/css-transform-origin-animation-timing/
CSS 애니메이션에서 동일한 회전 각도와 지속 시간, Easing Curve를 사용하더라도 transform-origin에 따라 화면에서 느껴지는 속도가 달라지는 이유를 실제 브라우저 측정으로 설명한 글이다.
일반적으로 애니메이션 속도를 조정할 때는 duration이나 cubic-bezier()의 값을 변경한다.
그러나 요소가 회전하거나 크기가 변하는 애니메이션에서는 변환의 기준점도 중요한 역할을 한다.
transform-origin은 CSS Transform이 적용되는 기준점을 결정한다.
기본값은 50% 50%로 요소의 중앙이다.
이를 0 0으로 변경하면 요소의 왼쪽 위 모서리를 기준으로 회전하거나 크기가 변경된다.
같은 각도로 회전하더라도 실제로 각 지점이 이동하는 거리는 달라진다.
회전 기준점에 따른 실제 이동 거리
저자는 Chromium 브라우저에서 가로 200px, 세로 120px인 요소를 12도 회전시키는 실험을 수행했다.
요소의 네 모서리에 측정 지점을 배치하고, 회전 전후의 위치를 비교했다.
결과는 다음과 같다.
transform-origin | 가장 멀리 이동한 모서리 |
|---|---|
50% 50% — 중앙 | 24.4px |
50% 0 — 위쪽 중앙 | 32.7px |
0 0 — 왼쪽 위 모서리 | 48.8px |
50% -60px — 요소 위쪽 60px | 43.1px |
흥미로운 점은 회전 각도가 모두 12도로 동일하다는 것이다.
중앙을 기준으로 회전할 때 가장 멀리 이동한 모서리는 24.4px 움직였다.
반면 왼쪽 위 모서리를 기준으로 회전하면 반대쪽 모서리는 48.8px 움직였다.
같은 회전 각도에서 최대 이동 거리가 약 두 배로 증가한 것이다.
애니메이션 지속 시간이 동일하다면 두 배의 거리를 같은 시간 안에 이동해야 한다.
따라서 CSS의 Easing Curve를 변경하지 않았더라도 화면에서는 더 빠르고 과장된 움직임처럼 느껴질 수 있다.
이는 단순한 시각적 착각이 아니다.
회전하는 지점이 중심에서 멀어질수록 이동 거리가 증가하기 때문이다.
크기 변경에서도 동일한 현상이 발생
저자는 Scale Transform에서도 같은 실험을 수행했다.
가로 240px, 세로 160px인 요소를 0.9배로 축소했다.
결과는 다음과 같다.
transform-origin | 가장 멀리 이동한 모서리 |
|---|---|
50% 50% | 14.4px |
50% 0 | 20.0px |
0 0 | 28.8px |
회전과 마찬가지로 중심을 기준으로 축소하는 경우보다 모서리를 기준으로 축소하는 경우 최대 이동 거리가 두 배가 됐다.
이는 팝오버나 드롭다운 메뉴처럼 크기 변화를 이용해 열리는 UI에서 중요하다.
예를 들어 버튼 바로 아래에 나타나는 메뉴가 화면 중앙을 기준으로 확대된다면, 메뉴가 버튼에서 시작되는 것이 아니라 허공에서 부풀어 오르는 것처럼 보일 수 있다.
반면 버튼과 연결되는 모서리를 기준으로 확대하면 메뉴가 버튼에서 펼쳐지는 것처럼 느껴진다.
이 때문에 팝오버와 드롭다운에서는 트리거와 가까운 모서리 또는 가장자리를 transform-origin으로 사용하는 방식이 적합한 경우가 많다.
Easing Curve와 실제 속도
저자는 cubic-bezier(0.16, 1, 0.3, 1)을 사용하는 애니메이션도 측정했다.
이 Easing Curve는 애니메이션 초반에 빠르게 진행하고 후반에는 느리게 마무리되는 형태다.
같은 300ms 애니메이션에서 회전 기준점을 중앙에서 모서리로 옮기면 실제 이동 거리가 증가한다.
그 결과 가장 멀리 이동하는 지점의 속도도 증가한다.
저자는 기준점이 달라졌을 때 애니메이션이 지나치게 빠르게 느껴진다면 지속 시간을 늘리기보다 회전 각도나 크기 변화량을 먼저 조정하는 방식을 제안한다.
예를 들어 중앙 기준에서 12도 회전하던 요소를 모서리 기준으로 변경한다면 회전 각도를 6도로 줄여 이동 거리를 비슷하게 맞출 수 있다.
지속 시간을 두 배로 늘리는 방법도 존재하지만, 애니메이션 전체가 지나치게 느려질 수 있다.
SVG와 접근성에 관한 제한사항
SVG에서는 transform-origin이 일반적인 HTML 요소와 다르게 동작할 수 있다.
특히 기준이 되는 Bounding Box와 좌표계가 다를 수 있으므로 transform-box 설정을 함께 고려해야 한다.
또한 사용자의 운영체제에서 움직임 감소 설정을 활성화했다면 prefers-reduced-motion을 이용해 애니메이션을 축소하거나 제거하는 방식도 필요하다.
이번 글의 측정은 요소의 이동 거리와 속도에 초점을 맞추고 있다.
따라서 transform-origin을 변경했다고 해서 GPU 처리 비용이나 프레임 속도가 일정한 비율로 개선되거나 악화된다고 해석해서는 안 된다.
움직임의 기하학적 특성과 애니메이션 렌더링 성능은 별개의 문제다.
이 글은 CSS 애니메이션을 감각적으로 조정하는 방법을 넘어 같은 CSS Timing 설정에서도 실제 이동 거리가 달라지면 사용자가 느끼는 움직임이 달라진다는 사실을 구체적인 측정값으로 보여준다.
The JavaScript Event Loop, Fully Explained: Tasks, Microtasks, and Where Rendering Fits In
- 저자: Ghazi Khan / IOCombats
- 게시일: 2026-10-12
- 원문: https://iocombats.com/blogs/javascript-event-loop-tasks-microtasks-rendering-explained
JavaScript의 Event Loop를 Task와 Microtask의 실행 순서뿐 아니라 실제 브라우저의 렌더링 과정까지 연결해 설명한 글이다.
Event Loop는 JavaScript 면접에서 자주 등장하는 주제다.
일반적으로는 동기 코드가 먼저 실행되고, Promise Callback과 같은 Microtask가 실행된 뒤 setTimeout Callback이 실행된다는 규칙을 암기하는 경우가 많다.
하지만 이러한 순서만 이해해서는 실제 웹 애플리케이션에서 발생하는 성능 문제를 충분히 설명하기 어렵다.
예를 들어 다음과 같은 상황을 생각해 볼 수 있다.
사용자가 버튼을 클릭했을 때 이벤트 핸들러는 빠르게 실행되지만 화면이 늦게 바뀐다.
또는 긴 반복 작업에 await를 추가했는데도 브라우저가 계속 멈춘다.
이런 문제를 이해하려면 Event Loop가 JavaScript 코드 실행뿐 아니라 사용자 입력과 브라우저 렌더링을 언제 처리할 수 있는지까지 알아야 한다.
Task와 Microtask의 차이
브라우저의 메인 스레드에서는 JavaScript 실행, 사용자 입력 처리, 스타일 계산, 레이아웃, 페인팅 등이 이루어진다.
하나의 JavaScript Task가 실행 중이라면 일반적으로 해당 Task가 종료되기 전까지 다른 Task를 실행할 수 없다.
예를 들어 300ms 동안 CPU를 계속 사용하는 JavaScript 함수가 실행된다면 그 시간 동안 브라우저는 사용자 입력과 화면 렌더링을 원활하게 처리하지 못할 수 있다.
setTimeout Callback은 일반적인 Task로 실행된다.
반면 Promise의 .then() Callback이나 queueMicrotask()로 등록한 작업은 Microtask Queue에서 처리된다.
중요한 규칙은 Microtask Queue가 비워질 때까지 Microtask를 계속 실행한다는 것이다.
Microtask가 실행되는 동안 새로운 Microtask를 추가하면 해당 작업도 현재 Microtask 처리 과정에 포함될 수 있다.
따라서 Microtask가 계속 자기 자신을 등록하는 구조에서는 브라우저가 다음 Task나 렌더링 과정으로 넘어가지 못할 수 있다.
이러한 상황을 Microtask Starvation이라고 한다.
await가 항상 브라우저에 렌더링 시간을 주는 것은 아니다
저자는 await Promise.resolve()를 이용한 예제를 통해 이 문제를 설명한다.
개발자는 긴 반복문 안에 await를 추가하면 브라우저가 중간에 화면을 업데이트할 수 있다고 생각할 수 있다.
하지만 이미 해결된 Promise를 기다리는 await는 다음 코드를 Microtask로 이어서 실행할 수 있다.
따라서 반복문이 계속 Microtask만 생성한다면 브라우저는 중간에 렌더링할 기회를 얻지 못할 수 있다.
즉 await가 존재한다는 사실과 브라우저 메인 스레드가 다음 화면을 렌더링할 기회를 얻는다는 사실은 동일하지 않다.
반대로 setTimeout을 이용해 작업을 여러 Task로 나누면 Task 사이에 브라우저가 사용자 입력이나 렌더링을 처리할 기회를 가질 수 있다.
다만 setTimeout을 사용하는 모든 반복문이 자동으로 효율적이라는 의미는 아니다.
각 Task 자체가 오래 실행된다면 여전히 사용자의 입력을 지연시킬 수 있다.
requestAnimationFrame과 화면 업데이트
requestAnimationFrame은 브라우저가 다음 화면을 렌더링하기 전에 Callback을 실행하도록 요청하는 API다.
일반적인 Task나 Microtask와는 다른 시점에 실행된다.
브라우저는 렌더링 업데이트 과정에서 requestAnimationFrame Callback을 실행하고 이후 필요한 스타일 계산과 레이아웃, 페인팅을 수행할 수 있다.
따라서 화면의 위치나 크기를 변경하는 애니메이션에서는 requestAnimationFrame을 활용할 수 있다.
하지만 requestAnimationFrame 안에서 무거운 계산을 수행하면 해당 Frame을 렌더링하는 작업이 지연될 수 있다.
또한 스타일을 변경한 직후 offsetHeight 같은 레이아웃 정보를 읽으면 브라우저가 필요한 레이아웃 계산을 즉시 수행해야 할 수 있다.
이런 과정이 반복되면 Forced Synchronous Layout 문제가 발생할 수 있다.
저자는 DOM의 읽기와 쓰기를 가능한 한 묶어서 처리하는 방식을 설명한다.
scheduler.yield()와 작업 분할
긴 작업을 여러 구간으로 나누는 방법으로 scheduler.yield()도 소개한다.
이 API는 실행 중인 JavaScript 작업이 다른 작업에 실행 기회를 제공한 뒤 다시 이어서 처리할 수 있도록 설계됐다.
예를 들어 수천 개의 데이터를 변환해야 한다면 전체 데이터를 하나의 긴 Task에서 처리하는 대신 일정량씩 나누어 실행할 수 있다.
이 과정에서 브라우저가 사용자 입력을 처리하거나 화면을 업데이트할 기회를 얻으면 체감 반응성을 개선할 수 있다.
그러나 scheduler.yield()는 모든 브라우저와 실행 환경에서 동일한 방식으로 사용할 수 있는 API라고 가정해서는 안 된다.
실제 적용 시에는 대상 브라우저의 지원 여부와 Fallback을 검토해야 한다.
Event Loop와 INP의 관계
글은 마지막으로 Event Loop의 동작을 INP와 연결한다.
INP는 사용자가 입력한 뒤 다음 화면 업데이트가 나타날 때까지의 반응성을 측정한다.
사용자 입력이 발생했을 때 긴 JavaScript Task가 실행 중이라면 입력 이벤트를 처리하기까지 대기 시간이 발생할 수 있다.
이벤트 핸들러 내부에서 오래 걸리는 작업을 수행해도 INP가 나빠질 수 있다.
또한 이벤트 핸들러가 종료된 이후에도 렌더링을 차단하는 작업이 존재하면 화면 업데이트가 늦어질 수 있다.
이는 앞선 Cloudflare Web Analytics의 INP 세부 지표와도 연결되는 개념이다.
다만 이 글은 특정 실제 애플리케이션을 최적화한 사례나 독립적인 성능 Benchmark를 제공하지 않는다.
Event Loop의 실행 규칙과 브라우저 스케줄링 API를 실제 코드 예제로 설명하는 기술 해설에 가깝다.
그럼에도 JavaScript의 비동기 실행 순서를 암기하는 수준에서 벗어나 렌더링과 사용자 입력 지연을 이해하는 데 필요한 실행 모델을 비교적 체계적으로 설명한다.
Under the Hood, Off the Hot Path: How D1 Scales to Millions of Databases
- 저자: David Laban, Lambros Petrou / Cloudflare
- 게시일: 2026-10-13
- 원문: https://blog.cloudflare.com/d1-control-plane/
Cloudflare가 서버리스 데이터베이스 D1을 수백만 개의 데이터베이스 인스턴스로 확장하기 위해 제어 영역과 실제 쿼리 실행 영역을 어떻게 분리했는지 설명한 기술 글이다.
이 글은 새로운 D1 API의 출시 공지가 아니다.
기존 D1의 내부 구조를 대규모 운영 환경에 맞게 개선한 과정과 그 과정에서 선택한 설계 원칙을 공개한다.
D1은 SQLite를 기반으로 하는 Cloudflare의 서버리스 데이터베이스다.
일반적인 관계형 데이터베이스 서비스에서는 하나의 애플리케이션이 하나 또는 소수의 대형 데이터베이스를 사용하는 구조가 흔하다.
반면 서버리스 애플리케이션이나 멀티테넌트 플랫폼에서는 고객, 사용자, 프로젝트, 미리보기 환경마다 독립적인 작은 데이터베이스를 제공하는 구조가 유용할 수 있다.
문제는 데이터베이스 하나의 크기가 작더라도 생성하고 관리해야 하는 데이터베이스의 개수가 매우 많아질 수 있다는 점이다.
Cloudflare가 공개한 자체 운영 자료에 따르면 2026년 10월 8일 기준 D1의 삭제되지 않은 데이터베이스 수는 1년 전보다 약 15배 증가했다.
2년 전과 비교하면 약 65배다.
하루 동안 실제 쿼리를 실행한 활성 데이터베이스 수 역시 1년 동안 약 18배 증가했다.
이 수치는 Cloudflare가 자체적으로 집계한 운영 데이터다.
데이터 영역과 제어 영역을 분리
D1의 중요한 설계 원칙은 실제 SQL 쿼리를 처리하는 경로에 중앙 집중식 관리 데이터베이스를 두지 않는 것이다.
Cloudflare는 D1의 내부 처리를 세 가지 영역으로 나눈다.
첫 번째는 Data Plane이다.
Data Plane은 실제 데이터베이스 쿼리를 실행하는 영역이다.
사용자의 요청과 직접 연결되기 때문에 가능한 한 낮은 지연 시간으로 처리해야 한다.
두 번째는 Control Plane이다.
Control Plane은 데이터베이스 생성과 삭제, 계정 설정, 권한, 메타데이터 등을 관리한다.
이러한 작업은 일반적인 SQL 쿼리처럼 매우 자주 발생하지 않으므로 중앙 데이터베이스를 사용할 수 있다.
세 번째는 비동기 작업 영역이다.
사용량 집계, 저장 용량 계산, 과금 관련 작업처럼 즉시 처리하지 않아도 되는 작업을 담당한다.
이 영역에서는 일정 수준의 최종 일관성(Eventual Consistency)을 허용할 수 있다.
중요한 점은 세 영역의 모든 작업이 동일한 일관성과 지연 시간 조건을 요구하지 않는다는 사실이다.
Cloudflare는 이를 이용해 중앙 데이터베이스에 강한 일관성이 필요한 관리 정보를 저장하되, 실제 사용자 쿼리에서는 해당 데이터베이스에 의존하지 않는 구조를 설계했다.
SQLite와 Durable Objects의 결합
D1의 각 데이터베이스는 내부적으로 하나의 SQLite 기반 Durable Object와 연결된다.
Durable Objects는 고유한 ID를 가진 상태 저장 실행 단위다.
각 객체는 자신의 상태를 관리하고 지속 저장소를 사용할 수 있다.
이 구조를 이용하면 수많은 작은 데이터베이스를 독립적으로 생성할 수 있다.
하지만 각 데이터베이스가 어느 Durable Object에 연결되는지 알아야 실제 쿼리를 전달할 수 있다.
Cloudflare는 이 관계를 관리하기 위해 데이터베이스 UUID와 Durable Object ID 사이의 매핑을 사용한다.
이 매핑을 매번 중앙 PostgreSQL에서 조회한다면 데이터베이스 개수가 늘어날수록 중앙 데이터베이스가 병목이 될 수 있다.
따라서 자주 읽히는 라우팅 정보를 Workers KV에 저장한다.
Workers KV와 Hyperdrive를 이용한 조회 경로
사용자가 HTTP API로 D1에 쿼리를 보내면 먼저 Edge API Worker가 요청을 처리한다.
Edge API Worker는 인증, 권한, 요청 검증, 사용량 제한 등을 확인한다.
이후 Workers KV에서 데이터베이스 UUID에 대응하는 정보를 조회한다.
Workers KV에서 필요한 정보를 찾으면 해당 Durable Object로 요청을 전달한다.
반면 KV에서 정보를 찾지 못한 경우에는 Hyperdrive를 통해 PostgreSQL의 읽기 복제본에서 필요한 정보를 조회한다.
Hyperdrive는 PostgreSQL 연결 풀링과 캐싱을 제공하기 때문에 중앙 데이터베이스에 직접 연결하는 비용을 줄일 수 있다.
또한 사용자가 Cloudflare Worker의 D1 Binding을 통해 데이터베이스에 접근하는 경우에는 필요한 라우팅 정보가 Binding 자체에 포함돼 있다.
따라서 이 경우에는 UUID 매핑을 조회하는 과정을 생략할 수 있다.
이러한 설계의 목표는 일반적인 쿼리 요청이 중앙 PostgreSQL을 거치지 않도록 만드는 것이다.
데이터베이스 생성 과정의 실패 처리
새로운 데이터베이스를 생성하는 과정에서는 여러 시스템에 정보를 기록해야 한다.
먼저 새 데이터베이스 UUID와 Durable Object ID를 생성한다.
Durable Object를 초기화한 뒤 PostgreSQL에 데이터베이스 정보를 저장한다.
마지막으로 Workers KV에 필요한 라우팅 정보를 기록한다.
문제는 이 과정이 여러 저장소에 걸쳐 있다는 점이다.
하나의 데이터베이스 트랜잭션으로 모든 시스템의 상태를 동시에 변경할 수 없다.
따라서 중간 단계에서 실패할 수 있다.
예를 들어 Durable Object 생성은 성공했지만 PostgreSQL에 정보를 기록하지 못할 수 있다.
반대로 PostgreSQL에 기록한 뒤 KV 업데이트가 실패할 수도 있다.
Cloudflare는 실패가 발생할 수 있다는 사실을 전제로 작업을 설계한다.
데이터베이스 생성 과정에는 재시도와 복구 가능한 상태를 정의하고, 일부 비동기 업데이트는 이후 다시 수행할 수 있도록 한다.
이 과정에서 모든 작업을 하나의 긴 분산 트랜잭션으로 묶지 않는다.
중앙 PostgreSQL의 트랜잭션을 오래 유지하면 데이터베이스 생성 요청이 증가할 때 Lock 경합과 지연 시간이 커질 수 있기 때문이다.
주기적인 Heartbeat를 이용한 상태 복구
각 데이터베이스의 Durable Object는 주기적으로 자신의 상태를 보고한다.
Cloudflare는 이 Heartbeat를 이용해 여러 저장소 사이의 상태가 어긋난 상황을 복구할 수 있도록 한다.
예를 들어 관리 데이터베이스와 Durable Object 사이에서 일부 업데이트가 누락됐다면, 이후 전달되는 상태 보고를 이용해 일관된 상태로 복구할 수 있다.
이는 모든 데이터 변경을 즉시 하나의 중앙 시스템과 동기화하는 방식과 다르다.
비동기적인 상태 확인과 복구 작업을 통해 여러 시스템의 상태가 결국 일치하도록 하는 방식이다.
이런 설계는 데이터베이스 인스턴스 수가 많고 여러 지역에 분산돼 있는 환경에서 중앙 시스템의 부하를 줄이는 데 도움이 된다.
사용량 집계에서 발생하는 병목
저장 용량을 계산하는 작업도 흥미롭다.
하나의 계정이 데이터베이스를 몇 개만 가지고 있다면 각 데이터베이스의 크기를 조회해 모두 더하는 방식으로 전체 사용량을 계산할 수 있다.
하지만 하나의 계정이 수백만 개의 데이터베이스를 가지고 있다면 단순한 합계 쿼리도 부담이 된다.
매번 전체 데이터베이스 목록을 조회하고 저장량을 더해야 하기 때문이다.
Cloudflare는 이 문제를 해결하기 위해 변경된 사용량을 별도로 기록한 뒤 주기적으로 집계하는 방식을 사용한다.
각 Durable Object는 저장량 정보를 비동기 메시지 시스템에 전달한다.
중앙 Consumer는 이 정보를 모아 PostgreSQL에 기록한다.
각 데이터베이스의 저장량이 변경되면 전체 사용량을 다시 계산하는 대신 이전 값과 새로운 값의 차이를 저장한다.
이후 주기적인 작업이 해당 차이들을 합산해 계정 단위의 저장 용량을 갱신한다.
이렇게 하면 사용량을 조회할 때 수백만 개의 데이터베이스를 매번 탐색하지 않아도 된다.
하지만 비동기 집계를 사용하기 때문에 실제 저장량과 관리 시스템에 표시되는 값 사이에는 짧은 시간 차이가 발생할 수 있다.
Cloudflare는 이러한 최종 일관성을 허용해 중앙 데이터베이스의 처리량과 운영 안정성을 확보한다.
설계의 핵심적인 트레이드오프
이 구조는 중앙 데이터베이스의 부담을 줄이고 전 세계 여러 지역에서 빠르게 쿼리를 처리하도록 설계됐다.
하지만 시스템이 단순해지는 것은 아니다.
Workers KV, Hyperdrive, PostgreSQL, Durable Objects, 비동기 메시지 시스템 등 여러 구성요소가 함께 동작해야 한다.
따라서 데이터베이스 생성 중 일부 단계가 실패했을 때 어떻게 복구할지, 사용량 정보가 늦게 반영돼도 되는지, 중앙 PostgreSQL이 일시적으로 사용할 수 없는 상황에서 어떤 기능을 유지해야 하는지 등을 명확하게 정의해야 한다.
Cloudflare가 제시한 구조가 모든 서비스에 필요한 것은 아니다.
작은 규모의 웹 애플리케이션에서는 하나의 PostgreSQL 데이터베이스와 적절한 Connection Pool만으로도 충분할 수 있다.
또한 이 글에서 제시한 성장 수치는 Cloudflare의 실제 운영 규모를 설명하지만, 동일한 아키텍처를 다른 환경에 적용했을 때 같은 성능이 나온다는 보장은 아니다.
그럼에도 제어 영역과 데이터 영역의 분리, 중앙 집중식 병목 제거, 비동기 집계, 장애 이후 상태 복구를 실제 대규모 데이터베이스 서비스에서 어떻게 구현했는지 자세히 살펴볼 수 있다.
Knowing When to Stop Retrying
- 저자: Torsten Landergren / Meltwater Engineering
- 게시일: 2026-10-13
- 원문: https://underthehood.meltwater.com/blog/2026/10/13/adaptive-retries/
Meltwater가 외부 서비스의 오류를 처리하기 위한 재시도 로직이 오히려 전체 시스템의 장애를 악화시키는 문제를 해결한 과정을 설명한 글이다.
웹 애플리케이션에서 외부 API 호출은 실패할 수 있다.
네트워크 연결이 일시적으로 끊기거나 서버가 짧은 시간 동안 오류를 반환하는 상황에서는 요청을 다시 보내는 것이 도움이 될 수 있다.
이 때문에 많은 백엔드 시스템이 Retry와 Exponential Backoff를 사용한다.
하지만 이미 과부하 상태에 있는 서버에 재시도 요청을 계속 보내면 서버의 부하가 더 증가할 수 있다.
Meltwater는 실제 운영 환경에서 이런 문제를 경험했다.
여러 계층의 재시도가 서로 증폭된 문제
Meltwater의 서비스 구조에는 여러 API 계층이 존재한다.
프론트엔드에서 사용하는 BFF(Backend for Frontend)가 Middleware API를 호출하고, Middleware API는 공유 Elasticsearch 클러스터에 검색 요청을 전달한다.
Middleware API는 고객의 접근 권한을 확인하고 검색 결과에 필요한 처리를 추가한다.
문제는 여러 서비스 계층이 각각 독립적인 재시도 로직을 가지고 있었다는 것이다.
예를 들어 상위 API가 요청을 세 번 재시도하고 하위 API도 각 요청을 세 번 재시도한다면, 원래 하나였던 사용자 요청이 여러 개의 Elasticsearch 요청으로 확대될 수 있다.
Meltwater가 분석한 최악의 경우에는 사용자 요청 하나가 Elasticsearch 요청 144개로 증가할 수 있었다.
이 현상은 Retry Storm이라고 한다.
원래 재시도는 일시적인 실패를 복구하기 위해 설계됐지만, 실제 장애 상황에서는 동일한 서버에 더 많은 요청을 보내면서 복구를 방해할 수 있다.
Meltwater는 먼저 서비스 계층 사이에서 어떤 오류를 재시도할지 정책을 정리했다.
하위 서비스가 이미 재시도를 수행했다면 상위 서비스가 같은 작업을 반복하지 않도록 조정했다.
또한 모든 오류 상태를 무조건 재시도하는 대신 실제로 재시도할 가치가 있는 오류만 처리하도록 변경했다.
이후 Middleware API에도 추가적인 보호 장치를 도입했다.
Retry 횟수가 아니라 Retry 예산을 관리
Meltwater가 선택한 방법은 Token Pool을 이용해 일정 기간 허용할 재시도의 총량을 제한하는 것이다.
기존 Retry Policy에 토큰 기반 제한을 추가했다.
각 API 인스턴스에는 일정한 개수의 토큰이 주어진다.
재시도를 수행할 때마다 토큰 하나를 사용한다.
토큰이 모두 소진되면 해당 인스턴스는 더 이상 재시도를 수행하지 않는다.
중요한 점은 최초 요청 자체를 차단하지 않는다는 것이다.
Circuit Breaker는 특정 조건에서 외부 서비스에 대한 요청 자체를 차단할 수 있다.
반면 이번 Token Pool은 원래 사용자가 보낸 요청은 계속 전달한다.
재시도만 제한한다.
따라서 외부 서비스가 일부 요청에 대해서는 정상적으로 응답할 수 있다면 해당 요청은 그대로 처리할 수 있다.
또한 토큰은 성공한 요청이 발생했을 때 다시 채워진다.
서비스가 계속 실패하는 상황에서는 재시도 예산을 빠르게 복구하지 않도록 설계한 것이다.
실제 운영 설정
Meltwater가 처음 적용한 설정은 다음과 같다.
| 항목 | 설정 |
|---|---|
| 초기 Token Pool | API 인스턴스당 25개 |
| 토큰 보충 속도 | 초당 1개 |
| 토큰 보충 조건 | 요청 성공 |
| API 인스턴스 | 4개 |
| 일반적인 요청량 | 전체 초당 약 40~100개 |
예를 들어 Elasticsearch가 과부하 상태에 들어가 대부분의 요청이 실패한다고 가정해 보자.
기존 방식에서는 실패한 요청마다 재시도가 발생하면서 추가 부하가 계속 증가할 수 있다.
새로운 방식에서는 각 API 인스턴스의 토큰이 빠르게 소진된다.
이후에는 사용자의 원래 요청만 전달되고 불필요한 재시도 요청은 차단된다.
서비스가 다시 정상적인 응답을 반환하기 시작하면 성공한 요청을 통해 토큰이 보충된다.
따라서 장애가 복구되는 과정에서 재시도가 점진적으로 다시 허용된다.
실제 장애에서 확인한 결과
Meltwater는 새로운 방식을 적용한 뒤 Elasticsearch 클러스터에 다시 과부하가 발생했을 때의 운영 데이터를 공개했다.
해당 장애는 약 15분 동안 지속됐다.
로그와 모니터링 결과를 분석한 결과 새로운 Token Pool이 재시도를 빠르게 제한했다.
Meltwater는 이 과정에서 23,000건 이상의 재시도 요청을 방지했다고 설명한다.
이는 장애가 시작될 당시 요청량과 비교했을 때 약 60%에 해당하는 규모였다.
만약 해당 요청들이 모두 Elasticsearch로 전달됐다면 이미 과부하 상태인 클러스터에 상당한 추가 부하가 발생했을 것이다.
반대로 정상적인 상황에서는 Token Pool이 거의 소진되지 않았다.
따라서 일시적인 오류가 발생했을 때는 기존과 비슷하게 재시도를 수행할 수 있었다.
이 수치는 Meltwater가 실제 운영 환경에서 수집한 자체 측정 결과다.
독립적인 통제 실험은 아니지만 실제 장애 중에 재시도 요청량이 어떻게 달라졌는지 보여준다는 점에서 의미가 있다.
여러 서버 인스턴스가 있는 경우의 제한
현재 Token Pool은 각 Kubernetes Pod에 독립적으로 존재한다.
이 방식은 구현이 단순하고 중앙 저장소를 추가하지 않아도 된다는 장점이 있다.
하지만 서버 인스턴스를 늘리면 전체 재시도 예산도 함께 증가한다.
예를 들어 인스턴스가 네 개일 때는 초기 토큰이 총 100개지만, 인스턴스가 여덟 개로 증가하면 총 200개의 초기 토큰을 사용할 수 있게 된다.
따라서 수평 확장 과정에서 외부 Elasticsearch가 받는 재시도 부하도 증가할 가능성이 있다.
Meltwater는 향후 여러 인스턴스가 하나의 Token Pool을 공유하는 구조를 검토할 수 있다고 설명한다.
또한 현재 사용 중인 초기 토큰 25개와 초당 1개 보충이라는 수치도 정교한 분석으로 결정된 값은 아니다.
운영 경험을 바탕으로 우선 적용한 설정이며, 앞으로 조정할 여지가 있다고 명시했다.
따라서 다른 서비스가 같은 수치를 그대로 사용한다고 해서 동일한 효과를 얻을 수 있는 것은 아니다.
재시도 정책은 시스템 전체에서 설계해야 한다
이 글의 핵심은 특정 Retry 라이브러리를 선택하는 문제가 아니다.
여러 서비스가 연결된 시스템에서는 한 계층의 재시도가 다른 계층의 재시도와 결합해 예상하지 못한 요청량을 만들 수 있다.
따라서 각 서비스가 독립적으로 재시도 횟수를 늘리는 것보다 전체 요청 경로에서 재시도가 몇 번 발생할 수 있는지를 관리해야 한다.
또한 모든 실패를 같은 방식으로 처리해서는 안 된다.
짧은 네트워크 오류에서는 재시도가 도움이 될 수 있지만, 서버 자체가 과부하 상태라면 재시도가 장애를 악화시킬 수 있다.
Meltwater의 사례는 재시도 기능의 존재 여부보다 언제 재시도를 중단해야 하는지 판단하는 정책이 중요하다는 점을 실제 운영 데이터로 설명한다.