> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana RPC 최적화: 성능 및 비용 모범 사례

> Solana RPC 성능을 최적화하고 비용을 절감하며 신뢰성을 향상시킵니다. 거래 최적화, 데이터 검색 패턴 및 모범 사례 가이드입니다.

RPC 사용을 최적화하면 성능이 크게 향상되고 비용이 절감되며 사용자 경험이 향상될 수 있습니다. 이 가이드는 효율적인 Solana RPC 상호작용을 위한 입증된 기술을 다룹니다.

## 빠른 시작

<CardGroup cols={2}>
  <Card title="트랜잭션 최적화" icon="bolt" href="#트랜잭션-최적화">
    컴퓨팅 단위, 우선 수수료 및 거래 전송 최적화
  </Card>

  <Card title="데이터 검색" icon="database" href="#데이터-검색-최적화">
    계정 및 프로그램 데이터를 가져오기 위한 효율적인 패턴
  </Card>

  <Card title="실시간 모니터링" icon="chart-line" href="#실시간-모니터링">
    WebSocket 구독 및 스트리밍 데이터 최적화
  </Card>

  <Card title="모범 사례" icon="shield-check" href="#모범-사례">
    성능 지침 및 리소스 관리
  </Card>
</CardGroup>

## 트랜잭션 최적화

### 컴퓨팅 단위 관리

**1. 실제 사용량을 결정하기 위한 시뮬레이션:**

```typescript theme={"system"}
const testTransaction = new VersionedTransaction(/* your transaction */);
const simulation = await connection.simulateTransaction(testTransaction, {
  replaceRecentBlockhash: true,
  sigVerify: false
});
const unitsConsumed = simulation.value.unitsConsumed;
```

**2. 여유를 고려한 적절한 한계 설정:**

```typescript theme={"system"}
const computeUnitLimit = Math.ceil(unitsConsumed * 1.1);
const computeUnitIx = ComputeBudgetProgram.setComputeUnitLimit({ 
  units: computeUnitLimit 
});
instructions.unshift(computeUnitIx); // Add at beginning
```

### 우선 수수료 최적화

**1. 동적 수수료 추정치 얻기:**

```typescript theme={"system"}
const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${API_KEY}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    method: 'getPriorityFeeEstimate',
    params: [{
      accountKeys: ['11111111111111111111111111111112'], // System Program
      options: { recommended: true }
    }]
  })
});
const { priorityFeeEstimate } = await response.json().result;
```

**2. 우선 수수료 적용:**

```typescript theme={"system"}
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({ 
  microLamports: priorityFeeEstimate 
});
instructions.unshift(priorityFeeIx);
```

### 트랜잭션 전송 모범 사례

<Tabs>
  <Tab title="표준 접근법">
    ```typescript theme={"system"}
    // Serialize and encode
    const serializedTx = transaction.serialize();
    const signature = await connection.sendRawTransaction(serializedTx, {
      skipPreflight: true, // Saves ~100ms
      maxRetries: 0 // Handle retries manually
    });
    ```
  </Tab>

  <Tab title="확인과 함께">
    ```typescript theme={"system"}
    // Send and confirm with custom logic
    const signature = await connection.sendRawTransaction(serializedTx);

    // Monitor confirmation
    const confirmation = await connection.confirmTransaction({
      signature,
      blockhash: latestBlockhash.blockhash,
      lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
    });
    ```
  </Tab>
</Tabs>

## 데이터 검색 최적화

### 향상된 페이지네이션 방법 (V2)

**대규모 데이터 쿼리의 경우, 커서 기반 페이지네이션을 사용하는 새로운 V2 방법을 사용하십시오:**

<Card title="⚡ 성능 향상" icon="rocket" color="#E84125">
  `getProgramAccountsV2` 및 `getTokenAccountsByOwnerV2`는 대규모 데이터셋을 다루는 애플리케이션에 상당한 성능 개선을 제공합니다:

  * **구성 가능한 제한**: 요청당 1-10,000 계정
  * **커서 기반 페이지네이션**: 대규모 쿼리 시 시간 초과 방지
  * **증분 업데이트**: 실시간 동기화를 위해 `changedSinceSlot` 사용
  * **더 나은 메모리 사용**: 모든 데이터를 한 번에 불러오는 대신 스트리밍 데이터 사용
</Card>

**예시: 효율적인 프로그램 계정 쿼리**

```typescript theme={"system"}
// ❌ Old approach - could timeout with large datasets
const allAccounts = await connection.getProgramAccounts(programId, {
  encoding: 'base64',
  filters: [{ dataSize: 165 }]
});

// ✅ New approach - paginated with better performance
let allAccounts = [];
let paginationKey = null;

do {
  const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${API_KEY}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      id: '1',
      method: 'getProgramAccountsV2',
      params: [
        programId,
        {
          encoding: 'base64',
          filters: [{ dataSize: 165 }],
          limit: 5000,
          ...(paginationKey && { paginationKey })
        }
      ]
    })
  });
  
  const data = await response.json();
  allAccounts.push(...data.result.accounts);
  paginationKey = data.result.paginationKey;
} while (paginationKey);
```

**실시간 애플리케이션을 위한 증분 업데이트:**

```typescript theme={"system"}
// Get only accounts modified since a specific slot
const incrementalUpdate = await fetch(`https://mainnet.helius-rpc.com/?api-key=${API_KEY}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: '1',
    method: 'getProgramAccountsV2',
    params: [
      programId,
      {
        encoding: 'jsonParsed',
        limit: 1000,
        changedSinceSlot: lastProcessedSlot // Only get recent changes
      }
    ]
  })
});
```

## 데이터 검색 최적화

### 효율적인 계정 쿼리

<Tabs>
  <Tab title="단일 계정">
    ```typescript theme={"system"}
    // Use dataSlice to reduce payload size
    const accountInfo = await connection.getAccountInfo(pubkey, {
      encoding: 'base64',
      dataSlice: { offset: 0, length: 100 }, // Only get needed data
      commitment: 'confirmed'
    });
    ```
  </Tab>

  <Tab title="여러 계정">
    ```typescript theme={"system"}
    // Batch multiple account queries
    const accounts = await connection.getMultipleAccountsInfo([
      pubkey1, pubkey2, pubkey3
    ], {
      encoding: 'base64',
      commitment: 'confirmed'
    });
    ```
  </Tab>

  <Tab title="프로그램 계정">
    ```typescript theme={"system"}
    // Use filters to reduce data transfer
    const accounts = await connection.getProgramAccounts(programId, {
      filters: [
        { dataSize: 165 }, // Token account size
        { memcmp: { offset: 0, bytes: mintAddress }}
      ],
      encoding: 'jsonParsed'
    });
    ```
  </Tab>
</Tabs>

### 토큰 잔액 조회

<CodeGroup>
  ```typescript ❌ Inefficient theme={"system"}
  // Don't do this - requires N+1 RPC calls
  const tokenAccounts = await connection.getTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID
  });
  const balances = await Promise.all(
    tokenAccounts.value.map(acc => 
      connection.getTokenAccountBalance(acc.pubkey)
    )
  );
  // ~500ms + (100ms * N accounts)
  ```

  ```typescript ✅ Optimized theme={"system"}
  // Single call with parsed data
  const tokenAccounts = await connection.getTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID
  }, { encoding: 'jsonParsed' });

  const balances = tokenAccounts.value.map(acc => ({
    mint: acc.account.data.parsed.info.mint,
    amount: acc.account.data.parsed.info.tokenAmount.uiAmount
  }));
  // ~500ms total - 95% reduction for large wallets
  ```
</CodeGroup>

### 거래 기록

전체 주소 기록은 [`getTransactionsForAddress`](/docs/ko/rpc/gettransactionsforaddress) —관련된 토큰 계정 활동을 포함한 완전한 거래 데이터를 한 번에 반환하는 Helius 독점 메서드를 사용하세요:

<CodeGroup>
  ```typescript ❌ Inefficient theme={"system"}
  // Avoid sequential transaction fetching
  const signatures = await connection.getSignaturesForAddress(address, { limit: 100 });
  const transactions = await Promise.all(
    signatures.map(sig => connection.getTransaction(sig.signature))
  );
  // ~1s + (200ms * 100 txs) = ~21s
  // Also note: getSignaturesForAddress doesn't include token account transactions
  ```

  ```typescript ✅ Fast (Helius Exclusive) theme={"system"}
  // Use getTransactionsForAddress for full history including token accounts
  const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${API_KEY}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      jsonrpc: '2.0',
      id: 1,
      method: 'getTransactionsForAddress',
      params: [
        address,
        {
          transactionDetails: 'full',
          limit: 100,
          filters: { tokenAccounts: 'balanceChanged' }
        }
      ]
    })
  });
  // ~100ms total - includes complete token history in one call
  ```
</CodeGroup>

### 전송 기록

토큰 또는 SOL 이동만 필요할 경우 — 결제, 포트폴리오 활동, 잔액 조정 — [`getTransfersByAddress`](/docs/ko/rpc/gettransfersbyaddress) (Helius 독점, [개발자 플랜](/docs/ko/billing/plans) 이상 필요)을 사용하세요. 이미 소유자, 민트, 금액 및 소수 자리가 해결된 구문 분석된, 사람이 읽을 수 있는 전송 객체를 반환하여 거래 구문 분석을 완전히 건너뜁니다:

```typescript theme={"system"}
// Parsed USDC transfers received by a wallet - no manual parsing needed
const response = await fetch(`https://mainnet.helius-rpc.com/?api-key=${API_KEY}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'getTransfersByAddress',
    params: [
      address, // Wallet owner address, not a token account
      {
        mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
        direction: 'in',
        limit: 100
      }
    ]
  })
});
// Each transfer includes parsed sender, recipient, amount, decimals, and uiAmount
```

기본 원칙: 전체 거래 페이로드나 비전송 활동이 필요하다면 `getTransactionsForAddress`를 사용하고, 원천이 깨끗한 전송 기록이 필요하다면 `getTransfersByAddress`를 사용하세요.

## 실시간 모니터링

### 계정 구독

<CodeGroup>
  ```typescript ❌ Polling theme={"system"}
  // Avoid polling - wastes resources
  setInterval(async () => {
    const accountInfo = await connection.getAccountInfo(pubkey);
    // Process updates...
  }, 1000);
  ```

  ```typescript ✅ WebSocket theme={"system"}
  // Use WebSocket subscriptions for real-time updates
  const subscriptionId = connection.onAccountChange(
    pubkey,
    (accountInfo, context) => {
      // Handle real-time updates
      console.log('Account updated:', accountInfo);
    },
    'confirmed',
    { encoding: 'base64', dataSlice: { offset: 0, length: 100 }}
  );
  ```
</CodeGroup>

### 프로그램 계정 모니터링

```typescript theme={"system"}
// Monitor specific program accounts with filters
connection.onProgramAccountChange(
  programId,
  (accountInfo, context) => {
    // Handle program account changes
  },
  'confirmed',
  {
    filters: [
      { dataSize: 1024 },
      { memcmp: { offset: 0, bytes: ACCOUNT_DISCRIMINATOR }}
    ],
    encoding: 'base64'
  }
);
```

### 트랜잭션 모니터링

```typescript theme={"system"}
// Subscribe to transaction logs for real-time monitoring
const ws = new WebSocket(`wss://mainnet.helius-rpc.com/?api-key=${API_KEY}`);

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'logsSubscribe',
    params: [
      { mentions: [programId] },
      { commitment: 'confirmed' }
    ]
  }));
});

ws.on('message', (data) => {
  const message = JSON.parse(data);
  if (message.params) {
    const signature = message.params.result.value.signature;
    // Process transaction signature
  }
});
```

## 고급 패턴

### 스마트 재시도 로직

```typescript theme={"system"}
class RetryManager {
  private backoff = new ExponentialBackoff({
    min: 100,
    max: 5000,
    factor: 2,
    jitter: 0.2
  });

  async executeWithRetry<T>(operation: () => Promise<T>): Promise<T> {
    while (true) {
      try {
        return await operation();
      } catch (error) {
        if (error.message.includes('429')) {
          // Rate limit - wait and retry
          await this.backoff.delay();
          continue;
        }
        throw error;
      }
    }
  }
}
```

### 메모리 효율적 처리

```typescript theme={"system"}
// Process large datasets in chunks
function chunk<T>(array: T[], size: number): T[][] {
  return Array.from({ length: Math.ceil(array.length / size) }, (_, i) =>
    array.slice(i * size, i * size + size)
  );
}

// Process program accounts in batches
const allAccounts = await connection.getProgramAccounts(programId, {
  dataSlice: { offset: 0, length: 32 }
});

const chunks = chunk(allAccounts, 100);
for (const batch of chunks) {
  const detailedAccounts = await connection.getMultipleAccountsInfo(
    batch.map(acc => acc.pubkey)
  );
  // Process batch...
}
```

### 연결 풀링

```typescript theme={"system"}
class ConnectionPool {
  private connections: Connection[] = [];
  private currentIndex = 0;

  constructor(rpcUrls: string[]) {
    this.connections = rpcUrls.map(url => new Connection(url));
  }

  getConnection(): Connection {
    const connection = this.connections[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.connections.length;
    return connection;
  }
}

const pool = new ConnectionPool([
  'https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY',
  'https://mainnet-backup.helius-rpc.com/?api-key=YOUR_API_KEY'
]);
```

## 성능 모니터링

### RPC 사용량 추적

```typescript theme={"system"}
class RPCMonitor {
  private metrics = {
    calls: 0,
    errors: 0,
    totalLatency: 0
  };

  async monitoredCall<T>(operation: () => Promise<T>): Promise<T> {
    const start = Date.now();
    this.metrics.calls++;
    
    try {
      const result = await operation();
      this.metrics.totalLatency += Date.now() - start;
      return result;
    } catch (error) {
      this.metrics.errors++;
      throw error;
    }
  }

  getStats() {
    return {
      ...this.metrics,
      averageLatency: this.metrics.totalLatency / this.metrics.calls,
      errorRate: this.metrics.errors / this.metrics.calls
    };
  }
}
```

## 모범 사례

### 약속 수준

<Tabs>
  <Tab title="processed">
    * **사용 용도**: WebSocket 구독, 실시간 업데이트
    * **지연**: 약 400ms
    * **신뢰성**: 대부분의 애플리케이션에 적합
  </Tab>

  <Tab title="confirmed">
    * **사용 용도**: 일반 쿼리, 계정 정보
    * **지연**: 약 1초
    * **신뢰성**: 대부분의 사용 사례에 권장
  </Tab>

  <Tab title="finalized">
    * **사용 용도**: 최종 정산, 취소 불가능한 작업
    * **지연**: 약 32초
    * **신뢰성**: 최대 확실성
  </Tab>
</Tabs>

### 자원 관리

<CheckboxList>
  * `dataSlice`를 사용하여 페이로드 크기 제한
  * `memcmp` 및 `dataSize`을 사용하여 서버 측 필터링 구현
  * 배치 작업으로 라운드 트립 감소
  * 중복 호출 방지를 위해 결과 캐시
  * 완료 시 WebSocket 구독 닫기
  * 오류 처리를 위한 회로 차단기 구현
</CheckboxList>

### 오류 처리

```typescript theme={"system"}
// Implement robust error handling
async function robustRPCCall<T>(operation: () => Promise<T>): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    if (error.code === -32602) {
      // Invalid params - fix request
      throw new Error('Invalid RPC parameters');
    } else if (error.code === -32005) {
      // Node behind - retry with different node
      throw new Error('Node synchronization issue');
    } else if (error.message.includes('429')) {
      // Rate limit - implement backoff
      throw new Error('Rate limited');
    }
    throw error;
  }
}
```

## 피해야 할 일반적인 실수

<Warning>
  **다음과 같은 일반적인 실수를 피하세요:**

  * WebSocket 구독 대신 폴링
  * 필요한 부분 데이터만 필요할 때 전체 계정 데이터 가져오기
  * 다중 쿼리를 위한 배치 작업을 사용하지 않음
  * 비율 제한 무시 및 적절한 재시도 로직 미구현
  * `finalized` 약속을 사용할 때 `confirmed`로 충분한 경우
  * 구독을 닫지 않아 메모리 누수 발생
</Warning>

## 관련 메서드

이 가이드의 최적화 기술은 다음의 WebSocket 및 RPC 메서드를 참조합니다:

<CardGroup cols={2}>
  <Card title="getTransactionsForAddress" href="/docs/ko/rpc/gettransactionsforaddress">
    필터링, 정렬 및 토큰 계정 지원이 포함된 전체 거래 기록 (Helius 독점)
  </Card>

  <Card title="getTransfersByAddress" href="/docs/ko/rpc/gettransfersbyaddress">
    결제 및 조정을 위한 구문 분석된 토큰 및 SOL 전송 기록 (Helius 독점)
  </Card>

  <Card title="getTransaction" href="/docs/ko/api-reference/rpc/http/gettransaction">
    서명으로 전체 거래 세부 정보 검색
  </Card>

  <Card title="getProgramAccounts" href="/docs/ko/api-reference/rpc/http/getprogramaccounts">
    프로그램 소유의 모든 계정 검색
  </Card>

  <Card title="getTokenAccountsByOwner" href="/docs/ko/api-reference/rpc/http/gettokenaccountsbyowner">
    지갑의 토큰 계정 얻기
  </Card>

  <Card title="getMultipleAccountsInfo" href="/docs/ko/api-reference/rpc/http/getmultipleaccounts">
    여러 계정 세부 정보를 일괄 검색
  </Card>

  <Card title="getAccountInfo" href="/docs/ko/api-reference/rpc/http/getaccountinfo">
    단일 계정 정보 얻기
  </Card>

  <Card title="accountSubscribe" href="/docs/ko/api-reference/rpc/websocket/accountsubscribe">
    WebSocket을 통해 계정 변경 구독
  </Card>

  <Card title="programSubscribe" href="/docs/ko/api-reference/rpc/websocket/programsubscribe">
    WebSocket을 통해 프로그램 계정 변경 구독
  </Card>

  <Card title="logsSubscribe" href="/docs/ko/api-reference/rpc/websocket/logssubscribe">
    WebSocket을 통해 거래 로그 구독
  </Card>
</CardGroup>

## 요약

이러한 최적화 기술을 구현함으로써 다음을 달성할 수 있습니다:

* **60-90% 감소** API 호출량
* **실시간 운영에 대한 상당히 낮은 지연 시간**
* **대상 쿼리를 통해 대역폭 사용 감소**
* **스마트 재시도 로직으로 인한 오류 복원력 증가**
* **효율적인 자원 사용을 통한 운영 비용 절감**

<Card title="다음 단계" icon="arrow-right">
  이러한 최적화를 구현할 준비가 되셨나요? 트랜잭션에 특화된 모범 사례를 위한 [트랜잭션 최적화 가이드](/docs/ko/sending-transactions/optimizing-transactions)를 확인하세요.
</Card>
