> ## 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.

# LaserStream WebSocket: 실시간 Solana 데이터 스트리밍

> LaserStream WebSocket을 통해 WebSocket으로 Solana 블록체인 데이터를 실시간 스트리밍하세요. 표준 Solana 구독 및 트랜잭션 구독과 같은 Helius 확장 기능 포함, Agave RPC 기반 WebSockets보다 최대 200ms 빠름.

## LaserStream WebSocket이란?

LaserStream WebSocket은 [LaserStream](/docs/ko/laserstream)의 WebSocket 프로토콜 변형입니다. 표준 Solana JSON-RPC 구독 메서드( `accountSubscribe`, `programSubscribe`, `logsSubscribe`, `signatureSubscribe`, `slotSubscribe`, …)와 함께 고급 필터링을 위한 [`transactionSubscribe`](/docs/ko/rpc/websocket/transaction-subscribe)와 같은 Helius 전용 확장을 제공합니다. 이는 동일한 통합 `wss://mainnet.helius-rpc.com` 엔드포인트 및 [gRPC 제품](/docs/ko/laserstream)과 동일한 LaserStream 백엔드에서 제공합니다.

WebSockets은 지속적이고 실시간 연결을 제공합니다. 반복적으로 "무엇이 변경되었는지" 확인하는 대신, 블록체인이 무언가 발생하는 순간 즉시 알려줍니다.

<CardGroup cols={2}>
  <Card title="실시간 업데이트" icon="bolt">
    Solana 계정이 변경되거나, 거래가 발생하거나, 새로운 블록이 생성될 때 즉시 알림을 받으세요
  </Card>

  <Card title="효율적인 자원 사용" icon="leaf">
    수백 개의 HTTP 요청을 폴링하는 대신 하나의 지속적 연결
  </Card>

  <Card title="낮은 지연 시간" icon="clock">
    표준 Agave RPC 기반 WebSockets보다 최대 200ms 빠르게, LaserStream에 의해 제공
  </Card>

  <Card title="Helius 확장 기능" icon="filter">
    표준 Solana 메서드를 기반으로 고급 필터링을 위한 `transactionSubscribe` 및 다양한 `accountSubscribe`
  </Card>
</CardGroup>

## 엔드포인트

WebSocket은 표준 Solana 메서드와 Helius 전용 확장 기능 모두 네트워크당 하나의 통합 엔드포인트에서 제공됩니다:

**Mainnet:** `wss://mainnet.helius-rpc.com/?api-key=<API_KEY>`
**Devnet:** `wss://devnet.helius-rpc.com/?api-key=<API_KEY>`

### Gatekeeper (베타)

가장 빠른 WebSocket 제공을 테스트하려면 새로운 Gatekeeper (베타) 엔드포인트를 사용해 보세요:

`wss://beta.helius-rpc.com/?api-key=<API_KEY>`

## 가격 및 측정

WebSocket 사용은 **압축되지 않은 스트리밍 데이터 0.1MB당 2 크레딧**으로 측정됩니다. 연결을 여는 데 **1 크레딧**이 소요됩니다.

전문 플랜에서 대량 작업량을 처리하기 위해, [**데이터 추가 기능**](/docs/ko/billing/plans#데이터-추가-옵션)은 예측 가능한 비용으로 월별 데이터 할당량(5TB–100TB)을 제공합니다. 데이터 추가 기능은 LaserStream 및 WebSockets에 적용할 수 있습니다.

<Note>
  Helius 전용 메서드 `transactionSubscribe` 및 `accountSubscribe` (Helius 필터 포함)은 **개발자**, **비즈니스**, **프로페셔널** [플랜](/docs/ko/billing/plans)이 필요합니다. `programSubscribe`, `logsSubscribe` 및 `signatureSubscribe`와 같은 표준 Solana 메서드는 모든 플랜에서 사용할 수 있습니다.
</Note>

## 핵심 개념

### 구독 유형

<AccordionGroup>
  <Accordion title="계정 구독" icon="user">
    지갑 잔액, 토큰 계정 또는 프로그램 데이터와 같은 특정 계정의 변경 사항을 모니터링합니다.

    **사용 사례:**

    * 지갑 잔액 추적
    * 토큰 계정 모니터링
    * 스마트 계약 상태 변경
    * NFT 소유권 업데이트
  </Accordion>

  <Accordion title="프로그램 구독" icon="code">
    특정 프로그램이 소유한 모든 계정을 변경 사항에 대해 관찰합니다.

    **사용 사례:**

    * DEX 거래 모니터링
    * DeFi 프로토콜 추적
    * NFT 마켓플레이스 활동
    * 게임 자산 변경
  </Accordion>

  <Accordion title="트랜잭션 구독" icon="receipt">
    특정 거래가 확인될 때 또는 거래가 특정 계정을 언급할 때 알림을 받습니다.

    **사용 사례:**

    * 결제 확인
    * 거래 상태 추적
    * 다중 서명 승인
    * 계약 실행 모니터링
  </Accordion>

  <Accordion title="슬롯 구독" icon="clock">
    블록체인 진행 및 확정성을 슬롯 수준에서 모니터링합니다.

    **사용 사례:**

    * 블록 탐색기 애플리케이션
    * 네트워크 상태 모니터링
    * 합의 추적
    * 성능 분석
  </Accordion>
</AccordionGroup>

### 확정성 수준

확정성 수준을 이해하는 것은 신뢰성 있는 애플리케이션을 위해 중요합니다:

<Tabs>
  <Tab title="Processed">
    **가장 빠름** - 트랜잭션이 검증자에 의해 처리되었으나 확인되지 않음

    * 지연 시간: 약 400ms
    * 위험: 버려지거나 재정렬될 수 있음
    * 사용 사례: 실시간 UI 업데이트 (주의 필요)
  </Tab>

  <Tab title="Confirmed">
    **균형 잡힘** - 클러스터의 다수가 슬롯에 투표 완료

    * 지연 시간: 약 2-3초
    * 위험: 버려질 가능성 낮음
    * 사용 사례: 대부분의 애플리케이션
  </Tab>

  <Tab title="Finalized">
    **가장 안전함** - 클러스터의 절대 다수가 슬롯에 투표 완료

    * 지연 시간: 약 15-30초
    * 위험: 버려질 가능성 극히 낮음
    * 사용 사례: 금융 애플리케이션, 고가치 거래
  </Tab>
</Tabs>

<Info>
  **확정성 수준에 대해 더 알고 싶으신가요?** 자세한 블로그 게시물을 읽어보세요: [Solana 확정성 수준 이해하기](https://www.helius.dev/blog/solana-commitment-levels)
</Info>

## 사용 가능한 WebSocket 메서드

Helius는 Solana WebSocket 구독 메서드 전체 집합과 Helius 전용 확장을 지원합니다. 모든 메서드는 동일한 `wss://mainnet.helius-rpc.com` 엔드포인트를 공유합니다.

### Helius 확장

두 가지 메서드가 Solana 표준보다 풍부한 필터링을 제공합니다:

* [`transactionSubscribe`](/docs/ko/rpc/websocket/transaction-subscribe) — 포함/제외/필수 계정 목록, 투표/실패 플래그, 특정 서명을 사용하는 거래 구독
* [`accountSubscribe`](/docs/ko/rpc/websocket/account-subscribe) — Helius는 표준 `accountSubscribe` 형태에 고급 필터를 추가합니다.

### 표준 Solana 메서드

`accountSubscribe`, `blockSubscribe`, `logsSubscribe`, `programSubscribe`, `rootSubscribe`, `signatureSubscribe`, `slotSubscribe`, `slotsUpdatesSubscribe`, `voteSubscribe` 및 해당 `*Unsubscribe` 쌍.

<Card title="완전한 API 참조" icon="book" href="/docs/ko/api-reference/rpc/websocket-methods">
  **18개 이상의 WebSocket 메서드 탐색**. 각 메서드에는 자세한 매개변수, 응답 형식, 예제가 포함됩니다.
</Card>

## 재연결 로직 구현 방법

WebSocket 연결은 네트워크 문제, 서버 유지 관리 또는 일시적 장애와 같은 여러 가지 이유로 해제될 수 있습니다. 프로덕션 애플리케이션에서는 신뢰성을 위해 **반드시** 재연결 로직을 구현해야 합니다.

### 연결 해제 이유

<AccordionGroup>
  <Accordion title="네트워크 문제">
    * 인터넷 연결 문제
    * 모바일 기기의 WiFi 전환
    * 기업 방화벽 타임아웃
    * ISP 라우팅 변경
  </Accordion>

  <Accordion title="서버 측 이벤트">
    * 계획된 유지 보수 창
    * 로드 밸런서 재시작
    * RPC 노드 업데이트
    * 일시적인 과부하 보호
  </Accordion>

  <Accordion title="클라이언트 측 문제">
    * 브라우저 탭 백그라운드 실행
    * 모바일 앱 일시 중단
    * 컴퓨터 절전/동면
    * 프로세스 충돌 또는 재시작
  </Accordion>
</AccordionGroup>

### 연결 해제 감지

<Tabs>
  <Tab title="JavaScript/Browser">
    ```javascript [expandable] theme={"system"}
    class ConnectionMonitor {
      constructor(ws) {
        this.ws = ws;
        this.pingInterval = null;
        this.lastPong = Date.now();
        this.isConnected = false;
        
        this.setupEventListeners();
        this.startPingMonitoring();
      }
      
      setupEventListeners() {
        this.ws.onopen = () => {
          console.log('Connected');
          this.isConnected = true;
          this.lastPong = Date.now();
        };
        
        this.ws.onclose = (event) => {
          console.log('Disconnected:', event.code, event.reason);
          this.isConnected = false;
          this.stopPingMonitoring();
        };
        
        this.ws.onerror = (error) => {
          console.error('WebSocket error:', error);
          this.isConnected = false;
        };
        
        // Listen for pong responses (server acknowledgment)
        this.ws.onmessage = (event) => {
          const data = JSON.parse(event.data);
          if (data.method === 'pong') {
            this.lastPong = Date.now();
          }
          // Handle other messages...
        };
      }
      
      startPingMonitoring() {
        this.pingInterval = setInterval(() => {
          if (this.isConnected) {
            // Send ping to check connection health
            this.ws.send(JSON.stringify({
              jsonrpc: '2.0',
              method: 'ping',
              id: Date.now()
            }));
            
            // Check if we received a pong recently
            const timeSinceLastPong = Date.now() - this.lastPong;
            if (timeSinceLastPong > 30000) { // 30 seconds timeout
              console.warn('No pong received, connection may be stale');
              this.ws.close();
            }
          }
        }, 10000); // Ping every 10 seconds
      }
      
      stopPingMonitoring() {
        if (this.pingInterval) {
          clearInterval(this.pingInterval);
          this.pingInterval = null;
        }
      }
    }
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript [expandable] theme={"system"}
    const WebSocket = require('ws');

    class NodeConnectionMonitor {
      constructor(url) {
        this.url = url;
        this.ws = null;
        this.pingInterval = null;
        this.isAlive = false;
      }
      
      connect() {
        this.ws = new WebSocket(this.url);
        
        this.ws.on('open', () => {
          console.log('Connected');
          this.isAlive = true;
          this.startHeartbeat();
        });
        
        this.ws.on('close', () => {
          console.log('Disconnected');
          this.isAlive = false;
          this.stopHeartbeat();
        });
        
        this.ws.on('error', (error) => {
          console.error('WebSocket error:', error);
          this.isAlive = false;
        });
        
        // Built-in ping/pong handling
        this.ws.on('pong', () => {
          this.isAlive = true;
        });
      }
      
      startHeartbeat() {
        this.pingInterval = setInterval(() => {
          if (!this.isAlive) {
            console.log('Connection lost, terminating');
            return this.ws.terminate();
          }
          
          this.isAlive = false;
          this.ws.ping();
        }, 30000); // Ping every 30 seconds
      }
      
      stopHeartbeat() {
        if (this.pingInterval) {
          clearInterval(this.pingInterval);
          this.pingInterval = null;
        }
      }
    }
    ```
  </Tab>
</Tabs>

### 재연결 전략

<Tabs>
  <Tab title="지수 백오프">
    ```javascript [expandable] theme={"system"}
    class ExponentialBackoffReconnector {
      constructor(url, maxRetries = 10) {
        this.url = url;
        this.maxRetries = maxRetries;
        this.retryCount = 0;
        this.baseDelay = 1000; // Start with 1 second
        this.maxDelay = 30000; // Cap at 30 seconds
        this.ws = null;
        this.subscriptions = new Map();
        this.isReconnecting = false;
      }
      
      connect() {
        if (this.isReconnecting) return;
        
        try {
          this.ws = new WebSocket(this.url);
          this.setupEventHandlers();
        } catch (error) {
          console.error('Failed to create WebSocket:', error);
          this.scheduleReconnect();
        }
      }
      
      setupEventHandlers() {
        this.ws.onopen = () => {
          console.log('Connected successfully');
          this.retryCount = 0; // Reset retry count on successful connection
          this.isReconnecting = false;
          this.resubscribeAll(); // Restore subscriptions
        };
        
        this.ws.onclose = (event) => {
          console.log('Connection closed:', event.code);
          if (!this.isReconnecting) {
            this.scheduleReconnect();
          }
        };
        
        this.ws.onerror = (error) => {
          console.error('WebSocket error:', error);
        };
      }
      
      scheduleReconnect() {
        if (this.retryCount >= this.maxRetries) {
          console.error('Max retry attempts reached. Giving up.');
          return;
        }
        
        this.isReconnecting = true;
        this.retryCount++;
        
        // Calculate delay with exponential backoff + jitter
        const delay = Math.min(
          this.baseDelay * Math.pow(2, this.retryCount - 1),
          this.maxDelay
        );
        
        // Add jitter to prevent thundering herd
        const jitteredDelay = delay + (Math.random() * 1000);
        
        console.log(`Reconnecting in ${jitteredDelay}ms (attempt ${this.retryCount}/${this.maxRetries})`);
        
        setTimeout(() => {
          this.connect();
        }, jitteredDelay);
      }
      
      subscribe(method, params, callback) {
        const id = this.generateId();
        this.subscriptions.set(id, { method, params, callback });
        
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
          this.sendSubscription(id, method, params);
        }
        
        return id;
      }
      
      resubscribeAll() {
        console.log(`Restoring ${this.subscriptions.size} subscriptions`);
        for (const [id, sub] of this.subscriptions) {
          this.sendSubscription(id, sub.method, sub.params);
        }
      }
      
      sendSubscription(id, method, params) {
        this.ws.send(JSON.stringify({
          jsonrpc: '2.0',
          id: id,
          method: method,
          params: params
        }));
      }
      
      generateId() {
        return Date.now() + Math.random();
      }
    }
    ```
  </Tab>

  <Tab title="서킷 브레이커 패턴">
    ```javascript [expandable] theme={"system"}
    class CircuitBreakerWebSocket {
      constructor(url, options = {}) {
        this.url = url;
        this.failureThreshold = options.failureThreshold || 5;
        this.recoveryTimeout = options.recoveryTimeout || 60000;
        this.checkInterval = options.checkInterval || 10000;
        
        this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
        this.failureCount = 0;
        this.lastFailureTime = null;
        this.ws = null;
        this.subscriptions = new Map();
      }
      
      connect() {
        if (this.state === 'OPEN') {
          if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {
            console.log('Circuit breaker moving to HALF_OPEN state');
            this.state = 'HALF_OPEN';
          } else {
            console.log('Circuit breaker is OPEN, connection blocked');
            return false;
          }
        }
        
        try {
          this.ws = new WebSocket(this.url);
          this.setupEventHandlers();
          return true;
        } catch (error) {
          this.recordFailure();
          return false;
        }
      }
      
      setupEventHandlers() {
        this.ws.onopen = () => {
          console.log('Connected - Circuit breaker CLOSED');
          this.state = 'CLOSED';
          this.failureCount = 0;
          this.resubscribeAll();
        };
        
        this.ws.onclose = () => {
          this.recordFailure();
        };
        
        this.ws.onerror = (error) => {
          console.error('WebSocket error:', error);
          this.recordFailure();
        };
      }
      
      recordFailure() {
        this.failureCount++;
        this.lastFailureTime = Date.now();
        
        console.log(`Failure recorded: ${this.failureCount}/${this.failureThreshold}`);
        
        if (this.failureCount >= this.failureThreshold) {
          console.log('Circuit breaker opened due to repeated failures');
          this.state = 'OPEN';
        }
      }
      
      startHealthCheck() {
        setInterval(() => {
          if (this.state === 'OPEN' || 
              (this.ws && this.ws.readyState !== WebSocket.OPEN)) {
            this.connect();
          }
        }, this.checkInterval);
      }
    }
    ```
  </Tab>
</Tabs>

### 재연결 로직 테스트

<Tabs>
  <Tab title="네트워크 시뮬레이션">
    ```javascript [expandable] theme={"system"}
    // Test disconnection scenarios
    class NetworkSimulator {
      constructor(wsManager) {
        this.wsManager = wsManager;
      }
      
      // Simulate network outage
      simulateNetworkOutage(duration = 5000) {
        console.log('Simulating network outage...');
        
        // Force close the connection
        if (this.wsManager.ws) {
          this.wsManager.ws.close(1006, 'Network outage simulation');
        }
        
        // Block reconnection temporarily
        const originalConnect = this.wsManager.connect.bind(this.wsManager);
        this.wsManager.connect = () => {
          console.log('Connection blocked during outage simulation');
        };
        
        // Restore connection after duration
        setTimeout(() => {
          console.log('Network restored');
          this.wsManager.connect = originalConnect;
          this.wsManager.connect();
        }, duration);
      }
      
      // Simulate intermittent connectivity
      simulateIntermittentConnectivity() {
        setInterval(() => {
          if (Math.random() < 0.1) { // 10% chance every 10 seconds
            console.log('Simulating connection drop...');
            this.wsManager.ws?.close(1006, 'Intermittent connectivity');
          }
        }, 10000);
      }
    }

    // Usage
    const simulator = new NetworkSimulator(wsManager);
    simulator.simulateNetworkOutage(10000); // 10 second outage
    ```
  </Tab>

  <Tab title="자동화 테스트">
    ```javascript [expandable] theme={"system"}
    // Jest test example
    describe('WebSocket Reconnection', () => {
      let wsManager;
      
      beforeEach(() => {
        wsManager = new ProductionWebSocketManager({
          endpoint: 'ws://localhost:8080',
          apiKey: 'test-key'
        });
      });
      
      test('should reconnect after connection loss', async () => {
        const reconnectPromise = new Promise((resolve) => {
          wsManager.on('connected', resolve);
        });
        
        await wsManager.connect();
        
        // Simulate connection loss
        wsManager.ws.close(1006, 'Test disconnection');
        
        // Wait for reconnection
        await reconnectPromise;
        
        expect(wsManager.connectionState).toBe('CONNECTED');
        expect(wsManager.metrics.reconnections).toBeGreaterThan(0);
      });
      
      test('should restore subscriptions after reconnection', async () => {
        await wsManager.connect();
        
        const messages = [];
        const subscriptionId = wsManager.subscribe(
          'accountSubscribe',
          ['test-account', {}],
          (data) => messages.push(data)
        );
        
        // Verify subscription exists
        expect(wsManager.subscriptions.has(subscriptionId)).toBe(true);
        
        // Simulate disconnection and reconnection
        wsManager.ws.close(1006, 'Test disconnection');
        
        await new Promise(resolve => wsManager.on('connected', resolve));
        
        // Verify subscription was restored
        const subscription = wsManager.subscriptions.get(subscriptionId);
        expect(subscription.pending).toBe(true); // Should be re-subscribing
      });
    });
    ```
  </Tab>
</Tabs>

<Warning>
  **프로덕션에 중요한 사항**: 적절한 재연결 로직 구현은 프로덕션 애플리케이션에 선택 사항이 아닙니다. WebSocket 연결은 해제될 것입니다 - 계획하고 테스트하며 프로덕션에서 모니터링하세요.
</Warning>

## 문제 해결

<AccordionGroup>
  <Accordion title="연결 실패">
    **증상**: WebSocket이 초기 연결에 실패함

    **해결책**:

    * API 키가 올바르고 충분한 크레딧을 가지고 있는지 확인
    * 엔드포인트 URL 형식 확인: `wss://mainnet.helius-rpc.com?api-key=YOUR_KEY`
    * 포트 443에서 WebSocket 연결을 허용하는지 방화벽 확인
    * 기본 연결 확인을 위한 간단한 핑으로 테스트
  </Accordion>

  <Accordion title="빈번한 연결 해제">
    **증상**: 연결이 몇 분마다 끊어짐

    **해결책**:

    * WebSocket은 **10분 비활성 타이머**가 있습니다. 연결을 유지하려면 최소 1분에 한 번씩 핑을 보내십시오 (위의 재연결 예제 및 [WebSocket FAQ](/docs/ko/faqs/websockets#연결-끊김-및-재시도) 참조)
    * 적절한 핑/퐁 하트비트를 구현하십시오 (위의 재연결 예제 참조)
    * 네트워크 안정성 및 기업 방화벽 설정 확인
    * 구독 수를 모니터링하세요 - 너무 많으면 불안정성을 초래할 수 있습니다
    * 연결 수명주기를 적절히 처리하는지 확인
  </Accordion>

  <Accordion title="메시지 누락">
    **증상**: 예상되는 구독 업데이트를 받지 못함

    **해결책**:

    * 구독이 확인되었는지 확인 (응답 확인)
    * 모니터링 중인 계정/프로그램에 실제 활동이 있는지 확인
    * 연결 상태를 모니터링하세요 - 누락된 메시지는 종종 연결 해제를 나타냅니다
  </Accordion>

  <Accordion title="높은 지연 시간">
    **증상**: 메시지 전달 속도가 느리거나 업데이트 지연

    **해결책**:

    * "Finalized" 대신 "Confirmed" 확정성을 사용
    * 활성 구독 수를 줄이세요
    * 메시지 처리 로직 최적화
    * 부하 분산을 위해 여러 연결 사용 고려
    * 네트워크 연결 품질 확인
  </Accordion>

  <Accordion title="메모리 누수">
    **증상**: 애플리케이션 메모리 사용량이 시간 경과에 따라 증가함

    **해결책**:

    * 적절한 구독 정리 구현
    * 컴포넌트가 언마운트될 때 이벤트 리스너 제거
    * 메시지 로그를 주기적으로 정리
    * 구독 수를 모니터링하고 제한 적용
    * 콜백 함수에 약한 참조 사용 가능
  </Accordion>
</AccordionGroup>

## 표준 RPC에서의 마이그레이션

현재 HTTP 폴링을 사용 중인 경우, WebSocket으로 마이그레이션하는 방법은 다음과 같습니다:

```javascript [expandable] theme={"system"}
// Old approach - HTTP polling
class HTTPAccountMonitor {
  constructor(connection, accountAddress) {
    this.connection = connection;
    this.accountAddress = accountAddress;
    this.interval = null;
    this.lastKnownBalance = null;
  }

  start() {
    this.interval = setInterval(async () => {
      try {
        const accountInfo = await this.connection.getAccountInfo(
          new PublicKey(this.accountAddress)
        );
        
        const currentBalance = accountInfo?.lamports || 0;
        
        if (this.lastKnownBalance !== currentBalance) {
          console.log(`Balance changed: ${currentBalance}`);
          this.lastKnownBalance = currentBalance;
        }
      } catch (error) {
        console.error('Failed to fetch account info:', error);
      }
    }, 2000); // Poll every 2 seconds
  }

  stop() {
    if (this.interval) {
      clearInterval(this.interval);
      this.interval = null;
    }
  }
}

// New approach - WebSocket subscription
class WebSocketAccountMonitor {
  constructor(wsManager, accountAddress) {
    this.wsManager = wsManager;
    this.accountAddress = accountAddress;
    this.subscriptionId = null;
  }

  start() {
    this.subscriptionId = this.wsManager.subscribe(
      'accountSubscribe',
      [
        this.accountAddress,
        { encoding: 'jsonParsed', commitment: 'confirmed' }
      ],
      (data) => {
        const currentBalance = data.value.lamports;
        console.log(`Balance changed: ${currentBalance}`);
        
        // Handle the change immediately - no polling delay!
      }
    );
  }

  stop() {
    if (this.subscriptionId) {
      this.wsManager.unsubscribe(this.subscriptionId);
      this.subscriptionId = null;
    }
  }
}
```

## 향상된 기능

더 고급 기능이 필요한 애플리케이션의 경우 [LaserStream gRPC](/docs/ko/laserstream)를 고려하세요:

<CardGroup cols={2}>
  <Card title="24시간 이력 재생" icon="clock-rotate-left">
    앱이 오프라인일 때 누락된 데이터를 보충
  </Card>

  <Card title="다중 노드 집계" icon="network-wired">
    여러 검증자에서 데이터를 통해 신뢰성 향상
  </Card>

  <Card title="더 높은 처리량" icon="gauge-high">
    더 많은 구독 및 더 높은 메시지 속도 처리
  </Card>

  <Card title="기업 기능" icon="building">
    고급 모니터링, 분석 및 데이터 파이프라인
  </Card>
</CardGroup>

## 시작하기

시작할 준비가 되셨습니까?

실용적인 예제와 단계별 구현을 위한 [WebSocket 빠른 시작 가이드](/docs/ko/rpc/websocket/quickstart)를 확인하세요.
