일괄 요청

전역 일괄 HTTP 엔드포인트 지원 중단으로 인해 BigQuery API만 대상으로 하는 일괄 HTTP 요청도 2021년 6월 1일에 중단됩니다. 애플리케이션에서 일괄 HTTP 요청을 보내는 경우 2021년 6월 1일 전에 일괄 HTTP 요청을 개별 HTTP 요청으로 교체합니다.

지원 중단에 대한 자세한 내용은 다음 FAQ 섹션을 참조하세요. HTTP 요청을 일괄 처리하는 방법에 대한 문서는 요청 일괄 처리를 참조하세요.

BigQuery 일괄 HTTP API 지원 중단 FAQ

BigQuery 일괄 HTTP 요청이 지원 중단되는 이유는 무엇인가요?

전역 HTTP 배치 엔드포인트 지원은 단일 공유 프록시를 사용하여 모든 API에 대한 요청을 수신하는 아키텍처를 기반으로 했습니다. Google은 요청이 적절한 API 서버로 직접 전달되는 보다 분산된 고성능 아키텍처로 이전하면서 더 이상 이러한 글로벌 엔드포인트를 지원하지 않습니다.

BigQuery 일괄 HTTP 요청 지원 중단은 다음 단계입니다. BigQuery 서비스도 배포됩니다. 높은 QPS 메서드는 전용 백엔드에서 처리됩니다. 모든 리전은 격리되지만 일괄 HTTP 요청은 리전 간 요청 팬아웃을 유발할 수 있습니다. 이렇게 하면 일괄 처리가 비효율적이며 일괄 HTTP 요청 지원의 원래 목표에 상쇄되어 처리 지연 시간이 길어질 수 있습니다.

구체적으로 무엇이 지원 중단되나요?

다음과 같은 일괄 요청 메서드는 BigQuery API와 상호작용하지 않게 됩니다.

마이그레이션하려면 어떻게 해야 하나요?

대부분의 BigQuery 사용자는 일괄 HTTP 요청을 사용하지 않습니다. 일괄 요청을 사용 중인 경우 다음 예시를 사용하여 일괄 HTTP 요청을 개별 HTTP 요청으로 바꾸세요.

REST

BigQuery API 참조 섹션에 설명된 대로 개별 HTTP 요청을 전송합니다. /batch/v2/bigquery 경로를 사용하여 요청을 일괄적으로 결합하지 마세요.

자바스크립트

자바스크립트를 사용하는 경우 다음과 같은 코드 블록으로 시작합니다.

// Notice that the outer batch request contains inner API requests
// for two different APIs.

// Request to urlshortener API
request1 = gapi.client.urlshortener.url.get({"shortUrl":
"http://goo.gl/fbsS"});

// Request to zoo API
request2 = gapi.client.zoo.animals.list();

// Request to urlshortener API
request3 = gapi.client.urlshortener.url.get({"shortUrl":
"https://goo.gl/XYFuPH"});

// Request to zoo API
request4 = gapi.client.zoo.animal().get({"name": "giraffe"});

// Creating a batch request object
batchRequest = gapi.client.newBatch();
// adding the 4 batch requests
batchRequest.add(request1);
batchRequest.add(request2);
batchRequest.add(request3);
batchRequest.add(request4);
// print the batch request
batchRequest.then(x=>console.log(x))

앞의 코드 블록을 다음과 같은 코드 블록으로 바꿉니다.

// Request to urlshortener API
request1 = gapi.client.urlshortener.url.get({"shortUrl": "http://goo.gl/fbsS"});

// Request to zoo API
request2 = gapi.client.zoo.animals.list();

// Request to urlshortener API
request3 = gapi.client.urlshortener.url.get({"shortUrl": "http://goo.gl/fbsS"})

// Request to zoo API
request4 = gapi.client.zoo.animals.list();

// print the 4 individual requests
Promise.all([request1, request2, request3, request4])
    .then(x=>console.log(x));

Python

Python을 사용하는 경우 다음과 같은 코드 블록으로 시작합니다.

from apiclient.http import BatchHttpRequest

def insert_animal(request_id, response, exception):
  if exception is not None: # Do something with the exception
    pass
  else: # Do something with the response
    pass

service = build('farm', 'v2')
batch = service.new_batch_http_request(callback=insert_animal)
batch.add(service.animals().insert(name="sheep"))
batch.add(service.animals().insert(name="pig"))
batch.add(service.animals().insert(name="llama"))
batch.execute(http=http)

앞의 코드 블록을 다음과 같은 코드 블록으로 바꿉니다.

# import a new API to create a thread pool
from concurrent.futures import ThreadPoolExecutor as PoolExecutor

def run_it(request):
  print(request.execute())

service = build('farm', 'v2')
request1 = service.animals().insert(name="sheep")
request2 = service.animals().insert(name="pig")
request3 = service.animals().insert(name="llama")
with PoolExecutor(max_workers=4) as executor:
  for _ in executor.map(run_it,[request1, request2, request3]):
    pass

기타 언어

앞의 예시와 마찬가지로 BatchRequest 호출을 개별 요청으로 바꿉니다.

마이그레이션 지원 받기

마이그레이션과 관련하여 도움이 필요하면 Stack Overflow에서 질문할 수 있습니다. Google 엔지니어는 google-bigquery 태그를 사용하여 질문을 모니터링하고 답변합니다. 질문할 때는 이 태그를 사용하세요. Google은 가능한 이른 기간 내에 모든 질문에 답변해 드리려고 합니다.

요청 일괄 처리

이 문서에서는 API 호출을 일괄 처리하여 클라이언트가 수행해야 하는 HTTP 연결 수를 줄이는 방법을 보여줍니다.

이 문서에서는 특히 HTTP 요청을 보내 일괄 요청을 하는 방법을 다룹니다. Google 클라이언트 라이브러리를 사용하여 일괄 요청을 하는 경우 클라이언트 라이브러리의 문서를 참조하세요.

개요

클라이언트가 수행하는 각 HTTP 연결에는 어느 정도의 오버헤드가 수반됩니다. BigQuery API는 일괄 처리를 지원하므로 클라이언트에서 단일 HTTP 요청에 여러 개의 API 호출을 넣을 수 있습니다.

다음과 같은 경우에 일괄 처리를 사용할 수 있습니다.

  • API를 이제 막 사용하기 시작했고 업로드할 데이터가 많습니다.
  • 애플리케이션이 오프라인인 상태에서(인터넷 연결이 끊김) 사용자가 데이터를 변경했기 때문에 애플리케이션에서 많은 업데이트와 삭제를 전송하여 로컬 데이터와 서버를 동기화해야 합니다.

각각의 경우 각 호출을 개별적으로 보내는 대신 단일 HTTP 요청으로 그룹화할 수 있습니다. 내부 요청은 모두 동일한 Google API로 이동해야 합니다.

일괄 요청 1개에 포함할 수 있는 호출 수는 1,000개로 제한됩니다. 더 많이 호출해야 하는 경우 일괄 요청을 여러 개 사용합니다.

참고: BigQuery API용 일괄 처리 시스템은 OData 일괄 처리 시스템과 동일한 구문을 사용하지만 시맨틱스는 다릅니다.

일괄 처리 세부정보

일괄 요청은 하나의 HTTP 요청으로 결합된 여러 API 호출로 구성되며, 이 요청을 API 검색 문서에 지정된 batchPath로 보낼 수 있습니다. 기본 경로는 /batch/api_name/api_version입니다. 이 섹션에서는 일괄 처리 구문을 세부적으로 설명하며 뒷부분에서 예시를 제시합니다.

참고: 일괄 처리된 n개 요청의 사용량 한도를 계산할 때는 요청 하나가 아니라 n개로 계산됩니다. 일괄 요청은 일련의 요청 집합으로 분리된 후 처리됩니다.

일괄 요청의 형식

일괄 요청은 여러 개의 BigQuery API 호출이 포함된 단일 표준 HTTP 요청이며, multipart/mixed 콘텐츠 유형을 사용합니다. 이 기본 HTTP 요청 내의 각 부분에 중첩된 HTTP 요청이 포함됩니다.

각 부분은 자체 Content-Type: application/http HTTP 헤더로 시작됩니다. 선택사항인 Content-ID 헤더가 있는 경우도 있습니다. 그러나 부분 헤더는 부분의 시작을 표시하기 위해 있을 뿐이며 중첩된 요청과는 별개입니다. 서버에서 일괄 요청을 개별 요청으로 해체하면 부분 헤더는 무시됩니다.

각 부분의 본문은 자체 동사와 URL, 헤더, 본문을 포함하며 그 자체로 완전한 HTTP 요청입니다. HTTP 요청은 URL의 경로 부분만 포함해야 합니다. 전체 URL은 일괄 요청에서 허용되지 않기 때문입니다.

외부 일괄 요청의 HTTP 헤더(Content-Type과 같은 Content- 헤더 제외)는 일괄 처리되는 각 요청에 모두 적용됩니다. 특정 HTTP 헤더를 외부 요청과 개별 호출에 모두 지정하는 경우 개별 호출 헤더의 값이 외부 일괄 요청 헤더의 값을 재정의합니다. 개별 호출의 헤더는 해당 호출에만 적용됩니다.

예를 들어 특정 호출에 승인 헤더를 제공하는 경우 이 헤더는 해당 호출에만 적용됩니다. 외부 요청에 승인 헤더를 제공하는 경우 이 헤더는 개별 호출에서 자체 승인 헤더로 재정의하지 않는 이상 모든 개별 호출에 적용됩니다.

서버는 일괄 요청을 수신하면 외부 요청의 쿼리 매개변수와 헤더를 각 부분에 적절히 적용한 다음 각 부분을 개별 HTTP 요청처럼 취급합니다.

일괄 요청 응답

서버 응답은 multipart/mixed 콘텐츠 유형의 단일 표준 HTTP 응답입니다. 각 부분은 일괄 요청에 포함된 요청 중 하나에 대한 응답이며 요청 순서와 동일한 순서로 표시됩니다.

요청의 부분과 마찬가지로 각 응답 부분에는 상태 코드, 헤더, 본문을 포함한 완전한 HTTP 응답이 포함됩니다. 또한 요청의 부분과 마찬가지로 각 응답 부분 앞에는 Content-Type 헤더가 붙어 부분의 시작을 표시합니다.

요청의 특정 부분에 Content-ID 헤더가 있는 경우 해당하는 응답 부분에도 일치하는 Content-ID 헤더가 표시되며 원래 값 앞에는 문자열 response-가 붙습니다(다음 예시 참조).

참고: 서버는 호출을 임의의 순서로 수행할 수 있습니다. 지정한 순서에 따라 실행된다고 생각하면 안 됩니다. 2개의 호출이 지정된 순서에 따라 실행되도록 하려면 1개의 요청으로 두 호출을 보내면 안 됩니다. 첫 번째 호출을 단독으로 보낸 다음 첫 번째 호출의 응답을 기다렸다가 두 번째 호출을 보내야 합니다.

예시

다음은 Farm API라는 일반(가상의) 데모 API에 일괄 요청을 사용하는 예시입니다. 같은 개념이 BigQuery API에도 적용됩니다.

일괄 요청 예시

POST /batch/farm/v1 HTTP/1.1
Authorization: Bearer your_auth_token
Host: www.googleapis.com
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item1:12930812@barnyard.example.com>

GET /farm/v1/animals/pony

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:12930812@barnyard.example.com>

PUT /farm/v1/animals/sheep
Content-Type: application/json
Content-Length: part_content_length
If-Match: "etag/sheep"

{
  "animalName": "sheep",
  "animalAge": "5"
  "peltColor": "green",
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <item3:12930812@barnyard.example.com>

GET /farm/v1/animals
If-None-Match: "etag/animals"

--batch_foobarbaz--

일괄 응답 예시

이전 섹션의 요청 예시에 대한 응답입니다.

HTTP/1.1 200
Content-Length: response_total_content_length
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item1:12930812@barnyard.example.com>

HTTP/1.1 200 OK
Content-Type application/json
Content-Length: response_part_1_content_length
ETag: "etag/pony"

{
  "kind": "farm#animal",
  "etag": "etag/pony",
  "selfLink": "/farm/v1/animals/pony",
  "animalName": "pony",
  "animalAge": 34,
  "peltColor": "white"
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item2:12930812@barnyard.example.com>

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: response_part_2_content_length
ETag: "etag/sheep"

{
  "kind": "farm#animal",
  "etag": "etag/sheep",
  "selfLink": "/farm/v1/animals/sheep",
  "animalName": "sheep",
  "animalAge": 5,
  "peltColor": "green"
}

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item3:12930812@barnyard.example.com>

HTTP/1.1 304 Not Modified
ETag: "etag/animals"

--batch_foobarbaz--