パフォーマンスを改善させる



  • この記事は、Google Drive™ APIに関する記事を和訳したものです。
  • 原文: Improve performance
  • 元記事のライセンスは CC-BYで、この和訳記事のライセンスは CC-BYです。
  • 自己責任でご利用ください。
  • 和訳した時期は 2019年6月ころです。

このドキュメントでは、あなたのアプリケーションのパフォーマンスを改善させるために使用することができる、幾つかのテクニックについて説明します。 幾つかのケースでは、提示されたアイデアを示すために、他の APIあるいは汎用的な APIの例が使用されます。 しかしながら、Drive APIにも同じ概念が適用されています。

gzipを使用する

それぞれのリクエストのために必要とされる帯域幅を減少させるための簡単で便利な方法は、gzip圧縮を有効にすることです。 これは、結果を圧縮解除するために追加の CPU時間を必要としますが、ネットワークコストとのトレードオフは、通常、非常に価値があります。

gzipでエンコードされた応答を受け取るには、2つのことをしなければなりません: Accept-Encodingヘッダをセットし、文字列 gzipを含むよう、あなたのユーザエージェントを修正します。 gzip圧縮を有効にするための、適切な形式の HTTPヘッダの例を、次に示します:

Accept-Encoding: gzip
User-Agent: my program (gzip)

部分的なリソースを用いて動作させる

あなたの API呼び出しのパフォーマンスを改善するための別の方法は、関心を持つデータの一部のみをリクエストすることです。 これは、あなたのアプリケーションが、不要なフィールドを変換し、パースし、格納することを回避させるので、それは、ネットワーク、CPU、およびメモリをより効率的に使用できます。

部分的なレスポンス

デフォルトでは、サーバは、リクエストを処理した後、リソースの完全な表現を送り返します。 より良いパフォーマンスのために、本当に必要なフィールドのみを送信し、代わりに、部分的なレスポンスを取得するよう、サーバに依頼することができます。

部分的なレスポンスをリクエストするには、返して欲しいフィールドを指定するために、fieldsリクエストパラメータを使用します。 レスポンスデータを返す任意のリクエストとともに、このパラメータを使用することができます。

次の例は、汎用的な(架空の) "Demo" APIを用いて、fieldsパラメータを使用する方法を示しています。

シンプルリクエスト: この HTTP GETリクエストは fieldsパラメータを省略し、フルリソースを返します。

https://www.googleapis.com/demo/v1

フルリソースレスポンス: フルリソースのデータは、次のフィールドを含んでいます、それは、簡潔さのために省略されている多くの他のものとともにあります。

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

部分的なレスポンスのためのリクエスト: この同じリソースのための次のリクエストは、返されるデータの量を大幅に減らすために、fieldsパラメータを使用しています。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

部分的なレスポンス: 上記のリクエストへの応答には、サーバは、それぞれのアイテム内の HTMLタイトル(title)および長さ(length)の特性情報(characteristics)のみを含む、切り詰められたアイテム配列とともに種類(kind)情報のみを含むレスポンスを送り返します。

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

レスポンスは、選択されたフィールドおよびそれらの囲んでいる親オブジェクトのみを含む JSONオブジェクトであることに注意してください。

fieldsパラメータを形式する方法の詳細については、次に説明します、そこでは、レスポンスにて何が正確に返されるのかについて、より詳細に説明します。

Fieldsパラメータの構文の要約

fieldsリクエストパラメータ値の形式は、大まかに XPath構文に基づいています。 サポートされる構文は以下に要約されており、追加の例が、次のセクションにて提供されています。

  • 複数のフィールドを選択するために、コンマ区切りのリストを使用します。
  • フィールド a内にネストされているフィールド bを選択するために、a/bを使用します; b内にネストされているフィールド cを選択するために、a/b/cを使用します。

    例外: "data" ラッパーを使用する APIレスポンスの場合、そこでは、レスポンスは、data: { ... }のように見える dataオブジェクト内にネストされていますが、fields指定にて "data" を含まないでください。 data/a/bのようなフィールド指定を伴うデータオブジェクトを含むことは、エラーを引き起こします。 代わりに、a/bのような fields指定を使用してください。

  • カッコ "( )" 内に式を配置することによって、配列あるいはオブジェクトの特定のサブフィールドのセットをリクエストするために、サブセレクタを使用します。

    例えば: fields=items(id,author/email) は、アイテム配列内のそれぞれの要素の、アイテム IDおよび著者の電子メールのみを返します。 さらには、単一のサブフィールドを指定することができます、そこでは、 fields=items(id)fields=items/id と等価です。

  • 必要に応じて、フィールド選択にてワイルドカードを使用します。

    例えば: fields=items/pagemap/* は、ページマップ内のすべてのオブジェクトを選択します。

fieldパラメータを使用するより多くの例

以下の例は、fieldsパラメータ値がレスポンスにどのように影響するかについて説明しています。

備考: すべてのクエリパラメータ値と同様に、fieldsパラメータ値は URLエンコードされていなければなりません。 より読みやすくするために、このドキュメントでの例は、エンコーディングを省略しています。

返したいフィールドを識別する、あるいは フィールド選択を行います。
fieldsリクエストパラメータの値はコンマで区切られたフィールドのリストで、それぞれのフィールドは、レスポンスのルートに関連して指定されます。 したがって、もし list操作を実行しているならば、レスポンスはコレクションであり、それは通常、リソースの配列を含んでいます。 もし単一のリソースを返す操作を実行しているならば、fieldsは、そのリソースに関連して指定されます。 もし選択したフィールドが配列(あるいはその一部)であるなら、サーバは、その配列内のすべての要素の選択された部分を返します。

幾つかのコレクションレベルの例を以下に示します:
効果
items アイテム配列内のすべての要素を返します、それは、それぞれの要素のすべてのフィールドを含んでいますが、他のフィールドを含んでいません。
etag,items etagフィールドおよびアイテム配列内のすべての要素の両方を返します。
items/title アイテム配列内のすべての要素の titleフィールドのみを返します。

ネストされたフィールドが返されるときはいつでも、レスポンスは、囲んでいる親オブジェクトを含んでいます。 親フィールドは、それらが明示的に選択されない限り、他の子フィールドを含みません。
context/facets/label facets配列のすべてのメンバの labelのみを返します、それは、それ自体が contextオブジェクトの下にネストされています。
items/pagemap/*/title アイテム配列内のそれぞれの要素に対して、pagemapの子であるすべてのオブジェクトの titleフィールド(存在するならば)のみを返します。

リソースレベルの例を幾つか示します:
効果
title リクエストされたリソースの titleフィールドを返します。
author/uri リクエストされたリソースの authorオブジェクトの uriサブフィールドを返します。
links/*/href
linksの子であるすべてのオブジェクトの hrefフィールドを返します。
サブ選択を使用して、特定のフィールドの一部のみをリクエストします。
デフォルトでは、もしあなたのリクエストが特定のフィールドを指定しているならば、サーバは、オブジェクトあるいは配列要素の全体を返します。 特定のサブフィールドのみを含むレスポンスを指定することができます。 下の例のように、"( )" サブ選択構文を使用してこれを行います。
効果
items(title,author/uri) アイテム配列内のそれぞれの要素の titleおよび著者の uriの値のみを返します。

部分的なレスポンスを処理する

サーバが fieldsクエリパラメータを含む有効なリクエストを処理した後、それは、リクエストされたデータとともに、HTTP 200 OKステータスコードを送り返します。 もし fieldsクエリパラメータがエラーを持っている、あるいは無効であるならば、サーバは、それらのフィールドの選択の何が間違っていたかをユーザに示すエラーメッセージ(例えば、"Invalid field selection a/b")とともに、HTTP 400 Bad Requestステータスコードを返します。

部分的なレスポンスの例は、上記の入門セクションに示されています。 リクエストは、返すためのフィールドを指定するために fieldsを使用します。

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

部分的なレスポンスは次のようになります:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

備考: データのページネーションのためのクエリパラメータ(例えば、maxResultsnextPageToken)をサポートする APIの場合、それぞれのクエリの結果を管理可能なサイズに減少させるには、それらのパラメータを使用します。 そうしないと、部分的なレスポンスを用いて可能なパフォーマンスの向上が実現しないかもしれません。

gzip圧縮を用いてパフォーマンスを改善させる

Drive APIを用いてパフォーマンスを改善させることができる、幾つかの基本的な対策があります。 gzip圧縮を使用し、部分的なリソースを用いて動作させることは、パフォーマンスのヒントに詳しく説明されています。

リクエストをバッチ処理する

代わりに、対応する APIエンドポイント(www.googleapis.com/batch/api/version)に同様のバッチリクエストを使用するために、ブログ投稿の指示に従ってください。 Global HTTP Batch Endpoints (www.googleapis.com/batch)は、Google Developers blogpostで発表されているように、2019年3月25日に機能しなくなります。

このドキュメントでは、あなたのクライアントが行わなければならない HTTP接続の数を減らすために、API読み出しをまとめてバッチ処理する方法を示します。

このドキュメントでは、具体的には、HTTPリクエストを送信することによってバッチリクエストを行う方法について説明しています。 もし、代わりにバッチリクエストを行うために Googleクライアントライブラリを使用しているならば、クライアントライブラリのドキュメントを参照してください。

概要

あなたのクライアントが行うそれぞれの HTTP接続は、一定の量のオーバーヘッドを発生させます。 Drive APIはバッチをサポートし、それは、あなたのクライアントが、単一の HTTPリクエスト内に複数の API呼び出しをまとめることができるようにします。

バッチを使用したいときの状況の例:

  • 多数のファイルのメタデータを取得するとき。
  • 一括してメタデータあるいはプロパティを更新するとき。
  • 新しいユーザあるいはグループを追加するといった、多数のファイルのパーミッションを変更するとき。
  • 初めて、あるいは、長期間オフラインであった後に、ローカルのクライアントデータを同期させるとき。

いずれの場合も、それぞれの呼び出しを個別に送信する代わりに、単一の HTTPリクエスト内にそれらをまとめてグループ化することができます。 すべての内部のリクエストは、同じ Google APIに送信されなければなりません。

単一のバッチリクエストは、100回の呼び出しに制限されています。 もしそれより多くの呼び出しを行う必要があるならば、複数のバッチリクエストを使用します。

備考: Drive APIのためのバッチシステムは、OData batch processingシステムと同じ文法を使用しますが、セマンティクスは異なります。

備考: 100を超える API呼び出しを伴うバッチリクエストは、エラーになる可能性があります。

備考: それぞれの内部のリクエストのための URLの中長さの制限は、8,000キャラクタのです。

備考: 現在のところ、Google Driveは、アップロードあるいはダウンロードのいずれものための、メディアのためのバッチ操作をサポートしていません。

バッチ処理の詳細

バッチリクエストは、ひとつの HTTPリクエストに結合された複数の API呼び出しで構成されます、それは、API discovery documentに指定された batchPathに送信される可能性があります。 デフォルトパスは、/batch/api_name/api_versionです。 このセクションでは、バッチ構文について詳しく説明します; 後に、があります。

備考: 一度にバッチされる n個の一連のリクエストは、1つのリクエストではなく n個のリクエストとしてあなたの使用量の制限にカウントします。 バッチリクエストは、処理の前に、一連のリクエストに分割されます。

バッチリクエストの形式

バッチリクエストは、複数の Drive API呼び出しを含む単一の標準的な HTTPリクエストです、それは、multipart/mixedコンテンツタイプを使用します。 メインの HTTPリクエスト内に、それぞれの部分が、ネストされた HTTPリクエストを含んでいます。

それぞれの部分は、独自の Content-Type: application/http HTTPヘッダを伴って始まります。 さらには、オプションの Content-IDヘッダを持つこともできます。 しかしながら、部分のヘッダは部分の始まりをマークするためのものです; それらはネストされたリクエストとは別のものです。 サーバがバッチリクエストを個別のリクエストにラップ解除した後、部分のヘッダは無視されます。

それぞれの部分のボディは、それ自身、完全な HTTPリクエストです、それは、独自の動詞、URL、ヘッダ、およびボディを伴っています。 HTTPリクエストは、URLのパス部分のみを含んでいなければなりません; フルな URLは、バッチリクエストでは許可されていません。

外側のバッチリクエストのためのHTTPヘッダは、Content-Typeといった Content-ヘッダを除き、バッチ内のすべてのリクエストに適用されます。 もし外側のリクエストおよび個々の呼び出しの両方に特定の HTTPヘッダを指定するならば、個々の呼び出しのヘッダの値は、外側のバッチのリクエストのヘッダの値を上書きします。 個々の呼び出しのためのヘッダは、その呼び出しにのみ適用されます。

例えば、もし特定の呼び出しのために Authorizationヘッダを提供するならば、そのヘッダはその呼び出しにのみ適用されます。 もし外側のリクエストのために Authorizationヘッダを提供するならば、そのヘッダは、それらがそれら独自の Authorizationヘッダを用いてそれを上書きしない限りは、個々の呼び出しのすべてに適用されます。

サーバがバッチされたリクエストを受け取るとき、それは、外側のリクエストのクエリパラメータおよびヘッダをそれぞれの部分に(適切な場合に)適用し、それから、それが個別の HTTTPリクエストであったかのように、それぞれの部分を扱います。

バッチリクエストへのレスポンス

サーバのレスポンスは、multipart/mixedコンテンツタイプを伴う、単一の標準的な HTTPレスポンスです; それぞれの部分は、バッチされたリクエスト内の 1つのリクエストへのレスポンスです、それは、リクエストと同じ順序です。

リクエスト内の部分のように、それぞれのレスポンス部分は、完全な HTTPレスポンスを含んでいます、それは、ステータスコード、ヘッダ、およびボディを含みます。 そして、リクエスト内の部分にように、それぞれのレスポンス部分の前には、部分の開始を示す Content-Typeヘッダが付いています。

もしリクエストの特定の部分が Content-IDヘッダを持っていたならば、レスポンスの対応する部分は、マッチする Content-IDヘッダを持っています、それは、次の例に示すように、元の値の前に文字列 response-が付いています。

備考: サーバは、あなたの呼び出しを任意の順序で実行するかもしれません。 それらを指定した順に、それらが実行されることをあてにしないでください。 もし 2つの呼び出しが指定された順序で発生することを保証したければ、単一のリクエストにてそれらを送信することはできません; 代わりに、最初のものを単独で送信し、それから、2番目のものを送信する前に、最初のものへのレスポンスを待ってください。

次の例は、Drive APIを用いてバッチを使用する方法を示しています。

バッチリクエストの例

POST https://www.googleapis.com/batch/drive/v3
Accept-Encoding: gzip
User-Agent: Google-HTTP-Java-Client/1.20.0 (gzip)
Content-Type: multipart/mixed; boundary=END_OF_PART
Content-Length: 963

--END_OF_PART Content-Length: 337 Content-Type: application/http content-id: 1 content-transfer-encoding: binary

POST https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id Authorization: Bearer authorization_token Content-Length: 70 Content-Type: application/json; charset=UTF-8

{ "emailAddress":"example@appsrocks.com", "role":"writer", "type":"user" } --END_OF_PART Content-Length: 353 Content-Type: application/http content-id: 2 content-transfer-encoding: binary

POST https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id&sendNotificationEmail=false Authorization: Bearer authorization_token Content-Length: 58 Content-Type: application/json; charset=UTF-8

{ "domain":"appsrocks.com", "role":"reader", "type":"domain" } --END_OF_PART--

バッチレスポンスの例

これは、前のセクション内のリクエスト例へのレスポンスです。

HTTP/1.1 200 OK
Alt-Svc: quic=":443"; p="1"; ma=604800
Server: GSE
Alternate-Protocol: 443:quic,p=1
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
X-XSS-Protection: 1; mode=block
Content-Type: multipart/mixed; boundary=batch_6VIxXCQbJoQ_AATxy_GgFUk
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
Date: Fri, 13 Nov 2015 19:28:59 GMT
Cache-Control: private, max-age=0
Vary: X-Origin
Vary: Origin
Expires: Fri, 13 Nov 2015 19:28:59 GMT

--batch_6VIxXCQbJoQ_AATxy_GgFUk Content-Type: application/http Content-ID: response-1

HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 Date: Fri, 13 Nov 2015 19:28:59 GMT Expires: Fri, 13 Nov 2015 19:28:59 GMT Cache-Control: private, max-age=0 Content-Length: 35

{ "id": "12218244892818058021i" }

--batch_6VIxXCQbJoQ_AATxy_GgFUk Content-Type: application/http Content-ID: response-2

HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 Date: Fri, 13 Nov 2015 19:28:59 GMT Expires: Fri, 13 Nov 2015 19:28:59 GMT Cache-Control: private, max-age=0 Content-Length: 35

{ "id": "04109509152946699072k" }

--batch_6VIxXCQbJoQ_AATxy_GgFUk--