在不同的 Cloud Storage 值區之間執行移轉

您可以使用 Storage 移轉服務,在同一個 Google Cloud 專案內或不同專案之間,傳輸大量資料至 Cloud Storage 值區。

在許多情況下,桶分別都很實用。您可以使用這些指令碼合併來自不同專案的資料、將資料移至備份位置,或變更資料的位置。

使用 Storage 移轉服務的時機

Google Cloud 提供多種方法,可在 Cloud Storage 值區之間轉移資料。我們建議遵循下列準則:

  • 轉移資料量少於 1 TB:請使用 gcloud。如需操作說明,請參閱「移動及重新命名值區」一文。

  • 轉移超過 1 TB 的資料:請使用 Storage 移轉服務。Storage 移轉服務是受管理的移轉選項,可提供即用型安全性、可靠性和效能。因此不必最佳化及維護指令碼,也不必處理重試。

本指南將說明使用 Storage 移轉服務在 Cloud Storage 值區間轉移資料時的最佳做法。

定義轉移策略

轉移策略的形式取決於情況的複雜度。請務必在企劃書中納入下列考量。

選擇值區名稱

如要將資料移至其他位置的儲存空間值區,請選擇下列任一做法:

  • 新的值區名稱。更新應用程式,以便指向名稱不同的儲存空間值區。
  • 保留值區名稱。替換儲存體值區,保留目前名稱,這表示您不需要更新應用程式。

無論是哪種情況,您都應預先規劃停機時間,並適當通知使用者即將發生停機時間。請參閱以下說明,瞭解哪個選項最適合您。

新值區名稱

使用新的值區名稱時,您必須更新所有使用目前值區的程式碼和服務。這項操作的方式取決於應用程式的建構和部署方式。

對於某些設定而言,這種做法可能可縮短停機時間,但需要進行更多工作才能確保順利轉換。其中包含下列步驟:

  1. 將資料複製到新的儲存空間值區。
  2. 開始休息時間。
  3. 更新應用程式,使其指向新的值區。
  4. 確認所有項目皆依照預期運作,且所有相關系統和帳戶都能存取該值區。
  5. 刪除原始值區。
  6. 結束休息時間。

保留值區名稱

如果您不想變更程式碼,以便指向新的桶名,請使用此方法。其中包含下列步驟:

  1. 將資料複製到暫存值區。
  2. 開始休息時間。
  3. 刪除原始值區。
  4. 建立名稱與原始值區相同的新值區。
  5. 將資料從暫時值區複製到新值區。
  6. 刪除臨時值區。
  7. 確認所有項目皆依照預期運作,且所有相關系統和帳戶都能存取該值區。
  8. 結束休息時間。

將停機時間減至最低

Storage 移轉服務不會在轉移期間鎖定來源或目的地值區的讀取或寫入作業。

如果您選擇手動鎖定儲存桶的讀取/寫入作業,可以透過兩個步驟 (初始化和同步處理) 轉移資料,盡量減少停機時間。

  1. 種子轉移:在來源上執行大量轉移作業,但不鎖定讀取/寫入。

  2. 同步轉移:第一次執行完成後,請鎖定來源儲存桶的讀/寫權限,然後執行另一次轉移作業。Storage 移轉服務的傳輸作業預設為增量傳輸,因此這次的第二次傳輸作業只會傳輸在初始傳輸作業期間變更的資料。

提升傳輸速度

在估算轉移作業所需的時間時,請考量可能的瓶頸。舉例來說,如果來源有數十億個小檔案,傳輸速度就會受到 QPS 限制。如果物件大小很大,頻寬可能會成為瓶頸。

頻寬限制是在區域層級設定,並在所有專案中公平分配。如果有足夠的頻寬,Storage 移轉服務每秒可完成約 1000 個移轉工作任務。在這種情況下,您可以將工作拆分成多個小型移轉工作,例如使用納入和排除前置字串來轉移特定檔案,藉此加快移轉作業。

如果位置、儲存空間類別和加密金鑰相同,Storage 移轉服務不會建立新的位元組副本,而是建立指向來源 blob 的新中繼資料項目。因此,同一個大規模字典庫的相同位置和類別副本會非常快速完成,且只受 QPS 限制。

刪除也是僅限中繼資料的作業。對於這類轉移作業,您可以將轉移作業拆分成多項小型工作,以便並行執行,藉此加快速度。

保留中繼資料

使用 Storage 移轉服務在 Cloud Storage 值區之間轉移資料時,系統會保留下列物件中繼資料:

  • 使用者建立的自訂中繼資料
  • Cloud Storage 固定鍵中繼資料欄位,例如 Cache-Control、Content-Disposition、Content-Type 和 Custom-Time。
  • 物件大小。
  • 「Generation number」會以自訂中繼資料欄位保留,並使用鍵 x-goog-reserved-source-generation,您之後可以編輯或移除該欄位。

使用 API 進行轉移時,可選擇保留下列中繼資料欄位:

  • 存取控制清單 (acl)
  • 儲存空間級別 (storageClass)
  • CMEK (kmsKey)
  • 暫時性保留 (temporaryHold)
  • 物件建立時間 (customTime)

詳情請參閱 TransferSpec API 參考資料

系統不會保留下列中繼資料欄位:

  • 上次更新時間 (updated)
  • etag
  • componentCount

如果保留,物件建立時間會儲存為自訂欄位 customTime。物件的 updated 時間會在轉移時重設,因此物件在儲存空間級別中停留的時間也會重設。也就是說,在轉移後,Coldline Storage 中的物件必須在目的地再次存在 90 天,才能避免產生提前刪除費用。

您可以使用 customTime 套用以 createTime 為基礎的生命週期政策。現有的 customTime 值會遭到覆寫。

如要進一步瞭解哪些項目會保留,哪些項目不會保留,請參閱「中繼資料保留」一文。

處理版本化物件

如果您想轉移儲存空間物件的所有版本 (而非僅限最新版本),就必須使用 gcloud CLI 或 REST API 轉移資料,並搭配 Storage Transfer Service 的資訊清單功能

如要轉移所有物件版本,請按照下列步驟操作:

  1. 列出值區物件,並將這些物件複製到 JSON 檔案中:

    gcloud storage ls --all-versions --recursive --json [SOURCE_BUCKET] > object-listing.json
    

    這個指令通常每秒會列出約 1,000 個物件。

  2. 將 JSON 檔案拆分為兩個 CSV 檔案,一個檔案包含非最新版本,另一個則包含最新版本:

    jq -r '.[] | select( .type=="cloud_object" and (.metadata | has("timeDeleted") | not)) | [.metadata.name, .metadata.generation] | @csv' object-listing.json > live-object-manifest.csv
    jq -r '.[] | select( .type=="cloud_object" and (.metadata | has("timeDeleted"))) | [.metadata.name, .metadata.generation] | @csv' object-listing.json > non-current-object-manifest.csv
    
  3. 在目的地值區啟用物件版本管理

  4. 首先將非目前版本移轉,方法是將 non-current-object-manifest.csv 資訊清單檔案傳遞為 transferManifest 欄位的值

  5. 接著,以相同方式轉移實際版本,並指定 live-object-manifest.csv 做為資訊清單檔案。

設定轉移選項

設定轉移作業時,您可以使用下列部分選項:

  • 記錄:Cloud Logging 提供個別物件的詳細記錄,讓您驗證轉移狀態並執行其他資料完整性檢查。

  • 篩選:您可以使用納入和排除前置字串,限制 Storage 移轉服務可在哪些物件上執行。這個選項可用來將轉移作業分割成多個轉移工作,以便並行執行。詳情請參閱「最佳化傳輸速度」。

  • 移轉選項:您可以設定移轉作業,以便覆寫目標值區中的現有項目、刪除目標中不存在於移轉集的物件,或是從來源刪除已移轉的物件。

轉移資料

定義轉移策略後,您就可以執行轉移作業。

建立新 Bucket

開始移轉作業前,請建立儲存空間值區。如要瞭解如何選擇適當的值區位置,請參閱location_considerations

建立新值區時,您可能會想要複製部分值區中繼資料。請參閱「取得值區中繼資料」,瞭解如何顯示來源值區的中繼資料,以便將相同設定套用至新值區。

將物件複製到新 bucket

您可以使用Google Cloud 主控台、gcloud CLI、REST API 或用戶端程式庫,將來源儲存桶中的物件複製到新的儲存桶。您採用的做法取決於轉移策略

以下操作說明適用於將物件從一個值區轉移至另一個值區的基本用途,您應視需求加以修改。

請勿在轉移作業名稱中加入個人識別資訊 (PII) 或安全性資料等機密資訊。資源名稱可能會傳播至其他 Google Cloud 資源的名稱,並可能會公開給專案以外的 Google 內部系統。

Google Cloud 控制台

請在Google Cloud 主控台中使用 Cloud Storage 移轉服務

  1. 在 Google Cloud 控制台中開啟「移轉」頁面。

    開啟「移轉」頁面

  2. 按一下 [Create transfer job] (建立移轉工作)
  3. 按照逐步操作說明,在完成每個步驟時按一下「Next step」

    • 開始使用:將 Google Cloud Storage 做為來源類型目的地類型

    • 選擇來源:直接輸入所需值區的名稱,或按一下「瀏覽」,找出並選取所需值區。

    • 選擇目的地:直接輸入所需值區的名稱,或按一下「瀏覽」,找出並選取所需值區。

    • 選擇設定:選取「轉移檔案後,請從來源刪除檔案」

    • 排程選項:您可以忽略這部分。

  4. 逐步完成操作後,請按一下[Create](建立)

    如此將物件從舊值區複製到新值區的流程即會開始。這個流程可能需要一些時間;不過在按一下「建立」後,您就可以離開 Google Cloud 主控台。

    如要查看移轉進度:

    在 Google Cloud 控制台中開啟「移轉」頁面。

    開啟「移轉」頁面

    如要瞭解如何取得 Google Cloud 控制台 中 Storage Transfer Service 失敗作業的詳細錯誤資訊,請參閱排解問題

  5. 如果您在設定期間選取了「轉移作業完成後刪除來源物件」核取方塊,轉移作業完成後,您不需要採取任何行動,即可刪除舊值區中的物件。不過,您可能也想刪除舊的儲存桶,這項操作必須另外執行。

gcloud CLI

安裝 gcloud CLI

如果您尚未安裝,請安裝 gcloud 指令列工具

接著,請呼叫 gcloud init 來初始化工具,並指定專案 ID 和使用者帳戶。如需詳細資訊,請參閱「初始化 Cloud SDK」。

gcloud init

將服務帳戶新增至目的地資料夾

您必須先將 Storage 移轉服務的服務帳戶新增至目的地值區,才能建立移轉作業。如要這麼做,請使用 gcloud storage buckets add-iam-policy-binding

gcloud storage buckets add-iam-policy-binding gs://bucket_name \
--member=serviceAccount:project-12345678@storage-transfer-service.iam.gserviceaccount.com \
--role=roles/storage.admin

如需使用 Google Cloud 主控台或 API 的操作說明,請參閱 Cloud Storage 說明文件中的「使用 IAM 權限」一節。

建立轉移工作

如要建立新的移轉工作,請使用 gcloud transfer jobs create 指令。建立新工作會啟動指定的轉移作業,除非您指定了排程或 --do-not-run

gcloud transfer jobs create SOURCE DESTINATION

其中:

  • SOURCE 是此移轉作業的資料來源,格式為 gs://BUCKET_NAME

  • DESTINATION 是新的值區,格式為 gs://BUCKET_NAME

其他選項包括:

  • 工作資訊:您可以指定 --name--description

  • 時間表:指定 --schedule-starts--schedule-repeats-every--schedule-repeats-until,或 --do-not-run

  • 物件條件:使用條件判斷要轉移哪些物件。包括 --include-prefixes--exclude-prefixes,以及 --include-modified-[before | after]-[absolute | relative] 中的時間條件。

  • 轉移選項:指定是否要覆寫目的地檔案 (--overwrite-when=differentalways),以及是否要在轉移期間或之後刪除特定檔案 (--delete-from=destination-if-uniquesource-after-transfer);指定要保留哪些中繼資料值 (--preserve-metadata);以及視需要在已轉移的物件上設定儲存空間類別 (--custom-storage-class)。

  • 通知:使用 --notification-pubsub-topic--notification-event-types--notification-payload-format 設定轉移作業的 Pub/Sub 通知

如要查看所有選項,請執行 gcloud transfer jobs create --help

舉例來說,如要轉移所有前置字串為 folder1 的物件:

gcloud transfer jobs create gs://old-bucket gs://new-bucket \
  --include-prefixes="folder1/"

REST

在此範例中,可瞭解到如何在不同的 Cloud Storage 值區之間移動檔案。例如,您可以將資料移到其他位置的值區。

使用 transferJobs create 的要求:

POST https://storagetransfer.googleapis.com/v1/transferJobs
{
  "description": "YOUR DESCRIPTION",
  "status": "ENABLED",
  "projectId": "PROJECT_ID",
  "schedule": {
      "scheduleStartDate": {
          "day": 1,
          "month": 1,
          "year": 2025
      },
      "startTimeOfDay": {
          "hours": 1,
          "minutes": 1
      },
      "scheduleEndDate": {
          "day": 1,
          "month": 1,
          "year": 2025
      }
  },
  "transferSpec": {
      "gcsDataSource": {
          "bucketName": "GCS_SOURCE_NAME"
      },
      "gcsDataSink": {
          "bucketName": "GCS_SINK_NAME"
      },
      "transferOptions": {
          "deleteObjectsFromSourceAfterTransfer": true
      }
  }
}

回應:

200 OK
{
  "transferJob": [
      {
          "creationTime": "2015-01-01T01:01:00.000000000Z",
          "description": "YOUR DESCRIPTION",
          "name": "transferJobs/JOB_ID",
          "status": "ENABLED",
          "lastModificationTime": "2015-01-01T01:01:00.000000000Z",
          "projectId": "PROJECT_ID",
          "schedule": {
              "scheduleStartDate": {
                  "day": 1,
                  "month": 1,
                  "year": 2015
              },
              "startTimeOfDay": {
                  "hours": 1,
                  "minutes": 1
              }
          },
          "transferSpec": {
              "gcsDataSource": {
                  "bucketName": "GCS_SOURCE_NAME",
              },
              "gcsDataSink": {
                  "bucketName": "GCS_NEARLINE_SINK_NAME"
              },
              "objectConditions": {
                  "minTimeElapsedSinceLastModification": "2592000.000s"
              },
              "transferOptions": {
                  "deleteObjectsFromSourceAfterTransfer": true
              }
          }
      }
  ]
}

用戶端程式庫

在此範例中,可瞭解到如何在不同的 Cloud Storage 值區之間移動檔案。例如,您可以將資料從某個值區複製到另一個位置

如要進一步瞭解 Storage 移轉服務用戶端程式庫,請參閱「Storage 移轉服務用戶端程式庫的使用說明」。

Java

想查看較舊的範例嗎?請參閱 Storage 移轉服務遷移指南

import com.google.protobuf.Duration;
import com.google.storagetransfer.v1.proto.StorageTransferServiceClient;
import com.google.storagetransfer.v1.proto.TransferProto.CreateTransferJobRequest;
import com.google.storagetransfer.v1.proto.TransferTypes.GcsData;
import com.google.storagetransfer.v1.proto.TransferTypes.ObjectConditions;
import com.google.storagetransfer.v1.proto.TransferTypes.Schedule;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob.Status;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferOptions;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import com.google.type.Date;
import com.google.type.TimeOfDay;
import java.io.IOException;
import java.util.Calendar;

public class TransferToNearline {
  /**
   * Creates a one-off transfer job that transfers objects in a standard GCS bucket that are more
   * than 30 days old to a Nearline GCS bucket.
   */
  public static void transferToNearline(
      String projectId,
      String jobDescription,
      String gcsSourceBucket,
      String gcsNearlineSinkBucket,
      long startDateTime)
      throws IOException {

    // Your Google Cloud Project ID
    // String projectId = "your-project-id";

    // A short description of this job
    // String jobDescription = "Sample transfer job of old objects to a Nearline GCS bucket.";

    // The name of the source GCS bucket to transfer data from
    // String gcsSourceBucket = "your-gcs-source-bucket";

    // The name of the Nearline GCS bucket to transfer old objects to
    // String gcsSinkBucket = "your-nearline-gcs-bucket";

    // What day and time in UTC to start the transfer, expressed as an epoch date timestamp.
    // If this is in the past relative to when the job is created, it will run the next day.
    // long startDateTime =
    //     new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2000-01-01 00:00:00").getTime();

    // Parse epoch timestamp into the model classes
    Calendar startCalendar = Calendar.getInstance();
    startCalendar.setTimeInMillis(startDateTime);
    // Note that this is a Date from the model class package, not a java.util.Date
    Date date =
        Date.newBuilder()
            .setYear(startCalendar.get(Calendar.YEAR))
            .setMonth(startCalendar.get(Calendar.MONTH) + 1)
            .setDay(startCalendar.get(Calendar.DAY_OF_MONTH))
            .build();
    TimeOfDay time =
        TimeOfDay.newBuilder()
            .setHours(startCalendar.get(Calendar.HOUR_OF_DAY))
            .setMinutes(startCalendar.get(Calendar.MINUTE))
            .setSeconds(startCalendar.get(Calendar.SECOND))
            .build();

    TransferJob transferJob =
        TransferJob.newBuilder()
            .setDescription(jobDescription)
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setGcsDataSource(GcsData.newBuilder().setBucketName(gcsSourceBucket))
                    .setGcsDataSink(GcsData.newBuilder().setBucketName(gcsNearlineSinkBucket))
                    .setObjectConditions(
                        ObjectConditions.newBuilder()
                            .setMinTimeElapsedSinceLastModification(
                                Duration.newBuilder().setSeconds(2592000 /* 30 days */)))
                    .setTransferOptions(
                        TransferOptions.newBuilder().setDeleteObjectsFromSourceAfterTransfer(true)))
            .setSchedule(Schedule.newBuilder().setScheduleStartDate(date).setStartTimeOfDay(time))
            .setStatus(Status.ENABLED)
            .build();

    // Create a Transfer Service client
    StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.create();

    // Create the transfer job
    TransferJob response =
        storageTransfer.createTransferJob(
            CreateTransferJobRequest.newBuilder().setTransferJob(transferJob).build());

    System.out.println("Created transfer job from standard bucket to Nearline bucket:");
    System.out.println(response.toString());
  }
}

Python

想查看較舊的範例嗎?請參閱 Storage 移轉服務遷移指南

from datetime import datetime

from google.cloud import storage_transfer
from google.protobuf.duration_pb2 import Duration


def create_daily_nearline_30_day_migration(
    project_id: str,
    description: str,
    source_bucket: str,
    sink_bucket: str,
    start_date: datetime,
):
    """Create a daily migration from a GCS bucket to a Nearline GCS bucket
    for objects untouched for 30 days."""

    client = storage_transfer.StorageTransferServiceClient()

    # The ID of the Google Cloud Platform Project that owns the job
    # project_id = 'my-project-id'

    # A useful description for your transfer job
    # description = 'My transfer job'

    # Google Cloud Storage source bucket name
    # source_bucket = 'my-gcs-source-bucket'

    # Google Cloud Storage destination bucket name
    # sink_bucket = 'my-gcs-destination-bucket'

    transfer_job_request = storage_transfer.CreateTransferJobRequest(
        {
            "transfer_job": {
                "project_id": project_id,
                "description": description,
                "status": storage_transfer.TransferJob.Status.ENABLED,
                "schedule": {
                    "schedule_start_date": {
                        "day": start_date.day,
                        "month": start_date.month,
                        "year": start_date.year,
                    }
                },
                "transfer_spec": {
                    "gcs_data_source": {
                        "bucket_name": source_bucket,
                    },
                    "gcs_data_sink": {
                        "bucket_name": sink_bucket,
                    },
                    "object_conditions": {
                        "min_time_elapsed_since_last_modification": Duration(
                            seconds=2592000  # 30 days
                        )
                    },
                    "transfer_options": {
                        "delete_objects_from_source_after_transfer": True
                    },
                },
            }
        }
    )

    result = client.create_transfer_job(transfer_job_request)
    print(f"Created transferJob: {result.name}")

驗證複製的物件

移轉作業完成後,建議您執行額外的資料完整性檢查。

  • 驗證物件上的中繼資料 (例如總和檢查碼和大小),確認物件是否正確複製。

  • 確認複製的物件版本正確無誤。Storage 移轉服務提供即用型選項,可驗證物件是否為副本。如果您已啟用記錄功能,請查看記錄,確認是否已成功複製所有物件,包括相應的中繼資料欄位。

開始使用目標值區

遷移作業完成並經過驗證後,請更新所有現有應用程式或工作負載,以便使用目標儲存桶名稱。請在 Cloud 稽核記錄中查看資料存取記錄,確認您的作業是否正確修改及讀取物件。

刪除原始值區

一切運作正常後,請刪除原始儲存桶

Storage 移轉服務提供刪除物件的選項,您可以在工作設定中指定 deleteObjectsFromSourceAfterTransfer: true,或是在 Google Cloud 主控台中選取該選項,以便在物件轉移後刪除。

排定物件刪除作業

如要排定物件的刪除時間,請同時使用排定轉移工作deleteObjectsUniqueInSink = true 選項。

轉移工作應設為將空值區轉移至包含物件的值區。這會導致 Storage 移轉服務列出物件並開始刪除。由於刪除作業只涉及中繼資料,因此轉移工作只會受到 QPS 限制。為加快程序,請將轉移作業分割為多個工作,每個工作都會處理一組不同的前置字串。

Google Cloud 也提供受控的 Cron 工作排程器。詳情請參閱「使用 Cloud Scheduler 排程 Google Cloud STS 轉移工作」一文。