Spanner 遠端函式

Spanner 遠端函式可讓您以 SQL 以外的語言實作函式。函式必須託管在 Cloud Run functions Cloud Run 中。以這種方式代管函式,可將複雜的商業邏輯拆分成個別的遠端函式。

一般遠端函式部署作業的步驟如下:

  1. 在 Cloud Run 函式或 Cloud Run 中建立 HTTPS 端點

    • 如果您不熟悉遠端函式,建議使用 Cloud Run 函式。
  2. 在 Spanner 中建立遠端函式,指向該 HTTPS 端點。

  3. 在查詢中使用遠端函式

必要的角色

為確保 Spanner 代理程式服務帳戶 (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) 具備使用 Spanner 遠端函式的必要權限,請管理員將專案的「Spanner API 服務代理程式」 (roles/spanner.serviceAgent) IAM 角色授予 Spanner 代理程式服務帳戶 (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com)。

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和機構的存取權」。

管理員也可以將 Spanner 代理程式服務帳戶 (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) 自訂角色或其他預先定義的角色,取得必要權限。

支援的類型

遠端函式支援下列資料類型做為引數或傳回類型:

  • ARRAY (下列任一支援類型)
  • BOOLEAN
  • BYTES
  • DATE
  • JSON
  • INTEGER
  • NUMERIC
  • STRING
  • TIMESTAMP

限制

  • 您無法建立資料表值遠端函式。

  • 產生的資料欄運算式不支援遠端函式。

  • 由於暫時性網路錯誤或 Spanner 內部重新啟動,您可能會看到系統重複向端點傳送相同資料的請求,有時甚至在成功回應後也會發生這種情況。

  • 系統不支援在分數 Spanner 執行個體中執行遠端函式。

  • 自訂網域後方的 Cloud Run 函式不支援遠端函式。

  • PostgreSQL 方言不支援遠端函式。

建立端點

您必須將業務邏輯實作為 Cloud Run 函式或 Cloud Run。端點必須能夠在單一 HTTPS POST 要求中處理一批資料列,並以 HTTPS 回應的形式傳回該批資料的結果。

如果您已為 BigQuery 建立遠端函式,可以重複用於 Spanner。

如要瞭解如何編寫、部署、測試及維護 Cloud Run functions,請參閱 Cloud Run functions 教學課程和其他 Cloud Run functions 說明文件

如要瞭解如何編寫、部署、測試及維護 Cloud Run 服務,請參閱 Cloud Run 快速入門和其他 Cloud Run 說明文件

建議您為 Cloud Run 函式或 Cloud Run 服務保留預設驗證。請勿將服務設為允許未經驗證的叫用。

輸入格式

Spanner 會傳送 HTTPS POST 要求,並以 JSON 格式提供主體,格式如下:

欄位名稱 說明 欄位類型
requestId 要求 ID。在 GoogleSQL 查詢中傳送至端點的多個要求中,此值必須是唯一的。 一律提供。字串。
calls 一批輸入資料。 一律提供。JSON 陣列。

每個元素都是 JSON 陣列,代表單一遠端函式呼叫的 JSON 編碼引數清單。

要求範例:

// Sample request to a Cloud Run functions to calculate sum of two numbers. This request
// has two calls batched together into a single request.
{
 "requestId": "124ab1c",
 "calls": [
  [1, 2],
  [3, 4]
 ]
}

輸出格式

Spanner 預期端點會傳回下列格式的 HTTPS 回應;否則,Spanner 無法使用該回覆,且查詢會因呼叫遠端函式而失敗。

欄位名稱 說明 值範圍
replies 一批傳回值。 JSON 陣列。

每個元素都對應至外部函式的 JSON 編碼回傳值。

陣列大小必須與 HTTPS 要求中 calls 的 JSON 陣列大小相符。舉例來說,如果 calls 中的 JSON 陣列有 4 個元素,這個 JSON 陣列也必須有 4 個元素。這是成功回應的必要條件。
errorMessage 系統傳回的 HTTPS 回應碼不是 200 時,顯示的錯誤訊息。對於無法重試的錯誤,Spanner 會向使用者傳回這則錯誤訊息。失敗的回應中必須提供這項資訊。通常不到 1 KB。 字串。

成功回應範例如下:

// Sample response from the Cloud Run functions which has the sum of the two numbers. Note
// that the order of the values within `replies` field matches the `calls` field from
// the request.
{
  "replies": [
    3,  // 1 + 2 = 3
    7   // 3 + 4 = 7
  ]
}

失敗的回應範例如下:

{
  // The error message returned by your Cloud Run functions to indicate an error.
  // In this sample, the error message states that an overflow occurred when summing two numbers.
  "errorMessage": "Overflow detected when calculating sum of two numbers."
}

HTTPS 回應代碼

端點會針對成功的回應傳回 200 HTTPS 程式碼。如果 Spanner 收到任何其他值,就會將該回應視為失敗,並在 HTTPS 回應代碼為 408、429、500、503 或 504 時重試,直到達到內部限制為止。

程式碼範例

Cloud Run 函式

下列 Python 程式碼範例會實作新增遠端函式的所有整數引數。這個函式會處理要求,其中包含批次呼叫的引數,並在回應中傳回所有結果。

"""
Python script which uses Flask framework to spin up a HTTP server to take
integers and return their sum. In case of overflow, it returns the error
as part of the response.
"""
import functions_framework

from flask import jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
_MAX_LOSSLESS=9007199254740992

@functions_framework.http
def batch_add(request):
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return_json = jsonify( { "replies":  replies } )
    return return_json
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

假設函式部署在專案 PROJECT_ID us-east1 區域,且函式名稱為 remote_add,則可使用端點 https://us-east1-PROJECT_ID.cloudfunctions.net/remote_add 存取。

Cloud Run

下列 Python 程式碼範例會實作網路服務,可建構及部署至 Cloud Run,提供相同功能。

"""
Python script which uses Flask framework to spin up a HTTP server to take
integers and return their sum. In case of overflow, it returns the error
as part of the response.
"""
import os

from flask import Flask, request, jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
_MAX_LOSSLESS=9007199254740992

app = Flask(__name__)

@app.route("/", methods=['POST'])
def batch_add():
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return jsonify( { "replies" :  replies } )
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

如要建構及部署程式碼,請參閱「快速入門:在 Cloud Run 中建構及部署 Python (Flask) 網頁應用程式」。

假設 Cloud Run 服務部署在專案 PROJECT_IDus-east1 區域,且服務名稱為 remote_add,則可使用端點 https://remote_add-<project_id_hash>-ue.a.run.app 存取。

建立遠端函式

如要建立遠端函式,請按照下列指示操作:

SQL

在 Spanner 中執行下列 CREATE FUNCTION 陳述式:

CREATE FUNCTION REMOTE_FUNCTION_NAME(x INT64, y INT64) RETURNS INT64 NOT DETERMINISTIC LANGUAGE REMOTE OPTIONS (
  endpoint = `ENDPOINT_URL`,
  max_batching_rows = MAX_BATCHING_ROWS
);

更改下列內容:

  • REMOTE_FUNCTION_NAME:遠端函式名稱。例如:sum_func
  • ENDPOINT_URL:先前步驟中建立的 Cloud Run functions 或 Cloud Run 端點。
  • MAX_BATCHING_ROWS (選填):要求中要傳送的資料列數量上限。如未指定,Spanner 會自動判斷批次大小。

在查詢中使用遠端函式

如要在查詢中呼叫上一個步驟的遠端函式,請使用下列範例:

SELECT REMOTE_FUNCTION_NAME(1, 2); -- 1 + 2 = 3

定價

  • 適用標準 Spanner 定價

  • Spanner 會針對傳送至 Cloud Run functions/Cloud Run 或從中接收的位元組計費。

  • 這項功能可能會產生 Cloud Run functions 和 Cloud Run 的費用。詳情請參閱「Cloud Run functions」和「 Cloud Run」定價頁面。