콘텐츠로 이동

분산 추론 라우팅

부하 분산이 활성화되면 Backend.AI GO는 추론 요청을 네트워크 노드로 투명하게 라우팅합니다. 요청된 모델이 로컬에서 실행 중이 아니면 추론 프록시가 분산 모델 인덱스에서 모델을 조회하여 해당 모델을 보유한 네트워크 노드로 요청을 전달합니다.

작동 원리

추론 프록시는 로컬 우선 전략을 사용합니다:

  1. 로컬 해석: 요청된 모델이 Continuum Router 포트 또는 모델 서버 포트를 통해 로컬에서 실행 중인지 확인합니다.

  2. 네트워크 노드 폴백: 모델을 로컬에서 찾지 못하고 부하 분산이 활성화된 경우, InferenceRouter가 모델을 해당 모델을 보유한 접근 가능한 네트워크 노드로 해석합니다.

  3. 인증된 전달: 프록시는 노드의 API 키와 함께 Authorization: Bearer 헤더를 추가하여 네트워크 노드의 API로 요청을 전달합니다.

부하 분산이 활성화되면 연결된 네트워크 노드는 로컬 continuum-router 인스턴스에 OpenAI 클라우드 백엔드(node-{fingerprint})로도 동기화됩니다. 로컬 채팅 및 프록시 요청은 설정된 부하 분산 전략과 가중치를 사용하여 continuum-router를 통해 직접 라우팅됩니다. 요청이 continuum-router를 우회하는 경우 인프로세스 InferenceRouter가 폴백 라우팅 레이어로 동작합니다.

이 과정은 호출자에게 완전히 투명합니다. 요청 및 응답 형식은 변경되지 않으며, 라우팅 레이어는 OpenAI 호환 API를 사용하는 클라이언트에게 보이지 않습니다.

분산 라우팅 활성화

분산 라우팅은 부하 분산 설정으로 제어됩니다. 활성화하려면:

  1. 설정 > 노드 > 다른 컴퓨터 연결하기나 모델의 분산 풀 탭을 엽니다. 부하 분산 섹션은 연결된 컴퓨터가 하나 이상 있을 때 표시되고, 두 곳에 같은 섹션이 나옵니다.
  2. 부하 분산 제목 옆의 스위치를 켭니다. 나머지 항목은 스위치가 켜져 있을 때만 보입니다.
  3. 라우팅 전략을 선택합니다 (아래 참조).

섹션의 변경 사항은 바꾸는 즉시 저장되므로 저장 버튼이 따로 없는데, 전략과 스위치는 바꿀 때, 노드 순서는 노드를 놓을 때, 상태 확인 주기는 입력란을 벗어나거나 Enter 키를 누를 때 저장됩니다. 부하 분산이 꺼져 있으면 분산 풀 탭 맨 위에 해당 사실과 함께 켜는 버튼이 표시됩니다.

부하 분산이 비활성화되면 모든 추론 요청은 로컬에서 처리되며, node-* 클라우드 백엔드가 continuum-router에서 제거되고 노드 동기화가 일시 중지됩니다. 부하 분산이 활성화되면 등록된 노드가 선택한 부하 분산 전략에 매핑된 가중치와 선택 전략으로 continuum-router에 다시 동기화됩니다.

라우팅 전략

InferenceRouter는 네 가지 전략을 지원합니다:

전략 동작
priority 사용자가 정한 순서대로 노드에 요청을 보냅니다 (노드 순서 참조). continuum-router의 WeightedRoundRobin과 내림차순 가중치로 매핑됩니다.
round-robin 사용 가능한 노드를 순서대로 순환합니다. continuum-router의 RoundRobin으로 매핑됩니다.
least-loaded 현재 진행 중인 요청 수가 가장 적은 노드로 라우팅합니다 (실시간 부하 기준). continuum-router의 LeastLatency로 매핑됩니다.
fastest 측정된 지연 시간이 가장 낮은 노드로 라우팅합니다. continuum-router의 LeastLatency로 매핑됩니다.

전략은 설정 > 노드 > 다른 컴퓨터 연결하기나 분산 풀 탭의 부하 분산 섹션에서 설정합니다.

노드 순서

priority 전략에서는 부하 분산에 연결된 컴퓨터가 요청을 받는 순서대로 나열되고, 맨 위의 컴퓨터가 요청을 먼저 받습니다. 목록에서 컴퓨터를 위아래로 끌어 놓으면 순서가 바로 저장되고, 키보드로는 컴퓨터의 손잡이에 초점을 두고 스페이스 키로 집은 다음 위아래 화살표 키로 옮기고 스페이스 키를 다시 눌러 놓습니다. 목록의 컴퓨터마다 라우팅 포함 여부를 켜고 끌 수 있고, 각 컴퓨터의 라우팅 탭에서는 해당 컴퓨터가 몇 번째인지 볼 수 있습니다.

순서는 nodeConfigs의 컴퓨터별 priority 값으로 저장됩니다. 컴퓨터를 놓을 때 맨 위의 컴퓨터가 가장 큰 값을, 마지막 컴퓨터가 1을 받으므로 순서가 같은 컴퓨터는 생기지 않죠. 서버는 priority를 1부터 255까지 받습니다.

서킷 브레이커

각 네트워크 노드에는 연쇄 장애를 방지하는 서킷 브레이커가 연결되어 있습니다.

  • 임계값: 특정 노드에 3번 연속 장애가 발생하면 서킷이 열리고 해당 노드는 후보 선택에서 제외됩니다.
  • 초기화: 60초 후 서킷이 반열림(half-open) 상태로 전환되어 단일 프로브 요청이 통과할 수 있습니다. 프로브 성공 시 서킷이 닫히고, 또 다른 장애가 발생하면 즉시 재개방됩니다.
  • 라우팅 영향: 서킷이 열린 노드는 엔드포인트 해석 시 건너뜁니다. 모든 후보의 서킷이 열려 있는 경우 요청은 503을 반환합니다.

서킷 브레이커는 페일오버 메커니즘과 독립적으로 동작합니다: 서킷이 열린 노드는 페일오버 대상으로도 요청을 받지 않습니다.

자동 페일오버

부하 분산 설정에서 failoverEnabled가 true(기본값)인 경우, 프록시는 실패한 요청을 대체 노드에서 다시 시도합니다.

페일오버는 다음 상황에서 트리거됩니다:

  • 선택된 노드에 연결 오류가 발생하거나,
  • 노드가 5xx 상태 코드로 응답하는 경우.

트리거 시 프록시는 실패한 노드를 제외하고 엔드포인트를 재해석하여 요청을 한 번 다시 시도합니다. 원본 요청 본문이 그대로 재전송됩니다.

스트리밍 페일오버 제한

페일오버는 첫 번째 SSE 청크가 클라이언트에 전송되기 전에만 가능합니다. 스트리밍이 시작된 후에는 응답이 커밋되고 오류가 클라이언트에 직접 전파됩니다. 비스트리밍 요청은 대체 노드에서 요청 전체를 다시 시도합니다.

통합 모델 목록

GET /api/v1/inference/models (OpenAI 호환) 엔드포인트는 통합된 목록을 반환합니다:

  • 로컬 모델: 로컬 추론 서버에서 직접 보고된 모델.
  • 네트워크 노드 모델: 분산 모델 인덱스를 통해 발견된 모델로, "owned_by": "remote"로 표시됩니다.

중복된 모델 ID는 중복 제거됩니다. 동일한 ID가 로컬과 네트워크 노드 모두에 있는 경우 로컬 모델이 항상 우선합니다.

{
  "object": "list",
  "data": [
    { "id": "llama-3-8b-instruct", "object": "model", "owned_by": "llama.cpp" },
    { "id": "mistral-7b-instruct", "object": "model", "owned_by": "remote" }
  ]
}

분산 풀 상태

두 개의 API 엔드포인트가 분산 풀의 상태를 제공합니다.

추론 상태 (요약)

GET /api/v1/inference/status는 부하 분산이 활성화된 경우 distributed 필드를 반환합니다:

{
  "available": true,
  "routerRunning": true,
  "routerPort": 39080,
  "loadedModels": 1,
  "llmModels": 1,
  "diffusionModels": 0,
  "distributed": {
    "enabled": true,
    "strategy": "priority",
    "totalNodes": 2,
    "onlineNodes": 2,
    "remoteModels": 3
  }
}

전체 분산 상태

GET /api/v1/pool/distributed-status는 노드별 세부 정보를 포함한 전체 풀 보기를 반환합니다:

{
  "enabled": true,
  "strategy": "priority",
  "totalNodes": 2,
  "onlineNodes": 2,
  "models": [
    {
      "id": "mistral-7b-instruct",
      "availableOn": ["node-fingerprint-abc"]
    }
  ],
  "endpoints": [
    {
      "fingerprint": "node-fingerprint-abc",
      "baseUrl": "http://192.168.1.50:39080",
      "status": "online",
      "latencyMs": 12,
      "loadedModelCount": 2,
      "priority": 5
    }
  ]
}

이 엔드포인트는 get_distributed_pool_status Tauri IPC 명령을 통해 프론트엔드에서도 접근할 수 있습니다.

라우팅 통계

GET /api/v1/pool/routing-stats (및 GET /api/v1/nodes/routing-stats)는 노드별 요청 메트릭과 서킷 브레이커 상태를 반환합니다:

{
  "nodes": [
    {
      "fingerprint": "node-fingerprint-abc",
      "totalRequests": 150,
      "successCount": 147,
      "failureCount": 3,
      "avgLatencyMs": 42.5,
      "activeRequests": 2,
      "circuitOpen": false,
      "consecutiveFailures": 0
    }
  ],
  "totalRequests": 150,
  "totalSuccesses": 147,
  "totalFailures": 3,
  "circuitBreaker": {
    "failureThreshold": 3,
    "resetTimeoutSecs": 60
  }
}

continuum-router가 활성 상태일 때 /admin/stats의 원격 측정 데이터가 이 라우팅 통계에 자동으로 병합됩니다. 요청 수, 성공, 실패 및 지연 시간 측정값은 continuum-router를 통해 전달된 트래픽과 로컬 폴백 요청 모두를 반영합니다. 백엔드가 continuum-router에서 비정상(unhealthy)으로 표시되면 서킷 상태가 열립니다.

동일한 병합 데이터는 get_routing_stats Tauri IPC 명령과 프론트엔드 스토어의 nodeStore.getRoutingStats() 액션을 통해서도 조회할 수 있습니다.

네트워크 노드 인증

요청이 네트워크 노드로 라우팅될 때 프록시는 Authorization: Bearer <api_key> 헤더를 추가합니다. API key는 로컬 노드 레지스트리에 안전하게 저장되며, 로그나 UI에 노출되지 않습니다.

네트워크 노드에 API key가 설정되어 있는지 확인하세요. 네트워크 노드가 인증을 요구하는 경우, API key가 없는 노드로의 요청은 실패합니다.

폴백 동작

조건 동작
부하 분산 비활성화 로컬에서만 처리, 모델이 실행 중이 아닌 경우 503 반환.
부하 분산 활성화, 모델이 로컬에 있음 로컬에서 처리.
부하 분산 활성화, 모델이 네트워크 노드에 있음 네트워크 노드로 전달.
부하 분산 활성화, 어디에도 모델 없음 503 서비스 이용 불가 반환.
네트워크 노드 연결 불가, 페일오버 활성화 대체 노드에서 한 번 다시 시도.
네트워크 노드 연결 불가, 페일오버 비활성화 업스트림 오류를 클라이언트에 반환.
노드 서킷 열림 라우팅 시 노드 건너뜀, 사용 가능한 경우 대체 노드 사용.

관련 페이지