---
title: "다운타임 없이 RPC 제공업체를 마이그레이션하는 방법"
description: "RPC 제공업체 마이그레이션은 재구축이 아니라 엔드포인트 교체입니다. 드롭인 호환성이 다루는 범위, 먼저 점검해야 할 사항, 다운타임 없이 전환하는 방법을 다룹니다."
---

# 다운타임 없이 RPC 제공업체를 마이그레이션하는 방법

<ImageBlock
  src="https://media.alchemy.com/blog/migrate-between-rpc-providers-zero-downtime-16x9-20260821.png"
  alt="다운타임 없이 RPC 제공업체 간 마이그레이션"
  width={1920}
  height={1080}
  priority
/>

팀들이 RPC 제공자 전환을 미루는 이유는 재구축처럼 느껴지기 때문이다. 하지만 대부분의 경우 몇 시간짜리 설정 작업에 불과하다. 모든 주요 제공자는 동일한 JSON-RPC 표준을 따르므로, 오늘 앱이 보내는 요청은 내일 새 제공자가 받는 요청과 같다. RPC 제공자 마이그레이션은 재작성이 아니라 엔드포인트 교체다.

남는 작업은 교체 자체가 아니라 그 주변에 있다. 엔드포인트 URL이 숨어 있는 모든 위치를 찾는 일, 이전되지 않는 소수의 제공자 전용 호출을 매핑하는 일, 그리고 사용자가 눈치채지 못하는 순서로 트래픽을 전환하는 일이다.

## 드롭인 엔드포인트 호환성이란 무엇인가?

드롭인 엔드포인트 호환성이란 두 RPC 제공자가 표준 JSON-RPC 메서드에 대해 동일한 요청을 받아들이고 동일한 응답을 반환한다는 뜻이다. 애플리케이션은 호출하는 엔드포인트 URL을 바꾸는 것만으로 제공자를 전환한다. 메서드 이름, 파라미터, 응답 형태는 그대로 유지되므로 표준 표면에서는 코드 변경이 전혀 필요하지 않다.

이 호환성은 제공자 간의 어떤 합의가 아니라 프로토콜 자체에서 나온다. `eth_call`, `eth_getLogs`, `eth_sendRawTransaction`를 비롯해 `eth_*`, `net_*`, `web3_*` 계열의 나머지 메서드들은 [Ethereum JSON-RPC 사양](https://ethereum.org/en/developers/docs/apis/json-rpc/)에 정의되어 있고, 진지한 제공자라면 모두 이 사양대로 구현한다. 스트리밍도 마찬가지다. WebSocket을 통한 `eth_subscribe`은 [우리의 구독 엔드포인트](https://www.alchemy.com/docs/reference/subscription-api)에서도 다른 주요 제공자와 동일하게 newHeads, logs, newPendingTransactions 스트림을 전달한다.

우리의 엔드포인트 형태와 대부분의 다른 제공자가 쓰는 패턴을 나란히 두면 다음과 같다:

<CodeSnippet
  language="text"
  code={`Alchemy:         https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
Other providers: https://your-endpoint-name.provider.example/YOUR_AUTH_TOKEN/`}
/>

둘 다 경로에 비밀 값이 들어 있는 URL이다. 엔드포인트가 환경 변수에 있다면, 표준 트래픽을 마이그레이션하는 일은 그 변수 값을 바꾸는 것으로 끝난다. 이것이 바로 [백업 RPC 엔드포인트](https://www.alchemy.com/overviews/alternative-rpc-endpoint)를 설정해두라는 표준적인 안정성 권고가 동시에 마이그레이션 보험 역할도 하는 이유다. 가동 시간을 위해 추가하는 폴백 장치가 그대로 전환에 쓰이는 장치다.

표준 JSON-RPC 호출은 새 제공자에서도 변경 없이 동작한다. 작업이 필요한 곳은 앱이 제공자 전용 기능에 의존하는 지점뿐이며, 그런 지점을 찾는 것이 감사(audit)의 목적이다.

## 마이그레이션 전에 무엇을 점검해야 하는가?

제공자 마이그레이션에서 발생하는 대부분의 놀라운 문제는 전환 이후에 발견되지만, 그 모든 문제는 사전에 찾아낼 수 있었던 것들이다. 일반적인 코드베이스라면 감사에는 한두 시간이면 충분하다.

**모든 엔드포인트 참조를 찾는다.** 엔드포인트 URL은 아무도 기억하지 못하는 곳까지 쌓인다. 환경 파일, Hardhat 및 Foundry 설정, Docker 이미지, CI 파이프라인, 프론트엔드 빌드에서 현재 제공자의 도메인과 하드코딩된 URL을 검색한다. 놓치는 참조는 대개 몇 달째 아무도 열어보지 않은 cron 작업이나 CI 파이프라인에 있다.

**제공자 전용 접두사 메서드를 매핑한다.** 대부분의 제공자는 벤더 접두사가 붙은 편의 메서드를 제공하며(우리의 경우 `alchemy_`), 이런 메서드는 플랫폼 간에 이전되지 않는다. 토큰 조회는 [Data API](https://www.alchemy.com/docs/data)의 대응 메서드인 [alchemy_getTokenBalances](https://www.alchemy.com/docs/data/token-api/token-api-endpoints/alchemy-get-token-balances)로, 전송 기록은 [alchemy_getAssetTransfers](https://www.alchemy.com/docs/data/transfers-api/transfers-endpoints/alchemy-get-asset-transfers)로 옮겨간다. 대응되는 메서드는 존재하지만 응답 형태가 다르므로, 단순 찾아바꾸기가 아니라 각각을 작은 코드 변경으로 취급해야 한다.

**인증 방식을 확인한다.** URL 경로에 있는 키는 그대로 이전된다. 대신 `x-token` 헤더나 JWT로 인증한다면, 이런 제어는 새 제공자에서 다시 만들어야 한다. 우리 쪽에서는 도메인 및 IP 허용 목록이 [Alchemy 대시보드](https://dashboard.alchemy.com)에 있으며 설정에 몇 분이면 된다.

**새 계량 모델에 맞춰 트래픽 비용을 다시 산정한다.** 코드가 아니라 청구서에 영향을 주는 감사 항목이다. 많은 제공자가 초당 요청 수 예산을 정액으로 계량한다. 우리는 [컴퓨트 유닛](https://www.alchemy.com/docs/reference/compute-unit-costs)으로 계량하며, `eth_blockNumber` 같은 가벼운 호출은 `eth_getLogs` 같은 무거운 호출보다 비용이 적게 들고, [처리량](https://www.alchemy.com/docs/reference/throughput)은 고정된 요청 수가 아니라 이동 윈도 기준의 컴퓨트 유닛 비율이다. 이 영향은 양방향으로 작용한다. 로그 위주의 인덱싱 워크로드는 요청 수가 시사하는 것보다 더 빠르게 예산을 소모하는 반면, 가벼운 폴링 워크로드는 더 적게 소모한다. 대부분의 팀은 월간 총량에서 추측하는 대신 전환 전에 가장 트래픽이 많은 시간대의 실제 트래픽을 [우리 가격표](https://www.alchemy.com/pricing)에 대입해본다.

**trace 및 debug 메서드의 플랜 제한을 확인한다.** `debug_`과 `trace_` 메서드는 대부분의 제공자에서 플랜별로 제한된다. Alchemy에서는 [pay-as-you-go 및 엔터프라이즈 플랜](https://www.alchemy.com/pricing)에서 사용할 수 있지만 무료 티어에서는 사용할 수 없으므로, 무료 엔드포인트로 개념 증명(PoC)을 돌린다면 다른 기능은 다 동작해도 trace 호출은 실패할 것으로 예상해야 한다.

이 항목들 중 어느 것도 마이그레이션을 막지는 않지만, 합쳐서 그 범위를 정한다. 대부분의 앱에서 감사는 짧은 환경 변수 목록, 한두 개의 메서드 매핑, 가격 추정치로 끝난다.

## 다운타임 없이 전환하려면 어떻게 해야 하는가?

무중단 전환 패턴은 팀들이 데이터베이스 마이그레이션에 쓰는 것과 같다. 기존 것과 새 것을 병렬로 실행하고, 트래픽을 단계적으로 옮기며, 새 경로가 신뢰를 얻을 때까지 기존 경로를 따뜻하게 유지한다.

클라이언트 라이브러리는 병렬 실행 단계를 거의 공짜로 만들어준다. viem의 [폴백 트랜스포트](https://viem.sh/docs/clients/transports/fallback)는 순서가 정해진 엔드포인트 목록을 받아, 하나가 실패하면 목록의 다음으로 넘어간다:

<CodeSnippet
  language="typescript"
  code={`import { createPublicClient, fallback, http } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
  chain: mainnet,
  transport: fallback([
    http("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"),
    http("https://your-endpoint-name.provider.example/YOUR_AUTH_TOKEN/"),
  ]),
});`}
/>

새 제공자를 먼저, 기존 제공자를 두 번째로 두면, 모든 요청은 새 엔드포인트를 시도하고 실패하면 이미 작동하던 엔드포인트로 넘어간다. 전환 중 최악의 경우가 바로 오늘의 설정이 되는 셈이다. ethers.js도 [FallbackProvider](https://docs.ethers.org/v6/api/providers/fallback-provider/)에서 같은 패턴을 제공하며, 여러 제공자에 질의해 결과가 일치하면 받아들이는 쿼럼 옵션도 있어 클라이언트 내부에서 제공자 간 일치 검증까지 할 수 있다.

트래픽을 옮기는 순서는 얼마나 빨리 옮기느냐보다 더 중요하며, 원칙은 읽기를 먼저, 쓰기를 마지막에 하는 것이다. 읽기는 상태가 없고 검증하기 쉬우므로, 읽기 트래픽을 일찍 새 엔드포인트로 돌려 응답을 비교한다. 가장 부하가 큰 쿼리들, 즉 컨트랙트에서 가장 많이 쓰이는 블록 범위에 대한 `eth_getLogs`과 핵심 컨트랙트에 대한 `eth_call`를 양쪽 제공자에서 실행하고 응답을 비교한다. 트랜잭션 제출은 읽기가 깨끗이 돌아간 뒤 마지막에 옮긴다. 읽기 실패는 재시도지만 쓰기 실패는 지원 티켓이기 때문이다.

WebSocket 구독에는 한 단계가 더 필요하다. 구독은 그것을 만든 연결에 묶여 있어 페일오버되지 않는다. 연결이 끊기면 다시 만들어야 한다. 새 엔드포인트에서 재구독하고, 재연결 사이에 지나간 블록 범위에 대해 `eth_getLogs` 쿼리로 공백을 메워 이벤트가 누락되지 않도록 계획한다. 우리의 [WebSocket 모범 사례](https://www.alchemy.com/docs/reference/best-practices-for-using-websockets-in-web3)도 구독 범위를 좁게 유지하라고 권장하는데, 이렇게 하면 재구독과 백필 모두 비용이 줄어든다.

병렬 실행 중에는 두 가지를 대시보드에서 지켜볼 필요가 있다. 첫째는 블록 높이 지연이다. 건강한 두 제공자라도 특정 순간에는 체인 팁이 약간 다를 수 있으므로, 순간적인 차이가 아니라 새 엔드포인트가 기존 것보다 지속적으로 뒤처지는 경우에 알림을 설정한다. 둘째는 에러 형태다. 속도 제한 응답은 제공자마다 다르다. HTTP에서는 우리의 경우 [Retry-After 헤더](https://www.alchemy.com/docs/reference/throughput)와 함께 429를 반환하고, WebSocket에서는 같은 제한이 헤더 없이 JSON-RPC 429 에러로 나타난다. 프로덕션 트래픽을 맡기기 전에, 사용하는 두 트랜스포트 모두에서 새 엔드포인트에 대해 재시도 로직을 테스트해봐야 한다.

대부분의 팀은 병렬 단계에 하루 이틀 정도 프로덕션 트래픽을 흘려본 뒤 새 엔드포인트를 기본값으로 삼는다. 기존 엔드포인트는 청구 기간이 끝날 때까지 폴백으로 설정해둔다. 롤백은 그동안 내내 설정 변경 하나로 가능한 상태로 남으며, 이것이 실제로 무중단이 의미하는 바다. 문제는 여전히 일어날 수 있다. 다만 사용자에게까지 도달할 필요가 없을 뿐이다.

## 새 제공자가 잘 버티고 있는지 어떻게 알 수 있는가?

병렬 실행 단계에서 진행한 비교가 그대로 기준선이 된다. 전환 후에도 전환 전에 비교했던 수치들, 즉 성공률, p95 지연 시간, 블록 최신성을 계속 지켜본다. 마이그레이션이 그만한 가치가 있었다면 적어도 하나는 유리한 방향으로 움직여야 한다.

지연 시간에 대한 주장도 그냥 믿을 필요는 없다. 우리의 [실시간 RPC 벤치마크](https://www.alchemy.com/benchmarks)는 여러 체인과 지역에서 우리를 다른 주요 제공자들과 비교하며, [그 방법론](https://www.alchemy.com/blog/how-we-benchmark-rpc-performance)도 공개되어 있어 전환을 결정하기 전에 본인의 지역에서 직접 수치를 재현해볼 수 있다. 그 수치가 부하 상태에서도 유지되는 이유를 더 깊이 알고 싶다면, 우리의 [엣지 프록시 재구축](https://www.alchemy.com/blog/alchemy-edge-proxy) 글에서 모든 요청이 처음 거치는 라우팅 계층을 다룬다.

아직 제공자 검증이 아니라 제공자 선택을 고민 중이라면, 우리의 [노드 제공자 선택 가이드](https://www.alchemy.com/overviews/how-to-choose-a-blockchain-node-provider)와 [엔터프라이즈 RPC 평가 가이드](https://www.alchemy.com/blog/blockchain-rpc-infrastructure-evaluation-guide-for-enterprises)가 마이그레이션 질문이 나오기 전에 물어봐야 할 질문들을 다룬다.

마이그레이션이 끝난 뒤에도 병렬 실행 단계의 점검은 계속 살려둔다. 전환을 검증했던 응답 비교와 지연 시간 대시보드는 몇 달 뒤 제공자의 성능 저하나 오래된 데이터를 알려줄 것이며, 이미 다 만들어져 있는 것들이다.

## RPC 제공자를 전환할 준비가 되었는가?

어떤 제공자를 떠나든, 위의 내용은 그대로 적용된다.

[Alchemy 대시보드](https://dashboard.alchemy.com)에서 무료 엔드포인트를 만들고 오늘 스테이징 환경을 거기에 연결해보라. 계약도, 영업 통화도, 최소 약정도 없다. 무료 티어에는 [월 3,000만 컴퓨트 유닛](https://www.alchemy.com/pricing)이 포함되어 있어 실제 프로덕션 트래픽으로 병렬 단계 비교 전체를 실행하기에 충분하며, 같은 엔드포인트 교체 방식이 [우리가 지원하는 100개 이상의 체인](https://www.alchemy.com/rpc)에서도 동일하게 작동한다.
