---
title: "Cortex 라우터: 모든 요청에 가장 빠른 정상 노드를 선택하는 방법"
description: "요청을 가까운 리전으로 보내는 것은 기본 요건일 뿐입니다. 그 다음, 즉 어떤 노드가 응답할지 선택하는 과정에서 Cortex가 작동합니다."
---

# Cortex 라우터: 모든 요청에 가장 빠른 정상 노드를 선택하는 방법

<ImageBlock
  src="https://media.alchemy.com/blog/cortex-router-hero-16x9-20260821.png"
  alt="Cortex 라우터: 모든 요청에 가장 빠른 정상 노드를 선택하는 방법"
  width={1920}
  height={1080}
  priority
/>

앱이 보내는 모든 RPC 호출은 노드에 도달했다가 돌아와야 사용자에게 무언가가 보입니다. 그 호출을 가까운 리전으로 보내는 것은 진지한 프로바이더라면 모두 자동으로 하는 일이고, 우리도 그렇습니다. 그리고 첫 홉을 더 줄이기 위해 계속 리전을 늘려가고 있습니다. 더 흥미로운 질문은 그 뒤에 무슨 일이 일어나는가입니다. 그 리전 안에서 구체적으로 어떤 노드가 응답하는지, 그리고 요청을 보내기 전에 그 노드가 정상 상태이고 체인을 따라잡았는지를 무언가가 확인했는지 하는 것입니다.

두 번째 결정이 바로 우리가 요청마다 새로 내리는 결정이고, [EVM 체인 전반에서 평균 응답 시간이 15ms 미만](https://www.alchemy.com/benchmarks)인 이유의 상당 부분을 차지합니다. 이 수치는 이미 열려 있는 연결에서 측정한 웜(warm) 요청-응답 시간으로, 실행 중인 앱에서 반복되는 트래픽의 모습과 같습니다. DNS, 연결 설정, TLS 핸드셰이크는 제외되어 있으므로, 아래에서 다루는 엣지 작업은 이 수치 안이 아니라 밖에 있습니다.

## Cortex 라우터는 실제로 무엇을 결정하는가?

[Cortex](https://www.alchemy.com/blog/cortex)는 노드 플릿부터 라우팅 레이어, 그 위의 RPC 및 Data API까지 Alchemy 플랫폼 전체를 구동하는 엔진입니다. 예전 구성은 트래픽 앞단에 서드파티 CDN을 두었는데, 이는 그 CDN을 모든 네트워크와 모든 고객에 대한 단일 장애점으로 만들었습니다. 이를 [우리가 직접 운영하는 베어메탈](https://www.alchemy.com/blog/the-tech-behind-cortex)로 교체하면서 그 의존성을 제거했고 전체 경로를 우리의 운영 아래 두게 되었습니다. 이제 여러분이 보내는 모든 요청은 Cortex를 거치며, 라우터는 특정 요청이 어디로 갈지 결정하는 부분입니다.

각 요청에 대해 라우터는 경로를 선택합니다. 어떤 리전이 이를 받아들일지, 어떤 노드가 처리할지, 그리고 그 노드가 처리 중에 상태가 나빠지면 어떻게 할지를 말입니다. "여러분의 체인으로 가는 최적 경로"란 결국 지금 이 순간 이 특정 호출에 정확히 답할 수 있는, 지연이 가장 낮은 정상 노드를 뜻합니다. 그 답은 부하와 상태가 변함에 따라 초 단위로 바뀌며, 이것이 우리가 한 번 결정해서 재사용하는 대신 요청마다 다시 계산하는 이유입니다.

그 중 리전 선택 부분은 이제 업계 표준입니다. Singapore에서 온 요청과 Frankfurt에서 온 요청은 어떤 주요 프로바이더에서든 서로 다른 지점으로 진입하며, 이를 직접 설정하게 하는 프로바이더는 없습니다. 우리가 추가하는 것은 두 번째 결정입니다. 연결 단위가 아니라 요청 단위로 내려지는 결정으로, 요청이 도달한 리전 안에서 어떤 노드가 정상이고, 최신 상태이며, 이 특정 호출에 적합한지를 판단하는 것입니다.

<ImageBlock
  src="https://media.alchemy.com/blog/cortex-router-diagram.png"
  alt="Cortex 라우터 아키텍처: 요청은 가장 가까운 엣지 리전으로 들어오고, 컨트롤 플레인이 정상 서빙 스택을 선택하며, 플릿 앞단의 게이트웨이가 노드를 선택한다"
  width={3840}
  height={2160}
/>

## 요청은 어떻게 올바른 리전에 도달하는가?

Geo 기반 DNS는 엔드포인트를 가장 가까운 엣지 리전으로 해석하므로, 요청은 한 곳으로 모든 트래픽이 몰리는 대신 발신지에서 가까운 지점으로 진입합니다. 이는 라우터가 개별 노드를 살펴보기도 전에 일어나는데, 정문까지의 거리는 절대 만회할 수 없는 순수한 왕복 시간이기 때문입니다. 연결 설정과 TLS 협상도 스택 깊은 곳이 아니라 이 가장 가까운 지점에서 일어납니다.

그 정문이 바로 우리 자체의 [Alchemy Edge Proxy](https://www.alchemy.com/blog/alchemy-edge-proxy)로, 서드파티 CDN 대신 우리가 직접 운영하는 베어메탈 인그레스 레이어입니다. 이를 도입한 것은 이번 재구축에서 지연 시간 개선 폭이 가장 컸던 작업 중 하나였습니다. Asia-Pacific의 P99는 150ms에서 20ms로 떨어졌고, 전체 네트워크의 P95는 약 200ms에서 약 100ms로 대략 절반이 되었습니다. 이 수치들은 현재 값이 아니라 그 마이그레이션 전후를 비교한 것이며, P95와 P99는 가장 느린 5%와 1%의 요청을 뜻하는데, 사용자가 실제로 체감하는 부분이 바로 이 구간입니다. 엣지는 [예측적 스케일링부터 플릿 자동화까지](https://www.alchemy.com/blog/how-we-built-low-latency-rpc-infrastructure) 이어지는 더 넓은 지연 시간 개선 작업의 한 레이어입니다.

## 리전 안에서 노드는 어떻게 선택하는가?

여기에는 서로 다른 역할을 하는 두 개의 레이어가 있습니다. 엣지에서는 컨트롤 플레인이 요청된 네트워크를 지원하는 서빙 스택이 어느 것인지, 그중 정상 상태인 것이 어느 것인지를 보고 가장 가까운 곳으로 요청을 보냅니다. 하지만 노드를 고르는 일은 한 단계 더 깊은 곳, 즉 플릿 앞단의 게이트웨이에서 일어납니다. 그 게이트웨이가 경로상에서 개별 머신에 대해 무언가를 아는 첫 번째 지점입니다.

노드를 잘 고르려면 가까운 것을 고르는 것 이상이 필요하므로, 전달되기 전에 몇 가지가 후보 목록을 좁힙니다.

- **실시간 추적에서 나오는 상태(health).** 노드 추적 시스템이 지속적으로 상태 점검을 수행하며, 이를 통과하지 못한 노드는 후보에서 제외됩니다. 이는 상태가 나빠진 백엔드가 사용자에 의해 발견되는 대신 애초에 선택되지 않도록 막아줍니다.
- **현재 상태에 대한 일치 여부.** 노드들이 모두 같은 블록에 있는 것은 아니므로, 가장 빠른 노드에 단순히 읽기를 넘기면 체인이 이미 지나간 상태를 반환할 수 있습니다. 일관성 레이어는 [어떤 노드가 처리하든 동일한 정식(canonical) 체인 뷰](https://www.alchemy.com/blog/from-one-node-to-cortex)를 유지하며, 버전이 매겨진 업데이트 덕분에 페일오버가 진행 중일 때도 오래된(stale) 읽기를 받지 않습니다.
- **지리적 위치뿐 아니라 관측된 지연 시간.** 후보들은 최근 측정된 지연 시간의 지수가중이동평균(EWMA)으로 점수가 매겨지며, 이는 로드 밸런서들이 오랫동안 사용해온 방식과 같습니다. 오래된 샘플은 평균에서 점차 빠지므로, 몇 분 전부터 느려지기 시작한 노드는 누가 경고를 울리지 않아도 순위에서 자연스럽게 밀려납니다.
- **워크로드 형태.** 노드 클라이언트마다 동기화 동작과 잘 처리하는 메서드가 다르고, 아카이브 노드와 풀 노드가 보유한 데이터도 다르므로, 요청의 메서드와 파라미터가 후보 풀을 더 좁힙니다. 무거운 과거 데이터 조회와 단순한 잔액 조회는 같은 노드에 갈 것이 아닙니다.

따라서 "가장 낮은 지연 시간"은 어딘가에서 켜는 설정값이 아닙니다. 호출이 어디서 들어왔는지, 무엇을 요청하는지, 그리고 그 순간 어떤 머신이 빠르고 정상인지에 따라 매 호출마다 다시 계산됩니다.

## 선택된 노드가 정상이 아닐 때는 무슨 일이 일어나는가?

페일오버는 옆에 덧붙인 알람이 아니라 라우팅 결정 자체의 일부입니다. 노드가 다운되면 [Cortex는 자동으로 트래픽을 정상 노드로 재라우팅](https://www.alchemy.com/blog/from-one-node-to-cortex)합니다. 더 흥미로운 경우는 완전히 실패하지는 않았지만 혼잡하거나, 지연되거나, 알려진 버그가 있는 클라이언트 버전을 실행 중인 노드인데, 동일한 컨텍스트 기반 라우팅이 이런 노드들도 피해갑니다. 애플리케이션은 오류를 보지 않으며, 여러분이 작성해야 할 재시도 로직도 없습니다.

한 단계 위에서도 마찬가지입니다. 리전 전체가 상태가 나빠지면 요청은 보조 리전으로 라우팅되며, 그 뒤에는 추가적인 폴백이 있습니다. 실시간 글로벌 복제는 이런 전환 과정에서도 모든 리전을 일관되게 유지하므로, 더 먼 리전으로 가게 되어도 더 오래된 데이터를 읽는 것을 의미하지 않습니다.

Shuffle sharding과 중복 노드 풀이 이 모든 것의 기반에 있으며, 문제가 플릿 전체로 번지지 않고 격리되고 억제되도록 합니다. 라우팅 레이어는 상태가 나빠진 노드를 피해야 할 경로로 취급하며, 이는 [Solana gRPC의 무중단 스트리밍](https://www.alchemy.com/blog/zero-downtime-zero-gaps-solana-grpc-streaming)과 [암호화폐 역사상 최대 규모의 청산 이벤트](https://www.alchemy.com/blog/best-uptime-biggest-liquidation-event-in-crypto) 동안에도 계속 가동된 플릿을 뒷받침한 것과 동일한 장애 허용성입니다.

## 엣지를 직접 소유하는 것이 왜 라우팅을 더 똑똑하게 만드는가?

RPC 트래픽은 대부분 동적입니다. `eth_call`이나 트랜잭션 제출은 정적 이미지처럼 캐시할 수 없으므로, 일반적인 CDN의 주된 기술인 사용자 근처에 캐시된 콘텐츠를 서빙하는 방식은 대부분 적용되지 않으며, 요청은 여전히 살아있는 노드에 도달해야 합니다. CDN을 빌리는 대신 엣지를 직접 소유하면 이런 특정한 트래픽 형태에 맞게 튜닝할 수 있고, 서드파티 레이어가 전혀 볼 수 없는 신호, 예를 들어 지금 이 순간 이 메서드와 체인에 대해 어떤 노드가 동기화되어 있고 정상이며 가장 빠른지 같은 신호를 라우팅에 활용할 수 있습니다.

또한 이는 그 레이어를 관계없는 트래픽과 공유하지 않는다는 뜻이기도 합니다. 공유 CDN에서는 여러분의 앱과 전혀 관계없는 장애가 여러분의 지연 시간 급증으로 나타날 수 있고, 그 수정은 다른 누군가의 일정에 달려 있습니다.

프로바이더들이 실제로 갈라지는 지점은 리전 아래 모든 부분입니다. 그곳이 바로 라우팅 레이어가 각 머신이 무엇을 하고 있는지 실제로 아는지, 아니면 추측하고 있는지가 갈리는 지점이기 때문입니다.

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Approach", dataType: "object" },
      {
        key: "2",
        width: 260,
        title: "How a request gets routed",
        dataType: "object",
      },
      {
        key: "3",
        width: 260,
        title: "What the routing layer knows",
        dataType: "object",
      },
    ],
    data: [
      {
        "1": {
          title: "<p>Brokered across third-party operators</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>A balancer scores independent operators and forwards each request to one of them</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Health and latency as the operators expose it, at endpoint level rather than node level</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title:
            "<p>Own fleet, geo-routed and then selected per request (Cortex)</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title:
            "<p>A single endpoint resolves to the nearest healthy serving stack for that network, and the gateway in front of the fleet picks the node</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Every node's health, whether it agrees with the current state of the chain, recent measured latency, and which client it runs</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
    ],
  }}
/>

우리가 이를 직접 운영하는 이유는 경로의 어떤 구간도 다른 누군가의 소유가 되지 않는 유일한 방법이기 때문입니다. 그에 대해 실질적인 엔지니어링 비용을 치르고 있으며, 그 대가로 느린 부분을 소유한 누군가에게 티켓을 넣는 대신 경로 전체를 직접 튜닝할 수 있습니다.

## Base 같은 체인에서는 이것이 어떤 의미를 갖는가?

Base는 좋은 스트레스 테스트 대상입니다. 체인 자체가 빠르기 때문입니다. [Flashblocks를 통해 200ms 단위의 점진적 블록 업데이트](https://docs.base.org/base-chain/flashblocks)를 내보내므로, 응답에 그보다 더 오래 걸리는 RPC 경로는 체인이 아니라 그 경로 자체가 병목이 됩니다. 어느 리전에서 온 Base 호출이든 가장 가까운 엣지로 진입하고, 체인과 최신 상태를 유지하는 정상 Base 노드에 매칭되며, 그 노드 상태가 나빠지면 리전 내에서 재라우팅됩니다. 체인이 200ms마다 새로운 상태를 미리 보여주는 상황에서는, 네트워크 오버헤드 100밀리초를 줄이는 일이 덜 중요해지는 것이 아니라 더 중요해집니다.

일관성이 더 어려운 보증이며, 우리를 평가할 때 봐야 할 부분이기도 합니다. [Polymarket](https://www.alchemy.com/case-studies/polymarket)이 그 스트레스 사례입니다. 2024 US 대선 기간 동안 그들은 동시 사용자 125,000명 이상과 33억 달러 규모의 베팅을 처리했고, p99 지연 시간을 기준으로 요청이 동적으로 재라우팅되어 성능을 유지했습니다. 그들의 핵심 인입(ingestion) 워크플로우는 별도로 약 250ms에서 약 100ms로 2.5배 빨라졌습니다. 어느 한가한 오후에 한 리전에서 측정한 중앙값은 민팅이나 청산 캐스케이드 동안 여러분의 사용자가 실제로 경험하는 것에 대해 거의 아무것도 말해주지 않습니다. 저희 말을 그대로 믿기보다 직접 확인하고 싶으시다면, [벤치마크 방법론](https://www.alchemy.com/blog/how-we-benchmark-rpc-performance)은 지연 시간과 함께 성공률, 실패한 요청도 측정하며, [프로바이더 벤치마크](https://www.alchemy.com/benchmarks)는 공개되어 있습니다.

## 동일한 라우팅 경로 위에서 빌드하기

Alchemy 위의 모든 앱은 이미 아무 설정 없이 이 엔진을 통해 라우팅됩니다. [무료 RPC 엔드포인트](https://www.alchemy.com/rpc-api)를 만들면 여러분의 읽기와 쓰기는 여기서 설명한 것과 동일한 요청 단위 경로를 거치게 됩니다. 계약도, 대기자 명단도, 엔드포인트 변경도 필요 없습니다. [Data API](https://www.alchemy.com/docs/data) 호출도 마찬가지로 이 위에서 실행됩니다.

노드를 특정 리전에 고정하거나, 싱글 테넌트 격리가 필요하거나, 경로상에 커스텀 바이너리가 필요하다면, [Alchemy Dedicated Clusters](https://www.alchemy.com/dedicated-clusters)는 싱글 테넌트 하드웨어 위에서 동일한 라우팅을 실행하며, 트래픽이 클러스터 용량을 넘어설 경우 공유 플릿으로 자동 페일오버하도록 선택할 수도 있습니다. 어느 쪽이든, 앱 뒤에 있는 요청 처리는 더 이상 신경 쓰지 않아도 되는 부분이 됩니다.

## 자주 묻는 질문

### 어떤 RPC 프로바이더가 글로벌 리전 전반에서 가장 낮은 지연 시간을 제공하는가?

Alchemy의 EVM 체인 전반 평균 응답 시간은 [지속적으로 업데이트되는 벤치마크](https://www.alchemy.com/benchmarks) 기준으로 15ms 미만이며, 이는 이미 열려 있는 연결에서의 웜 요청-응답 시간으로 측정됩니다. 그 페이지는 몇 분마다 재계산되므로, 현재 프로바이더 순위는 그 페이지에서 확인하시기 바랍니다. 가동 시간(uptime)은 [99.995%](https://www.alchemy.com/blog/the-tech-behind-cortex)입니다. 진지한 프로바이더라면 모두 여러분을 가까운 리전으로 라우팅합니다. Cortex는 그 리전 안에서 한 걸음 더 나아가, 상태와 체인의 현재 상태와의 일치 여부가 확인된 노드에 각 요청을 매칭합니다.

### 어떤 RPC 프로바이더가 가장 낮은 지연 시간으로 Base RPC를 지원하는가?

Alchemy의 Base RPC는 가장 가까운 엣지 리전으로 진입한 뒤, 체인과 최신 상태를 유지하는 정상 Base 노드에 매칭됩니다. 이는 Flashblocks가 200ms마다 블록 업데이트를 내보내는 Base에서 더 느린 체인보다 더 중요합니다. 살짝이라도 뒤처진 노드는 이미 바뀐 상태를 반환할 수 있기 때문입니다.

### Cortex는 어떤 노드가 RPC 요청을 처리할지 어떻게 선택하는가?

두 개의 레이어가 이 작업을 나누어 맡습니다. 엣지 컨트롤 플레인은 요청된 네트워크를 지원하는 가장 가까운 정상 서빙 스택을 고르고, 그 다음 플릿 앞단의 게이트웨이가 노드를 고르는데, 상태, 체인의 현재 상태와의 일치 여부, 최근 관측된 지연 시간, 호출되는 메서드를 기준으로 후보를 좁힙니다.

### 요청 단위 라우팅이 지연 시간을 추가하는가?

라우팅은 헤드라인 수치가 아니라 응답 시간 예산의 작은 일부일 뿐입니다. 15ms 미만이라는 수치는 EVM 체인 전반의 웜 요청-응답 시간이며, 라우팅 결정 자체의 비용이 아니고, 모든 체인과 제품을 아우르는 플랫폼 전체의 50ms 미만 평균과도 다른 측정치입니다. 리전 선택은 사용자에게 가까운 엣지에서 일어나고, 노드 선택은 플릿 앞단의 게이트웨이라는 더 깊은 곳에서 일어납니다.

### RPC 노드가 실패하면 무슨 일이 일어나는가?

페일오버는 여러분이 직접 만드는 재시도 로직이 아니라 라우팅 결정 자체의 일부입니다. 노드가 다운되면 Cortex는 자동으로 트래픽을 정상 노드로 재라우팅하며, 컨텍스트 기반 라우팅은 혼잡하거나, 지연되거나, 버그 있는 클라이언트를 실행 중인 노드도 함께 피해갑니다. 리전 전체가 상태가 나빠지면 요청은 보조 리전으로 이동하고, 실시간 복제가 데이터 일관성을 유지합니다.
