Solana 블록체인은 데이터를 순차적이고 추가만 가능한 원장에 저장합니다. 이는 데이터 무결성과 거래 처리량에 좋지만, 역사 데이터 쿼리에 있어 매우 비효율적이고 지나치게 느립니다.
복잡한 작업은 종종 여러 소스에서 데이터를 필터링, 집계 또는 결합하는 것을 포함합니다. 이러한 경우, Solana에 직접 쿼리를 실행하는 것은 대부분의 실제 응용 프로그램에 비현실적입니다.
이를 해결하기 위해 대부분의 기업은 Solana의 역사 데이터에 대한 개인 색인을 구축합니다.
이 가이드는 역사 데이터를 getTransactionsForAddress 및 기타 아카이브 RPC 방법을 사용하여 백필링하고, 데이터베이스를 선택하며, 실시간 스트리밍으로 색인을 최신 상태로 유지하는 전체 수명 주기를 다룹니다.
사용 시기
다음과 같을 때 색인을 구축합니다:
- 제품이 빠르면서 필터링된 쿼리가 필요하지만 직접 RPC 호출은 너무 느린 경우 (예: 지갑의 토큰 계정 및 잔액, 거래쌍의 전체 이력)
- 온체인 데이터를 필터링, 집계, 결합하거나 오프체인 데이터와 결합해야 하는 경우 (CEX 가격, KYC, 라벨)
- 거래 손익 계산, 보유자 분석, NFT 판매 이력 등 미리 처리된 쿼리 가능 데이터를 필요로 하는 경우
- 많은 사용자를 지원해야 하고 체인에 대한 요청 대기 시간을 감당할 수 없는 경우
표준 지갑 또는 자산 데이터만 필요한 경우, 자체 색인을 실행하는 것보다 관리 API가 더 간단할 수 있습니다. 아래 보완 옵션을 참조하세요.
Solana 데이터 색인이란?
색인은 Solana 블록체인에서 데이터를 쿼리하여 요청 시 블록체인에 직접 쿼리할 필요 없이 고객 요청을 수월하게 처리할 수 있는 백엔드 데이터베이스(예: PostgreSQL, ClickHouse)에 저장하는 과정입니다.
인덱서는 일반적으로 네 가지 작업을 수행합니다:
- 역사 데이터 백필링: 아카이브 RPC 방법을 사용하여 모든 역사 데이터를 쿼리
- 새 데이터 스트리밍: 네트워크에 의해 확인된 새로운 블록 처리
- 데이터 파싱 및 변환: 확인된 블록에서 관련 데이터 추출 (예: 거래, 상태 변경 등)
- 데이터를 데이터베이스에 조직화: 새로운 데이터로 색인 업데이트
대부분의 기업이 Solana 색인을 구축하는 이유는?
기업이 Solana 색인을 구축하는 이유는 그들의 비즈니스가 기본 RPC가 제공하지 않는 특정 목적의 블록체인 데이터에 빠르고 실시간으로 접근할 수 있도록 하는 데 의존하기 때문입니다 (예: NFT 판매 이력).
또한 기업은 맞춤색인을 활용하여 오프체인 데이터(예: 중앙화 거래소 가격, KYC 정보 등)를 온체인 데이터와 결합합니다.
지갑 예시
예를 들어, Solana 지갑이 사용자의 토큰 계정과 잔액을 빠르게 반환해야 하는 경우, getTokenAccountsByOwner 및 getTokenAccountBalance를 사용하여 Solana에 직접 쿼리하는 것이 너무 느려서 제품이 사용 불가능할 수 있습니다. 대신, 지갑은 일반적으로 고객 주소, 토큰 및 계정 잔액에 대한 자체 색인을 유지합니다.
거래 예시
비슷하게, 암호화 거래 회사는 특정 거래쌍 (예: SOL-USDC) 또는 특정 시장에서 발생하는 모든 거래 활동을 기록하여 거래 알고리즘을 백테스트하고 싶어할 수 있습니다.
이 데이터를 블록체인에 직접 쿼리하는 것은 실제 거래 분석에 너무 느릴 것입니다. 대신, 양적 거래자는 SOL-USDC 시장에 대한 색인을 구축하고, LaserStream과 같은 실시간 스트리밍 제품을 사용하여 최신 거래로 업데이트할 수 있습니다.
필터링 예시
사용자가 프런트엔드 애플리케이션에서 특정 기준별로 거래를 필터링하려고 한다고 상상해보세요 (예: 토큰 유형, 전송 금액, 날짜, 지갑 주소 등).
인덱서가 없으면, 앱은 필터 조건과 일치하는 수백만 개의 거래를 수백만 개의 블록에서 스캔해야 합니다.
이 과정은 현대 제품 사용자 경험에는 너무 느립니다.
PnL 예시
거래자의 손익(PnL)을 계산하려면 다음을 수행해야 합니다:
- 주어진 기간 동안 그들의 지갑과 관련된 모든 거래 찾기
- 스왑 거래를 필터링하고 구매 또는 판매로 레이블 지정
- 사용자가 각 스왑 동안 지불한 수수료 확인
- 각 거래 시점의 각 토큰에 대한 역사적 가격 데이터 얻기
- 각 거래의 PnL을 집계하여 거래자의 총 PnL 계산
이를 모두 실시간으로 계산하는 것은 비현실적이며, 더 빠르고 확장 가능한 솔루션이 필요합니다.
색인을 사용하면 모든 정보가 이미 처리되어 쿼리가 가능한 데이터베이스에 저장됩니다. 이제 거래자의 PnL을 계산하는 것이 즉시 제공되는 단일 API 호출로 변환됩니다.
Solana 색인을 백필링하고 최신 상태로 유지하는 세 가지 접근 방식을 살펴보겠습니다.
1단계: 역사 데이터 얻기
Solana 색인을 구축하기 위한 첫 번째 단계는 필요한 모든 역사 데이터를 얻는 것입니다.
이를 수행하는 주요 방법은 세 가지입니다:
- getTransactionsForAddress (권장)
- getSignaturesForAddress 및 getTransaction
- getBlock
방법 1: getTransactionsForAddress (권장)
getTransactionsForAddress RPC 메서드를 사용하면 블록체인 데이터의 임의 세그먼트에 대한 전체 거래 세부정보를 가져올 수 있습니다. 강력한 필터링 기능 덕분에 색인에 필요하지 않은 데이터를 검색하는 데 시간을 낭비하지 않으며, 역순 검색 기능 덕분에 연대순으로 거래를 얻을 수 있습니다.
이 방법을 사용하는 단계
- 필요한 데이터의 기간을 결정하고 필터를 설정합니다.
- 모든 거래 세부정보를 얻기 위해
transactionDetails를 full로 설정합니다.
- 필요하다면 관련 토큰 계정 거래를 포함할 수 있도록
tokenAccounts 필터를 구성합니다.
paginationToken를 사용하여 결과를 페이지 매기기 합니다.
- 각 반복에서 필요한 데이터를 추출하고 데이터베이스에 저장합니다.
getTransactionsForAddress 사용의 이점
gTFA 엔드포인트를 사용하는 주요 장점은 속도와 단순성입니다. 슬롯 및 시간 기반 필터, 토큰 계정 지원, 역순 검색 및 페이지 매김 기능을 통해 Solana의 역사에서 필요로 하는 모든 데이터를 복잡한 반복 또는 재시도 로직 없이 단일 호출로 얻을 수 있습니다. getSignaturesForAddress와 달리 소유한 주소에 연결된 토큰 계정의 거래도 포함할 수 있습니다.
색인이 주로 토큰 및 네이티브 SOL 이동(지불, 원장, 잔액 조정)에 관련된 경우 getTransfersByAddress 메서드를 사용하여 완전한 거래 대신 파싱된, 조정 가능한 전송 행을 반환함으로써 파싱 단계를 절약할 수 있습니다.
방법 2: getSignaturesForAddress 및 getTransaction
gTFA 출시 이전에는 역사 데이터를 쿼리하기 위한 표준 접근 방식은 getSignaturesForAddress(최신에서 가장 오래된 것으로) 서명을 반복적으로 반복하고 그런 다음 getTransaction를 호출하여 전체 거래 세부정보를 추출하는 것이었습니다.
이 방법을 사용하는 단계
이 방법을 사용하는 기본 단계는 다음과 같습니다:
getSignaturesForAddress 호출
- 이 호출의 마지막으로 받은 거래 서명을 저장
- 다음
getSignaturesForAddress 호출을 위한 before 매개변수를 이 서명으로 설정
- 필요할 때까지 이 과정을 반복
- 이렇게 검색된 각 거래 서명에 대해
getTransaction를 호출하여 전체 거래 세부정보를 가져옴
- 관련 데이터를 데이터베이스에 삽입
이 방법의 단점
안타깝게도 이 방법을 사용하려면 다음이 필요합니다:
- 최신 거래에서 시작하여 역방향으로 작업
- 각 거래마다 추가 RPC 호출
- 동시 처리 관리를 위한 스레드 안전 큐 구축
- 누락된 데이터를 방지하고 속도 제한을 막기 위한 재시도와 백오프 로직 구축
- 소유한 주소에 연결된 토큰 계정의 거래는 포함되지 않음
이 방법은 작동하지만 더 복잡하고 유연성이 떨어지며 크레딧이 훨씬 많이 소모됩니다. 토큰 계정을 포함한 전체 지갑 이력을 위해 getTransactionsForAddress를 사용하는 것이 좋습니다.
방법 3: getBlock 사용
getBlock 메서드는 대상 블록의 거래 중 높은 비율이 분석에 관련이 있는 경우 가장 효과적입니다. 예를 들어 DFlow의 Aggregator, Pump.fun 프로그램, Solana의 토큰 프로그램과 같은 자주 사용되는 Solana 프로그램의 거래를 색인화 할 때 유용합니다.
이 방법을 사용하는 단계
getBlock를 사용하여 역사 데이터를 쿼리하는 기본 프로세스는 다음과 같습니다:
- 쿼리할 시간 범위 결정
- 이 시간 범위를 슬롯 번호로 변환
- 해당 블록을 순차적으로 가져오기 (순방향 또는 역방향)
- 각 블록의 색인과 관련된 거래 필터링
- 관련 정보를 색인에 저장
대부분의 사용 사례에서는 이 방법이 본질적으로 낭비가 많습니다. 일반적으로 한 블록에서 분석과 관련이 있는 거래는 소수에 불과하기 때문입니다.
자주 사용되는 프로그램의 거래를 조사하거나 주소 기반 필터링으로 목표 데이터를 캡처할 수 없을 때만 이 방법을 사용하십시오.
2단계: Solana 데이터를 데이터베이스와 동기화
역사 데이터를 가져온 후, 이를 변환하여 데이터베이스에 효율적으로 저장해야 합니다.
저장소 선택은 특정 사용 사례에 맞춰져야 합니다 — 모든 솔루션에 적합한 옵션은 없습니다. 올바른 데이터베이스는 데이터세트 크기, 대기 시간 요구 사항, 쿼리 패턴 및 팀의 전문 지식에 따라 다릅니다.
옵션 1: SQL 데이터베이스
Solana 데이터를 PostgreSQL과 같은 관계형 데이터베이스에 저장하는 것이 대부분의 사용 사례에 권장됩니다. SQL은 유연하고, 널리 사용되며 배우기 쉽습니다. 현대 관계형 데이터베이스는 1억 개 이상의 행을 초과하여 확장할 수 있으면서도 ACID 준수, 복잡한 조인 및 강력한 보조 색인의 이점을 제공합니다.
SQLite는 프로토타이핑, 로컬 개발 또는 단일 파일 데이터베이스로 무설정을 원하는 경우에 사용하십시오. 데이터세트가 몇 기가바이트 이하로 유지될 때 이상적입니다.
PostgreSQL은 데이터 복제, 여러 클라이언트에서의 동시 액세스, 전체 텍스트 검색 및 JSON 연산자와 같은 고급 기능이 필요한 프로덕션 응용 프로그램에 사용하십시오.
대부분의 프로덕션 수준 Solana 인덱서에는 PostgreSQL이 권장 선택입니다.
구현 예:
예를 들어, PostgreSQL 데이터베이스에 토큰 전송을 저장하는 방법을 보여줍니다.
먼저, 테이블을 생성합니다:
그런 다음, 자주 쿼리되는 열에 인덱스를 추가합니다:
자주 쿼리되는 데이터의 경우 부분 색인을 생성할 수도 있습니다.
고가치 전송만을 위한 인덱스를 만드는 방법은 다음과 같습니다:
데이터를 백필링할 때는 대량 삽입 및 준비된 문을 사용하여 최적의 쓰기 속도를 보장하십시오.
옵션 2: 컬럼형 데이터베이스
컬럼형 데이터베이스는 분석 쿼리, 집계 및 대용량 시계열 데이터에 최적화되어 있습니다. 여러 억 건의 거래를 색인화해야 하는 경우 ClickHouse 또는 Cassandra와 같은 컬럼형 데이터베이스가 가장 적합한 옵션입니다.
ClickHouse는 대규모 데이터 집합에 대한 실시간 분석 쿼리가 필요할 때 사용합니다 — 빠른 읽기, 집계 및 시계열 분석에 최적화되어 있습니다.
Cassandra는 극도로 높은 쓰기 처리량, 간편한 수평적 확장 및 높은 결함 허용성을 필요로 할 때 사용하십시오. 이는 Solana 데이터를 지속적으로 대량으로 수집하는 데 이상적입니다.
구현 예:
ClickHouse 데이터베이스에 토큰 전송을 저장하는 방법을 보여드립니다.
이를 위해 MergeTree 테이블 엔진을 사용하는 테이블을 만듭니다. 이는 높은 삽입 속도에 맞춰 설계되어 있으므로 색인화에 이상적입니다.
다음 명령을 사용합니다:
이 설정에서 (token_mint, date)가 기본 키와 정렬 키로 설정됩니다. ClickHouse는 정렬 키에 따라 디스크에 데이터를 순서대로 저장합니다. 이는 단일 토큰 민트에 대한 쿼리에 최적화되어 있으며, 날짜 범위로 응답을 좁히는 데 최적입니다.
다음은 예제 쿼리입니다:
거래 서명과 주소는 정밀한 바이트 수를 저장하는 FixedString(N) 데이터 형식을 사용하여 저장됩니다. ClickHouse는 데이터를 자동으로 압축하여 저장 비용을 10-20배 줄이고 쿼리 성능을 향상시킵니다.
쿼리 성능을 최적화하려면 일반적인 집계를 미리 계산하기 위해 물질화된 뷰를 사용하십시오.
예를 들어, 대시보드의 볼륨 관련 차트에 사용할 토큰의 일일 전송량을 미리 계산할 수 있습니다.
옵션 3: 데이터 레이크
데이터 레이크는 대량의 원시 및 처리된 블록체인 데이터를 장기적인 아카이브 및 분석 쿼리를 위해 저장하는 데 이상적입니다.
간단한 구현에는 Amazon Athena와 함께 Parquet 데이터 형식을 사용합니다.
Parquet는 효율적인 데이터 저장 및 검색을 위해 설계된 컬럼 지향 데이터 파일 형식입니다.
Amazon Athena는 Amazon S3에 저장된 데이터를 표준 SQL을 사용하여 분석할 수 있도록 하는 대화형 쿼리 서비스로, 인프라 구축이나 별도의 데이터베이스로 데이터를 로드할 필요가 없습니다.
데이터 레이크는 구조화되지 않은 대량의 데이터를 쿼리해야 하는 경우에만 권장됩니다. 대부분의 사용 사례에서는 SQL 데이터베이스(옵션 1)를 사용하는 것이 좋습니다.
구현 예:
토큰 전송의 아카이브를 만들고 이를 쿼리하고자 합니다.
먼저, S3에 저장해야 합니다: solana_index라는 버킷을 생성하고, 이 키 구조를 사용하여 토큰 전송 데이터를 시간별로 분할합니다:
각 일일 전송은 해당 날짜 폴더의 별도 Parquet 파일로 저장됩니다.
Solana에서 전송을 처리하면서, 이를 Parquet 형식으로 변환하고 해당 S3 객체에 쓰기합니다.
나중에 Athena에서 테이블을 생성하고 이를 버킷에 연결할 수 있습니다. 이를 통해 버킷 내 데이터를 직접 쿼리할 수 있습니다:
색인 프레임워크 사용
Carbon 및 유사한 프레임워크를 사용하여 보일러플레이트 코드를 작성하지 않고 몇 시간 만에 인덱서를 설정할 수 있습니다.
주요 기능:
- 인기 있는 프로그램(Token 프로그램, DeFi 프로토콜, Metaplex)에 대한 미리 생성된 디코더
- 구성 가능한 데이터 소스(RPC, LaserStream, Enhanced WebSockets)
- 백필링 및 실시간 스트리밍에 대한 내장 지원
- 여러 저장소 백엔드에 출력(Postgres 기본 제공)
- 완전한 사용자 정의 가능: 사용자 정의 데이터 소스, 디코더 및 데이터 싱크 설정 가능
3단계: 색인을 최신 상태로 유지
역사 데이터를 백필링한 후, 새로운 블록체인 활동에 맞춰 색인을 최신 상태로 유지하기 위한 실시간 스트리밍 솔루션이 필요합니다. 없으면 색인이 낡아질 것입니다.
방법 1: LaserStream (권장)
모든 프로덕션 색인 사용 사례에 기본 선택으로 LaserStream gRPC를 권장합니다. 신뢰할 수 있고 초저지연 및 결함 허용 데이터 스트리밍에 목적이 맞춰져 있습니다.
LaserStream 사용의 이점은 다음과 같습니다:
- 24시간 역사적 재생: 인덱서가 연결이 끊어지면 LaserStream이 누락된 모든 거래를 자동으로 재생합니다 [/laserstream/historical-replay)]
- 자동 재연결: LaserStream SDKs (Rust, Go, JS/TS)가 네트워크 중단을 매끄럽게 처리합니다
- 노드 페일오버: 여러 노드에서 데이터를 동시 집계하여 최대 가동 시간을 보장합니다
속도와 신뢰성을 결합한 LaserStream은 실시간 응용 프로그램(예: 실시간 거래 피드, 거래 대시보드, 즉시 잔액 업데이트)에 이상적입니다.
색인을 위한 LaserStream 사용 방법
subscribe 메서드를 사용하여 블록체인 이벤트를 구독하세요.
다음은 모범 사례입니다:
- 필터를 최대한 좁게 설정하세요: 인덱스할 실제 데이터만 구독하여 대역폭 소비와 필요한 처리를 최소화하세요.
confirmed 커밋 수준 사용: 이는 지연 시간과 최종성을 균형 있게 합니다. processed 수준은 너무 신뢰할 수 없을 수 있으며, finalized는 ~13초의 지연 시간을 추가합니다
failed: false를 설정하세요: 실패한 거래를 추적할 필요가 없는 경우에만 사용합니다
- 투표 거래 제외 (
vote: false): 인덱싱에 관련이 없습니다
예제를 살펴보겠습니다.
새로운 토큰 전송을 색인하기 위해 다음 구독을 사용하세요:
방법 2: LaserStream WebSocket 사용
LaserStream WebSocket — LaserStream의 WebSocket 변형으로, Helius 특정 [transactionSubscribe] 확장을 포함하며, gRPC가 필요 없는 경우 비용 효율적 실시간 스트리밍 대안입니다.
LaserStream WebSocket를 사용해야 할 때:
- 응용 프로그램이 간헐적인 데이터 격차를 감당할 수 있는 경우
- 실시간 업데이트가 중요하지만 필수는 아닌 경우
- 누락된 데이터를 감지하고 백필링하는 기존 인프라가 있는 경우
- 예산 제약이 크고 스트리밍 비용을 최소화해야 하는 경우
- LaserStream으로 전환하기 전 프로토타입화 또는 테스트 중인 경우
그러나 WebSockets를 선택할 때 고려해야 할 몇 가지 타협점이 있습니다:
- 속도: LaserStream WebSocket은 LaserStream gRPC와 동일한 백엔드에서 실행되지만 WebSocket 프로토콜은 JSON 프레이밍 및 메시지당 오버헤드를 추가합니다 — 동일한 데이터에 대한 가장 낮은 지연 시간을 원한다면 LaserStream gRPC를 사용하십시오
- 신뢰성: 역사적 재생 보장이 없습니다. WebSocket이 연결이 끊어지면 RPC 메서드를 사용하여 격차를 수동으로 감지하고 백필링해야 합니다
- 복잡성: 데이터 완전성을 보장하기 위해 추가 모니터링 인프라가 필요합니다
색인을 위한 WebSockets 사용 방법
모든 토큰 전송을 저장하는 색인을 업데이트하려면 transactionSubscribe에 구독하십시오:
시작하기
견고한 Solana 색인을 구축하고 데이터를 백필링하려면 세 가지 핵심 과제를 해결해야 합니다:
- 효율적으로 역사 데이터를 가져오기
- 데이터를 빠르게 검색할 수 있도록 변환 및 저장하기
- 색인된 Solana 데이터를 실시간으로 업데이트하기
최신 최첨단 아카이브 시스템, getTransactionsForAddress과 같은 아카이브 호출, LaserStream과 같은 업계 선도적인 데이터 스트리밍 솔루션을 사용하여 Solana 색인을 구축하는 것이 더 쉽고 실용적입니다.
보완 옵션
자체 색인을 실행하면 완전한 제어가 가능합니다, 그러나 항상 필요한 것은 아닙니다. 일반적인 요구 사항에 대해 관리되는 Helius API는 맞춤색인을 대체하거나 보완할 수 있습니다:
- DAS API — 자산 데이터를 직접 인덱싱하지 않고도 NFT, 대체 가능한 토큰 및 압축 자산(메타데이터, 소유권, 잔액, 소유자/컬렉션/생성자별)을 쿼리합니다.
- 지갑 API — USD 값을 가진 간단한 응답 형태의 지갑 잔액, 역사, 전송 및 신원을 위한 고급 REST 엔드포인트.
많은 팀이 포트폴리오, 토큰 및 지갑 데이터를 위해 이를 사용하고, 관리되는 API에서 다루지 않는 특정 목적의 데이터를 위한 맞춤색인을 사용합니다.
다음 단계