在檔案系統之間轉移資料

本頁說明如何在兩個 POSIX 檔案系統之間轉移資料。常見用途包括:

  • 爆量運算至雲端和混合式 HPC:將大量資料集從地端快速轉移至雲端進行處理。
  • 遷移及同步處理至 Filestore:將資料從地端檔案系統遷移或同步處理至 Filestore
  • 代管檔案傳輸:在資料中心之間或兩個雲端檔案系統之間,安全可靠地傳輸資料。

轉移效能指南

遵循下列指南,有助於在檔案系統之間的移轉作業期間,盡量提高效能。

部署代理程式

一般來說,我們建議在來源和目的地代理程式集區中各使用三個代理程式。監控轉移作業,並視需要新增更多服務專員。 每個代理程式需要 4 個 vCPU 和 8 GiB RAM。

如要遷移至 Filestore 執行個體,Filestore 建議為每個代理程式使用 n2-standard-8 執行個體類型。將執行個體掛接到 Compute Engine VM 時,請指定 nconnect=2。如要進一步瞭解如何最佳化及測試執行個體效能,請參閱 Filestore 效能指南

傳輸大量小型檔案

如要提升傳輸大量小型檔案時的效能,建議您將檔案分成多個目錄,並避免單一目錄包含數百萬個檔案。

事前準備

如要執行這個頁面中提及的工作,請先完成必要步驟

建立代理程式集區並安裝代理程式

如要進行檔案系統對檔案系統的移轉作業,您需要為來源和目的地檔案系統建立代理程式集區代理程式。來源代理程式集區的代理程式必須安裝在可存取來源檔案系統的機器或 VM 上。您必須在可存取目的地檔案系統的機器或 VM 上,安裝目的地代理程式集區的代理程式。

請勿在代理程式 ID 前置字元或代理程式集區名稱中加入敏感資訊,例如個人識別資訊 (PII) 或安全性資料。資源名稱可能會傳播至其他 Google Cloud 資源的名稱,並可能向專案外部的 Google 內部系統公開。

建立來源代理程式集區

使用下列任一方法建立來源代理程式集區:

gcloud CLI

執行下列指令,建立來源代理程式集區:

gcloud transfer agent-pools create SOURCE_AGENT_POOL

SOURCE_AGENT_POOL 替換為您要授予來源代理程式集區的名稱。

Google Cloud 控制台

  1. 前往 Google Cloud 控制台的「Agent pools」頁面。

    前往「Agent pools」(代理程式集區) 頁面

    系統會顯示「代理程式集區」頁面,列出您現有的代理程式集區。

  2. 按一下「建立其他集區」

  3. 輸入集區名稱。

  4. 點選「建立」

為來源代理程式集區安裝代理程式

在可存取來源檔案系統的機器或 VM 上,為來源代理程式集區安裝代理程式:

gcloud CLI

執行下列指令,為來源代理程式集區安裝代理程式:

gcloud transfer agents install --pool=SOURCE_AGENT_POOL --count=NUMBER_OF_AGENTS \
  --mount-directories=MOUNT_DIRECTORIES

更改下列內容:

  • SOURCE_AGENT_POOL 替換為來源代理程式集區的名稱。
  • NUMBER_OF_AGENTS,並輸入要為來源代理程式集區安裝的代理程式數量。如要判斷環境的最佳代理程式數量,請參閱「代理程式需求和最佳做法」。
  • MOUNT_DIRECTORIES,並以半形逗號分隔來源檔案系統中的目錄清單,這些目錄是要複製的來源。如果省略這個標記,系統會掛接整個檔案系統,這可能造成安全性風險

Google Cloud 控制台

  1. 前往 Google Cloud 控制台的「Agent pools」頁面。

    前往「Agent pools」(代理程式集區) 頁面

    系統會顯示「代理程式集區」頁面,列出您現有的代理程式集區。

  2. 按一下您剛建立的來源代理程式集區名稱。

  3. 在「代理程式」分頁中,按一下「安裝代理程式」

  4. 按照 Google Cloud 控制台中的操作說明安裝 Docker 並啟動代理程式。

建立目的地代理程式集區並安裝代理程式

重複上述步驟,建立目的地代理程式集區並安裝代理程式。

建立 Cloud Storage bucket 做為中介

檔案系統之間的移轉需要 Cloud Storage 值區做為資料移轉的中介。

  1. 建立 Cloud Storage Standard 類別值區,並使用下列設定:

    • 加密:您可以指定客戶管理的加密金鑰 (CMEK)。否則,系統會使用Google-owned and Google-managed encryption key 。
    • 物件版本管理值區鎖定預設物件保留:請停用這些功能。
  2. 使用下列任一方法授予權限和角色:

    • 為值區授予 Storage 移轉服務帳戶 Storage 管理員角色 (roles/storage.admin)。
    • 使用 gcloud transfer authorize 授權帳戶存取所有 Storage 移轉服務功能。這個指令會授予專案範圍的 Storage Admin 權限:

      gcloud transfer authorize --add-missing
      

建立移轉工作

gcloud CLI

如要從來源檔案系統建立轉移作業到目的地檔案系統,請執行

gcloud transfer jobs create SOURCE_DIRECTORY DESTINATION_DIRECTORY \
    --source-agent-pool=SOURCE_AGENT_POOL \
    --destination-agent-pool=DESTINATION_AGENT_POOL \
    --intermediate-storage-path= gs://STORAGE_BUCKET/FOLDER/

請替換下列變數:

  • SOURCE_DIRECTORY 替換為來源目錄的路徑。
  • DESTINATION_DIRECTORY 替換為目標目錄的路徑。
  • SOURCE_AGENT_POOL 替換為來源代理程式集區的名稱。
  • DESTINATION_AGENT_POOL 替換為目的地代理程式集區的名稱。
  • STORAGE_BUCKET 改成 Cloud Storage bucket 的名稱。
  • FOLDER,並填入要將資料轉移至其中的資料夾名稱。

啟動轉移工作後,系統會先計算來源和目的地的資料,判斷自上次轉移以來新增或更新的來源資料。系統只會轉移新資料。

用戶端程式庫

Go


import (
	"context"
	"fmt"
	"io"

	storagetransfer "cloud.google.com/go/storagetransfer/apiv1"
	"cloud.google.com/go/storagetransfer/apiv1/storagetransferpb"
)

func transferFromPosix(w io.Writer, projectID string, sourceAgentPoolName string, rootDirectory string, gcsSinkBucket string) (*storagetransferpb.TransferJob, error) {
	// Your project id
	// projectId := "myproject-id"

	// The agent pool associated with the POSIX data source. If not provided, defaults to the default agent
	// sourceAgentPoolName := "projects/my-project/agentPools/transfer_service_default"

	// The root directory path on the source filesystem
	// rootDirectory := "/directory/to/transfer/source"

	// The ID of the GCS bucket to transfer data to
	// gcsSinkBucket := "my-sink-bucket"

	ctx := context.Background()
	client, err := storagetransfer.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("storagetransfer.NewClient: %w", err)
	}
	defer client.Close()

	req := &storagetransferpb.CreateTransferJobRequest{
		TransferJob: &storagetransferpb.TransferJob{
			ProjectId: projectID,
			TransferSpec: &storagetransferpb.TransferSpec{
				SourceAgentPoolName: sourceAgentPoolName,
				DataSource: &storagetransferpb.TransferSpec_PosixDataSource{
					PosixDataSource: &storagetransferpb.PosixFilesystem{RootDirectory: rootDirectory},
				},
				DataSink: &storagetransferpb.TransferSpec_GcsDataSink{
					GcsDataSink: &storagetransferpb.GcsData{BucketName: gcsSinkBucket},
				},
			},
			Status: storagetransferpb.TransferJob_ENABLED,
		},
	}

	resp, err := client.CreateTransferJob(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer job: %w", err)
	}
	if _, err = client.RunTransferJob(ctx, &storagetransferpb.RunTransferJobRequest{
		ProjectId: projectID,
		JobName:   resp.Name,
	}); err != nil {
		return nil, fmt.Errorf("failed to run transfer job: %w", err)
	}
	fmt.Fprintf(w, "Created and ran transfer job from %v to %v with name %v", rootDirectory, gcsSinkBucket, resp.Name)
	return resp, nil
}

Java

import com.google.storagetransfer.v1.proto.StorageTransferServiceClient;
import com.google.storagetransfer.v1.proto.TransferProto;
import com.google.storagetransfer.v1.proto.TransferTypes.GcsData;
import com.google.storagetransfer.v1.proto.TransferTypes.PosixFilesystem;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import java.io.IOException;

public class TransferBetweenPosix {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.

    // Your project id
    String projectId = "my-project-id";

    // The agent pool associated with the POSIX data source. If not provided, defaults to the
    // default agent
    String sourceAgentPoolName = "projects/my-project-id/agentPools/transfer_service_default";

    // The agent pool associated with the POSIX data sink. If not provided, defaults to the default
    // agent
    String sinkAgentPoolName = "projects/my-project-id/agentPools/transfer_service_default";

    // The root directory path on the source filesystem
    String rootDirectory = "/directory/to/transfer/source";

    // The root directory path on the sink filesystem
    String destinationDirectory = "/directory/to/transfer/sink";

    // The ID of the GCS bucket for intermediate storage
    String bucketName = "my-intermediate-bucket";

    transferBetweenPosix(
        projectId,
        sourceAgentPoolName,
        sinkAgentPoolName,
        rootDirectory,
        destinationDirectory,
        bucketName);
  }

  public static void transferBetweenPosix(
      String projectId,
      String sourceAgentPoolName,
      String sinkAgentPoolName,
      String rootDirectory,
      String destinationDirectory,
      String bucketName)
      throws IOException {

    TransferJob transferJob =
        TransferJob.newBuilder()
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setSinkAgentPoolName(sinkAgentPoolName)
                    .setSourceAgentPoolName(sourceAgentPoolName)
                    .setPosixDataSource(
                        PosixFilesystem.newBuilder().setRootDirectory(rootDirectory).build())
                    .setPosixDataSink(
                        PosixFilesystem.newBuilder().setRootDirectory(destinationDirectory).build())
                    .setGcsIntermediateDataLocation(
                        GcsData.newBuilder().setBucketName(bucketName).build())
                    .build())
            .setStatus(TransferJob.Status.ENABLED)
            .build();

    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources,
    // or use "try-with-close" statement to do this automatically.
    try (StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.create()) {

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

      System.out.println(
          "Created and ran a transfer job from "
              + rootDirectory
              + " to "
              + destinationDirectory
              + " with name "
              + response.getName());
    }
  }
}

Node.js


// Imports the Google Cloud client library
const {
  StorageTransferServiceClient,
} = require('@google-cloud/storage-transfer');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// Your project id
// const projectId = 'my-project'

// The agent pool associated with the POSIX data source. Defaults to the default agent
// const sourceAgentPoolName = 'projects/my-project/agentPools/transfer_service_default'

// The agent pool associated with the POSIX data sink. Defaults to the default agent
// const sinkAgentPoolName = 'projects/my-project/agentPools/transfer_service_default'

// The root directory path on the source filesystem
// const rootDirectory = '/directory/to/transfer/source'

// The root directory path on the sink filesystem
// const destinationDirectory = '/directory/to/transfer/sink'

// The ID of the GCS bucket for intermediate storage
// const bucketName = 'my-intermediate-bucket'

// Creates a client
const client = new StorageTransferServiceClient();

/**
 * Creates a request to transfer from the local file system to the sink bucket
 */
async function transferDirectory() {
  const createRequest = {
    transferJob: {
      projectId,
      transferSpec: {
        sourceAgentPoolName,
        sinkAgentPoolName,
        posixDataSource: {
          rootDirectory,
        },
        posixDataSink: {
          rootDirectory: destinationDirectory,
        },
        gcsIntermediateDataLocation: {
          bucketName,
        },
      },
      status: 'ENABLED',
    },
  };

  // Runs the request and creates the job
  const [transferJob] = await client.createTransferJob(createRequest);

  const runRequest = {
    jobName: transferJob.name,
    projectId: projectId,
  };

  await client.runTransferJob(runRequest);

  console.log(
    `Created and ran a transfer job from '${rootDirectory}' to '${destinationDirectory}' with name ${transferJob.name}`
  );
}

transferDirectory();

Python

from google.cloud import storage_transfer


def transfer_between_posix(
    project_id: str,
    description: str,
    source_agent_pool_name: str,
    sink_agent_pool_name: str,
    root_directory: str,
    destination_directory: str,
    intermediate_bucket: str,
):
    """Creates a transfer between POSIX file systems."""

    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'

    # The agent pool associated with the POSIX data source.
    # Defaults to 'projects/{project_id}/agentPools/transfer_service_default'
    # source_agent_pool_name = 'projects/my-project/agentPools/my-agent'

    # The agent pool associated with the POSIX data sink.
    # Defaults to 'projects/{project_id}/agentPools/transfer_service_default'
    # sink_agent_pool_name = 'projects/my-project/agentPools/my-agent'

    # The root directory path on the source filesystem
    # root_directory = '/directory/to/transfer/source'

    # The root directory path on the destination filesystem
    # destination_directory = '/directory/to/transfer/sink'

    # The Google Cloud Storage bucket for intermediate storage
    # intermediate_bucket = 'my-intermediate-bucket'

    transfer_job_request = storage_transfer.CreateTransferJobRequest(
        {
            "transfer_job": {
                "project_id": project_id,
                "description": description,
                "status": storage_transfer.TransferJob.Status.ENABLED,
                "transfer_spec": {
                    "source_agent_pool_name": source_agent_pool_name,
                    "sink_agent_pool_name": sink_agent_pool_name,
                    "posix_data_source": {
                        "root_directory": root_directory,
                    },
                    "posix_data_sink": {
                        "root_directory": destination_directory,
                    },
                    "gcs_intermediate_data_location": {
                        "bucket_name": intermediate_bucket
                    },
                },
            }
        }
    )

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

管理中介值區

轉移作業完成後,Storage 移轉服務會將轉移記錄儲存到值區,列出已轉移和轉移失敗的資料。轉移完成後,系統會自動啟動清除工作,刪除中繼資料。在某些情況下,清除工作無法刪除 bucket 中的所有資料。 如要刪除清理作業未清除的資料,請按照下方操作說明手動刪除資料,或設定生命週期規則來自動刪除資料。

手動清除

根據要刪除的資料類型,執行下列指令,從中繼值區刪除資料。

  • 如要清除在清理期間未刪除的中繼 bucket 資料,請執行下列指令:

    gcloud storage rm gs://STORAGE_BUCKET/PREFIX**
    
  • 如要刪除所有資料 (包括轉移記錄),請使用 matches-all (*) 萬用字元指定 bucket 的根目錄。

    gcloud storage rm gs://STORAGE_BUCKET/*
    
  • 如要刪除 bucket,請執行下列指令:

    gcloud storage rm gs://STORAGE_BUCKET
    

請替換下列變數:

  • STORAGE_BUCKET 替換為中介值區的名稱。

  • PREFIX,其中包含資料在中間值區中轉移至的資料夾名稱。

設定生命週期規則

如要刪除自動清除週期未清除的資料,請為 Cloud Storage 值區設定生命週期規則。使用 age 條件,指定比使用該值區做為中介的轉移工作時間更長的期間,即可清除值區中的中繼資料。如果指定年齡條件短於從中介值區下載檔案至目的地所需的時間,檔案移轉就會失敗。

您也可以使用 matchesPrefix 條件,清除為中繼值區指定的資料夾中的資料。如要連同 bucket 中的資料一併刪除轉移記錄,則不需要 matchesPrefix 條件。

保留檔案中繼資料

如要保留檔案中繼資料,包括數字 UID、GID、MODE 和符號連結,請按照下列步驟操作:

gcloud CLI

使用 --preserve-metadata 欄位,指定這項轉移作業的保留行為。適用於檔案系統移轉的選項包括:gidmodesymlinkuid

REST API

metadataOptions 物件中指定適當的選項。

詳情請參閱「保留選用的 POSIX 屬性」。

使用 gcloud CLI 進行轉移的範例

在本範例中,我們會將 VM1 上的 /tmp/datasource 目錄中的資料轉移至 VM2 上的 /tmp/destination

  1. 設定轉移來源。

    1. 建立來源代理程式集區:

      gcloud transfer agent-pools create source_agent_pool
      
    2. 在 VM1 上,執行以下指令,安裝 source_agent_pool 的代理程式:

      gcloud transfer agents install --pool=source_agent_pool \
          --count=1 \
          --mount-directories="/tmp/datasource"
      
  2. 設定轉移目的地。

    1. 建立目的地代理程式集區:

      gcloud transfer agent-pools create destination_agent_pool
      
    2. 在 VM2 上,執行下列指令,安裝 destination_agent_pool 的代理程式:

      gcloud transfer agents install --pool=destination_agent_pool \
          --count=3 \
          --mount-directories="/tmp/destination"
      
  3. 建立中介 Cloud Storage bucket。

    1. 建立名為 my-intermediary-bucket 的 bucket:

      gcloud storage buckets create gs://my-intermediary-bucket
      
    2. 執行下列指令,授權帳戶使用所有 Storage 移轉服務功能:

      gcloud transfer authorize --add-missing
      
  4. 執行下列指令,建立轉移工作:

    gcloud transfer jobs create posix:///tmp/datasource posix:///tmp/destination \
        --source-agent-pool=source_agent_pool \
        --destination-agent-pool=destination_agent_pool \
        --intermediate-storage-path=gs://my-intermediary-bucket
    

後續步驟