ניהול שכפול אסינכרוני

במאמר הזה נסביר איך להתחיל ולהפסיק שכפול אסינכרוני.

שכפול אסינכרוני שימושי להתאוששות מאסון עם RPO נמוך ו-RTO נמוך. מידע נוסף על שכפול אסינכרוני

מגבלות

  • אפשר לשכפל דיסק ראשי רק לדיסק משני אחד בכל פעם.
  • אחרי שהשכפול מפסיק, אי אפשר להמשיך את השכפול לאותו דיסק. תצטרכו ליצור דיסק משני חדש ולהפעיל מחדש את השכפול.
  • אי אפשר לצרף, למחוק או ליצור תמונת מצב של דיסקים משניים בזמן שהם בתהליך השכפול.
  • אם משתמשים בדיסק אזורי כבדיסק משני, ומתרחש הפסקת חשמל אזורית באחד מהאזורים של הדיסק המשני, השכפול מהדיסק הראשי לדיסק המשני נכשל.

לפני שמתחילים

תפקידים והרשאות נדרשים

כדי לקבל את ההרשאות שדרושות להפעלה או להפסקה של שכפול, צריך לבקש מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

התפקידים המוגדרים מראש האלה כוללים את ההרשאות שנדרשות להפעלה או להפסקה של שכפול. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי להתחיל או להפסיק שכפול, נדרשות ההרשאות הבאות:

  • כדי להתחיל שכפול: compute.disks.startAsyncReplication
  • כדי להפסיק את השכפול של דיסק אחד: compute.disks.stopAsyncReplication
  • כדי להפסיק את השכפול של כל הדיסקים בקבוצת עקביות: compute.disks.stopGroupAsyncReplication

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

התחלת השכפול

מתחילים את השכפול באמצעות מסוף Google Cloud , Google Cloud CLI,‏ REST או Terraform.

המסוף

  1. נכנסים לדף Asynchronous replication במסוף Google Cloud .

    מעבר אל Asynchronous replication

  2. לוחצים על השם של הדיסק המשני שאליו רוצים להתחיל לשכפל.

  3. לוחצים על התחלת השכפול. נפתח החלון התחלת שכפול.

  4. לוחצים על התחלת השכפול.

gcloud

מתחילים את השכפול באמצעות הפקודה gcloud compute disks start-async-replication:

gcloud compute disks start-async-replication PRIMARY_DISK_NAME \
    --PRIMARY_LOCATION_FLAG=PRIMARY_LOCATION \
    --secondary-disk=SECONDARY_DISK_NAME \
    --SECONDARY_LOCATION_FLAG=SECONDARY_LOCATION \
    --secondary-disk-project=SECONDARY_PROJECT

מחליפים את מה שכתוב בשדות הבאים:

  • PRIMARY_DISK_NAME: השם של הדיסק הראשי.
  • PRIMARY_LOCATION_FLAG: דגל המיקום של הדיסק הראשי. לדיסקים אזוריים, צריך להשתמש ב---region. לדיסקים אזוריים, צריך להשתמש ב---zone.
  • PRIMARY_LOCATION: האזור או האזור הזמין של הדיסק הראשי. לדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.
  • SECONDARY_DISK_NAME: השם של הדיסק המשני.
  • SECONDARY_LOCATION_FLAG: דגל המיקום של הדיסק המשני. לדיסקים אזוריים, צריך להשתמש ב---secondary-disk-region. לדיסקים אזוריים, משתמשים ב---secondary-disk-zone.
  • SECONDARY_LOCATION: האזור או התחום של הדיסק המשני. לדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.
  • SECONDARY_PROJECT: הפרויקט שמכיל את הדיסק המשני.

המשך

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
)

// startReplication starts disk replication in a project for a given zone.
func startReplication(
	w io.Writer,
	projectID, zone, diskName, primaryDiskName, primaryZone string,
) error {
	// projectID := "your_project_id"
	// zone := "europe-west4-b"
	// diskName := "your_disk_name"
	// primaryDiskName := "your_disk_name2"
	// primaryZone := "europe-west2-b"

	ctx := context.Background()
	disksClient, err := compute.NewDisksRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewDisksRESTClient: %w", err)
	}
	defer disksClient.Close()

	secondaryFullDiskName := fmt.Sprintf("projects/%s/zones/%s/disks/%s", projectID, zone, diskName)

	req := &computepb.StartAsyncReplicationDiskRequest{
		Project: projectID,
		Zone:    primaryZone,
		Disk:    primaryDiskName,
		DisksStartAsyncReplicationRequestResource: &computepb.DisksStartAsyncReplicationRequest{
			AsyncSecondaryDisk: &secondaryFullDiskName,
		},
	}

	op, err := disksClient.StartAsyncReplication(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create disk: %w", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Replication started\n")

	return nil
}

Java

import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.DisksStartAsyncReplicationRequest;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.Operation.Status;
import com.google.cloud.compute.v1.StartAsyncReplicationDiskRequest;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class StartZonalDiskReplication {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // The project that contains the primary disk.
    String projectId = "YOUR_PROJECT_ID";
    // Name of the primary disk.
    String primaryDiskName = "PRIMARY_DISK_NAME";
    // Name of the secondary disk.
    String secondaryDiskName = "SECONDARY_DISK_NAME";
    // Name of the zone in which your primary disk is located.
    // Learn more about zones and regions:
    // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs
    String primaryDiskLocation = "us-central1-a";
    // Name of the zone in which your secondary disk is located.
    String secondaryDiskLocation = "us-east1-b";

    startZonalDiskAsyncReplication(projectId, primaryDiskName, primaryDiskLocation,
            secondaryDiskName, secondaryDiskLocation);
  }

  // Starts asynchronous replication for the specified zonal disk.
  public static Status startZonalDiskAsyncReplication(String projectId, String primaryDiskName,
      String primaryDiskLocation, String secondaryDiskName, String secondaryDiskLocation)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    String secondaryDiskPath = String.format("projects/%s/zones/%s/disks/%s",
            projectId, secondaryDiskLocation, secondaryDiskName);
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (DisksClient disksClient = DisksClient.create()) {
      DisksStartAsyncReplicationRequest diskRequest =
              DisksStartAsyncReplicationRequest.newBuilder()
                      .setAsyncSecondaryDisk(secondaryDiskPath)
                      .build();

      StartAsyncReplicationDiskRequest request =
              StartAsyncReplicationDiskRequest.newBuilder()
                      .setDisk(primaryDiskName)
                      .setDisksStartAsyncReplicationRequestResource(diskRequest)
                      .setProject(projectId)
                      .setZone(primaryDiskLocation)
                      .build();
      Operation response = disksClient.startAsyncReplicationAsync(request).get(1, TimeUnit.MINUTES);

      if (response.hasError()) {
        throw new Error("Error starting replication! " + response.getError());
      }
      return response.getStatus();
    }
  }
}

Node.js

// Import the Compute library
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

// Instantiate a diskClient
const disksClient = new computeLib.DisksClient();
// Instantiate a zoneOperationsClient
const zoneOperationsClient = new computeLib.ZoneOperationsClient();

/**
 * TODO(developer): Update/uncomment these variables before running the sample.
 */
// The project of the secondary disk.
const secondaryProjectId = await disksClient.getProjectId();

// The zone of the secondary disk.
// secondaryLocation = 'us-central1-a';

// The name of the secondary disk.
// secondaryDiskName = 'secondary-disk-name';

// The project of the primary disk.
const primaryProjectId = await disksClient.getProjectId();

// The zone of the primary disk.
// primaryLocation = 'us-central1-a';

// The name of the primary disk.
// primaryDiskName = 'primary-disk-name';

// Start replication
async function callStartReplication() {
  const [response] = await disksClient.startAsyncReplication({
    project: secondaryProjectId,
    zone: primaryLocation,
    disk: primaryDiskName,
    disksStartAsyncReplicationRequestResource:
      new compute.DisksStartAsyncReplicationRequest({
        asyncSecondaryDisk: `projects/${primaryProjectId}/zones/${secondaryLocation}/disks/${secondaryDiskName}`,
      }),
  });

  let operation = response.latestResponse;

  // Wait for the operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await zoneOperationsClient.wait({
      operation: operation.name,
      project: secondaryProjectId,
      zone: operation.zone.split('/').pop(),
    });
  }

  console.log(
    `Data replication from primary disk: ${primaryDiskName} to secondary disk: ${secondaryDiskName} started.`
  );
}

await callStartReplication();

Python

from __future__ import annotations

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def start_disk_replication(
    project_id: str,
    primary_disk_location: str,
    primary_disk_name: str,
    secondary_disk_location: str,
    secondary_disk_name: str,
) -> bool:
    """Starts the asynchronous replication of a primary disk to a secondary disk.
    Args:
        project_id (str): The ID of the Google Cloud project.
        primary_disk_location (str): The location of the primary disk, either a zone or a region.
        primary_disk_name (str): The name of the primary disk.
        secondary_disk_location (str): The location of the secondary disk, either a zone or a region.
        secondary_disk_name (str): The name of the secondary disk.
    Returns:
        bool: True if the replication was successfully started.
    """
    # Check if the primary disk location is a region or a zone.
    if primary_disk_location[-1].isdigit():
        region_client = compute_v1.RegionDisksClient()
        request_resource = compute_v1.RegionDisksStartAsyncReplicationRequest(
            async_secondary_disk=f"projects/{project_id}/regions/{secondary_disk_location}/disks/{secondary_disk_name}"
        )
        operation = region_client.start_async_replication(
            project=project_id,
            region=primary_disk_location,
            disk=primary_disk_name,
            region_disks_start_async_replication_request_resource=request_resource,
        )
    else:
        client = compute_v1.DisksClient()
        request_resource = compute_v1.DisksStartAsyncReplicationRequest(
            async_secondary_disk=f"zones/{secondary_disk_location}/disks/{secondary_disk_name}"
        )
        operation = client.start_async_replication(
            project=project_id,
            zone=primary_disk_location,
            disk=primary_disk_name,
            disks_start_async_replication_request_resource=request_resource,
        )
    wait_for_extended_operation(operation, verbose_name="replication operation")
    print(f"Replication for disk {primary_disk_name} started.")
    return True

REST

מתחילים את השכפול באחת מהשיטות הבאות:

  • מתחילים שכפול של דיסקים אזוריים באמצעות השיטה disks.startAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PRIMARY_DISK_PROJECT/zones/PRIMARY_LOCATION/disks/PRIMARY_DISK_NAME/startAsyncReplication
    
    {
    "asyncSecondaryDisk": "projects/SECONDARY_DISK_PROJECT/SECONDARY_LOCATION_PARAMETER/SECONDARY_LOCATION/disks/SECONDARY_DISK_NAME"
    }
    
  • מתחילים שכפול של דיסקים אזוריים באמצעות השיטה regionDisks.startAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PRIMARY_DISK_PROJECT/regions/PRIMARY_LOCATION/regionDisks/PRIMARY_DISK_NAME/startAsyncReplication
    
    {
    "asyncSecondaryDisk": "projects/SECONDARY_DISK_PROJECT/SECONDARY_LOCATION_PARAMETER/SECONDARY_LOCATION/disks/SECONDARY_DISK_NAME"
    }
    

מחליפים את מה שכתוב בשדות הבאים:

  • PRIMARY_DISK_PROJECT: הפרויקט שמכיל את הדיסק הראשי.
  • PRIMARY_LOCATION: האזור או האזור הזמין של הדיסק הראשי. לדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.
  • PRIMARY_DISK_NAME: השם של הדיסק הראשי.
  • SECONDARY_DISK_PROJECT: הפרויקט שמכיל את הדיסק המשני.
  • SECONDARY_LOCATION_PARAMETER: פרמטר המיקום של הדיסק המשני. לדיסקים אזוריים, צריך להשתמש ב-regions. לדיסקים אזוריים, משתמשים ב-zones.
  • SECONDARY_LOCATION: האזור או התחום של הדיסק המשני. לדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.
  • SECONDARY_DISK_NAME: השם של הדיסק המשני.

Terraform

כדי להתחיל שכפול בין דיסקים ראשיים ומשניים, משתמשים במשאב compute_disk_async_replication.

resource "google_compute_disk_async_replication" "default" {
  primary_disk = google_compute_disk.primary_disk.id
  secondary_disk {
    disk = google_compute_disk.secondary_disk.id
  }
}

כדי ללמוד איך להחיל הגדרות ב-Terraform או להסיר אותן, ראו פקודות בסיסיות ב-Terraform.

הפסקת השכפול

אפשר להפסיק את השכפול של דיסק ראשי או משני יחיד, או של כל הדיסקים בקבוצת עקביות. אם מפסיקים את השכפול של דיסק יחיד בקבוצת עקביות, זמן השכפול של הדיסק הזה לא מסונכרן עם הדיסקים האחרים בקבוצת העקביות.

הפסקת השכפול מתבצעת בתרחישים של מעבר לגיבוי פעיל וחזרה מגיבוי פעיל. אם מפסיקים את השכפול, אי אפשר להפעיל אותו מחדש לאותו דיסק משני. אם רוצים להפעיל מחדש את השכפול, צריך ליצור דיסק משני חדש ולהתחיל מחדש.

כשמפסיקים את השכפול בדיסק, מצב השכפול של הדיסק משתנה ל-STOPPED. מצב השכפול של הדיסק השני בצמד השכפול של הדיסק (הדיסק הראשי או המשני התואם) מתעדכן ל-STOPPED בשלב מאוחר יותר. אם רוצים להימנע מהפער בזמן ולעדכן את מצב השכפול של הדיסק השני ל-STOPPED באופן מיידי, צריך להפסיק את השכפול גם בדיסק השני באופן ידני. הפסקת השכפול בשני הדיסקים לא משפיעה על הזמן שבו השכפול מפסיק, אלא רק על מצבי השכפול של הדיסקים.

הפסקת השכפול של דיסק יחיד

אפשר להפסיק את השכפול של דיסק יחיד באמצעות מסוף Google Cloud , Google Cloud CLI או REST.

המסוף

כדי להפסיק את השכפול:

  1. נכנסים לדף Asynchronous replication במסוף Google Cloud .

    מעבר אל Asynchronous replication

  2. לוחצים על השם של הדיסק הראשי או המשני שרוצים להפסיק את השכפול שלו. ייפתח הדף ניהול הדיסק.

  3. לוחצים על הפסקת השכפול. נפתח החלון סיום השכפול.

  4. לוחצים על הפסקת השכפול.

gcloud

מפסיקים את השכפול באמצעות הפקודה gcloud compute disks stop-async-replication:

gcloud compute disks stop-async-replication DISK_NAME \
    --LOCATION_FLAG=LOCATION

מחליפים את מה שכתוב בשדות הבאים:

  • DISK_NAME: שם הדיסק.
  • LOCATION_FLAG: דגל המיקום של הדיסק. לדיסק אזורי, משתמשים ב---region. לדיסק אזורי, משתמשים ב---zone.
  • LOCATION: האזור או התחום של הדיסק. לדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.

המשך

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
)

// stopReplication stops primary disk replication in a project for a given zone.
func stopReplication(
	w io.Writer,
	projectID, primaryDiskName, primaryZone string,
) error {
	// projectID := "your_project_id"
	// primaryDiskName := "your_disk_name2"
	// primaryZone := "europe-west2-b"

	ctx := context.Background()
	disksClient, err := compute.NewDisksRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewDisksRESTClient: %w", err)
	}
	defer disksClient.Close()

	req := &computepb.StopAsyncReplicationDiskRequest{
		Project: projectID,
		Zone:    primaryZone,
		Disk:    primaryDiskName,
	}

	op, err := disksClient.StopAsyncReplication(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create disk: %w", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Replication stopped\n")

	return nil
}

Java

import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.Operation.Status;
import com.google.cloud.compute.v1.StopAsyncReplicationDiskRequest;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class StopZonalDiskReplication {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // The project that contains the primary disk.
    String projectId = "YOUR_PROJECT_ID";
    // Name of the region or zone in which your secondary disk is located.
    String secondaryDiskLocation = "us-east1-b";
    // Name of the secondary disk.
    String secondaryDiskName = "SECONDARY_DISK_NAME";

    stopZonalDiskAsyncReplication(projectId, secondaryDiskLocation, secondaryDiskName);
  }

  // Stops asynchronous replication for the specified disk.
  public static Status stopZonalDiskAsyncReplication(
          String project, String secondaryDiskLocation, String secondaryDiskName)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (DisksClient disksClient = DisksClient.create()) {
      StopAsyncReplicationDiskRequest stopReplicationDiskRequest =
              StopAsyncReplicationDiskRequest.newBuilder()
                      .setProject(project)
                      .setDisk(secondaryDiskName)
                      .setZone(secondaryDiskLocation)
                      .build();
      Operation response = disksClient.stopAsyncReplicationAsync(stopReplicationDiskRequest)
              .get(1, TimeUnit.MINUTES);

      if (response.hasError()) {
        throw new Error("Error stopping replication! " + response.getError());
      }
      return response.getStatus();
    }
  }
}

Node.js

// Import the Compute library
const computeLib = require('@google-cloud/compute');

// Instantiate a diskClient
const disksClient = new computeLib.DisksClient();
// Instantiate a zoneOperationsClient
const zoneOperationsClient = new computeLib.ZoneOperationsClient();

/**
 * TODO(developer): Update/uncomment these variables before running the sample.
 */
// The project that contains the primary disk.
const primaryProjectId = await disksClient.getProjectId();

// The zone of the primary disk.
// primaryLocation = 'us-central1-a';

// The name of the primary disk.
// primaryDiskName = 'primary-disk-name';

// Stop replication
async function callStopReplication() {
  const [response] = await disksClient.stopAsyncReplication({
    project: primaryProjectId,
    zone: primaryLocation,
    disk: primaryDiskName,
  });

  let operation = response.latestResponse;

  // Wait for the operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await zoneOperationsClient.wait({
      operation: operation.name,
      project: primaryProjectId,
      zone: operation.zone.split('/').pop(),
    });
  }

  console.log(`Replication for primary disk: ${primaryDiskName} stopped.`);
}

await callStopReplication();

Python

from __future__ import annotations

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def stop_disk_replication(
    project_id: str, primary_disk_location: str, primary_disk_name: str
) -> bool:
    """
    Stops the asynchronous replication of a disk.
    Args:
        project_id (str): The ID of the Google Cloud project.
        primary_disk_location (str): The location of the primary disk, either a zone or a region.
        primary_disk_name (str): The name of the primary disk.
    Returns:
        bool: True if the replication was successfully stopped.
    """
    # Check if the primary disk is in a region or a zone
    if primary_disk_location[-1].isdigit():
        region_client = compute_v1.RegionDisksClient()
        operation = region_client.stop_async_replication(
            project=project_id, region=primary_disk_location, disk=primary_disk_name
        )
    else:
        zone_client = compute_v1.DisksClient()
        operation = zone_client.stop_async_replication(
            project=project_id, zone=primary_disk_location, disk=primary_disk_name
        )

    wait_for_extended_operation(operation, verbose_name="replication operation")
    print(f"Replication for disk {primary_disk_name} stopped.")
    return True

REST

כדי להפסיק את השכפול, משתמשים באחת מהשיטות הבאות:

  • כדי להפסיק את השכפול של דיסקים אזוריים באמצעות השיטה disks.stopAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT/zones/LOCATION/disks/DISK_NAME/stopAsyncReplication
    {
    }
    
  • כדי להפסיק את השכפול של דיסקים אזוריים באמצעות השיטה regionDisks.stopAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT/regions/LOCATION/regionDisks/DISK_NAME/stopAsyncReplication
    {
    }
    

מחליפים את מה שכתוב בשדות הבאים:

  • PROJECT: הפרויקט שמכיל את הדיסק.
  • DISK_NAME: שם הדיסק.
  • LOCATION: האזור או האזור של הדיסק. בדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.

Terraform

כדי להפסיק את השכפול בדיסקים הראשיים והמשניים, מסירים את המשאב compute_disk_async_replication.

הפסקת השכפול של קבוצת אפליקציות עקביות

כדי להפסיק את השכפול של כל הדיסקים בקבוצת עקביות, משתמשים במסוףGoogle Cloud , ב-Google Cloud CLI או ב-REST.

המסוף

כדי להפסיק את השכפול של כל הדיסקים בקבוצת עקביות, מבצעים את הפעולות הבאות:

  1. נכנסים לדף Consistency Groups במסוף Google Cloud .

    כניסה לדף Consistency Groups

  2. בכרטיסייה קבוצות עקביות של דיסקים, לוחצים על השם של קבוצת העקביות שרוצים להפסיק את השכפול שלה. ייפתח הדף ניהול קבוצת עקביות.

  3. לוחצים על הפסקת השכפול. נפתח החלון סיום השכפול.

  4. לוחצים על הפסקת השכפול.

gcloud

כדי להפסיק את השכפול של כל הדיסקים בקבוצת עקביות, משתמשים בפקודה gcloud compute disks stop-group-async-replication:

gcloud compute disks stop-group-async-replication CONSISTENCY_GROUP \
--LOCATION_FLAG=LOCATION

מחליפים את מה שכתוב בשדות הבאים:

  • CONSISTENCY_GROUP: כתובת ה-URL של קבוצת העקביות. לדוגמה, projects/PROJECT/regions/REGION/resourcePolicies/CONSISTENCY_GROUP_NAME.
  • LOCATION_FLAG: דגל המיקום של הדיסקים בקבוצת אפליקציות עקביות. לדיסקים אזוריים, צריך להשתמש ב---region. לדיסקים אזוריים, משתמשים ב---zone.
  • LOCATION: האזור או התחום של הדיסק. בדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.

המשך

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
	"google.golang.org/protobuf/proto"
)

// stopReplicationConsistencyGroup stop replication for a consistency group for a project in a given region.
func stopReplicationConsistencyGroup(w io.Writer, projectID, region, groupName string) error {
	// projectID := "your_project_id"
	// region := "europe-west4"
	// groupName := "your_group_name"

	ctx := context.Background()
	disksClient, err := compute.NewRegionDisksRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewResourcePoliciesRESTClient: %w", err)
	}
	defer disksClient.Close()

	consistencyGroupUrl := fmt.Sprintf("projects/%s/regions/%s/resourcePolicies/%s", projectID, region, groupName)

	req := &computepb.StopGroupAsyncReplicationRegionDiskRequest{
		Project: projectID,
		DisksStopGroupAsyncReplicationResourceResource: &computepb.DisksStopGroupAsyncReplicationResource{
			ResourcePolicy: proto.String(consistencyGroupUrl),
		},
		Region: region,
	}

	op, err := disksClient.StopGroupAsyncReplication(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to stop replication: %w", err)
	}

	if err = op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Group stopped replicating\n")

	return nil
}

Java

import com.google.cloud.compute.v1.DisksClient;
import com.google.cloud.compute.v1.DisksStopGroupAsyncReplicationResource;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.Operation.Status;
import com.google.cloud.compute.v1.StopGroupAsyncReplicationDiskRequest;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class StopZonalDiskReplicationConsistencyGroup {
  public static void main(String[] args)
          throws IOException, InterruptedException, ExecutionException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Cloud project that contains the disk.
    String project = "YOUR_PROJECT_ID";
    // Zone of the disk.
    String zone = "us-central1-a";
    // Name of the consistency group.
    String consistencyGroupName = "CONSISTENCY_GROUP";

    stopZonalDiskReplicationConsistencyGroup(project, zone, consistencyGroupName);
  }

  // Stops replication of a consistency group for a project in a given zone.
  public static Status stopZonalDiskReplicationConsistencyGroup(
          String project, String zone, String consistencyGroupName)
          throws IOException, InterruptedException, ExecutionException, TimeoutException {
    String region = zone.substring(0, zone.lastIndexOf('-'));

    String resourcePolicy = String.format("projects/%s/regions/%s/resourcePolicies/%s",
            project, region, consistencyGroupName);
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (DisksClient disksClient = DisksClient.create()) {
      StopGroupAsyncReplicationDiskRequest request =
              StopGroupAsyncReplicationDiskRequest.newBuilder()
                      .setProject(project)
                      .setZone(zone)
                      .setDisksStopGroupAsyncReplicationResourceResource(
                              DisksStopGroupAsyncReplicationResource.newBuilder()
                                      .setResourcePolicy(resourcePolicy).build())
                      .build();
      Operation response = disksClient.stopGroupAsyncReplicationAsync(request)
              .get(3, TimeUnit.MINUTES);

      if (response.hasError()) {
        throw new Error("Error stopping disk replication! " + response.getError());
      }
      return response.getStatus();
    }
  }
}

Node.js

// Import the Compute library
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

// If disks are regional- use RegionDisksClient and RegionOperationsClient.
// TODO(developer): Uncomment disksClient and zoneOperationsClient before running the sample.
// Instantiate a disksClient
// disksClient = new computeLib.DisksClient();
// Instantiate a zoneOperationsClient
// zoneOperationsClient = new computeLib.ZoneOperationsClient();

/**
 * TODO(developer): Update/uncomment these variables before running the sample.
 */
// The project that contains the consistency group.
const projectId = await disksClient.getProjectId();

// If you use RegionDisksClient- define region, if DisksClient- define zone.
// The zone or region of the disks.
const disksLocation = 'europe-central2-a';

// The name of the consistency group.
const consistencyGroupName = 'consistency-group-1';

// The region of the consistency group.
const consistencyGroupLocation = 'europe-central2';

async function callStopReplication() {
  const [response] = await disksClient.stopGroupAsyncReplication({
    project: projectId,
    // If you use RegionDisksClient, pass region as an argument instead of zone.
    zone: disksLocation,
    disksStopGroupAsyncReplicationResourceResource:
      new compute.DisksStopGroupAsyncReplicationResource({
        resourcePolicy: [
          `https://www.googleapis.com/compute/v1/projects/${projectId}/regions/${consistencyGroupLocation}/resourcePolicies/${consistencyGroupName}`,
        ],
      }),
  });

  let operation = response.latestResponse;

  // Wait for the operation to complete.
  while (operation.status !== 'DONE') {
    [operation] = await zoneOperationsClient.wait({
      operation: operation.name,
      project: projectId,
      // If you use RegionDisksClient, pass region as an argument instead of zone.
      zone: operation.zone.split('/').pop(),
    });
  }

  const message = `Replication stopped for consistency group: ${consistencyGroupName}.`;
  console.log(message);
  return message;
}

return await callStopReplication();

Python

from __future__ import annotations

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def stop_replication_consistency_group(project_id, location, consistency_group_name):
    """
    Stops the asynchronous replication for a consistency group.
    Args:
        project_id (str): The ID of the Google Cloud project.
        location (str): The region where the consistency group is located.
        consistency_group_id (str): The ID of the consistency group.
    Returns:
        bool: True if the replication was successfully stopped.
    """
    consistency_group = compute_v1.DisksStopGroupAsyncReplicationResource(
        resource_policy=f"regions/{location}/resourcePolicies/{consistency_group_name}"
    )
    region_client = compute_v1.RegionDisksClient()
    operation = region_client.stop_group_async_replication(
        project=project_id,
        region=location,
        disks_stop_group_async_replication_resource_resource=consistency_group,
    )
    wait_for_extended_operation(operation, "Stopping replication for consistency group")

    return True

REST

כדי להפסיק את השכפול של כל הדיסקים בקבוצת עקביות, משתמשים באחת מהשיטות הבאות:

  • כדי להפסיק את השכפול של דיסקים אזוריים באמצעות השיטה disks.stopGroupAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT/zones/LOCATION/disks/stopGroupAsyncReplication
    {
    "resourcePolicy": "CONSISTENCY_GROUP"
    }
    
  • כדי להפסיק את השכפול של דיסקים אזוריים באמצעות השיטה regionDisks.stopGroupAsyncReplication:

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT/regions/LOCATION/regionDisks/DISK_NAME/stopAsyncReplication
    {
    "resourcePolicy": "CONSISTENCY_GROUP"
    }
    

מחליפים את מה שכתוב בשדות הבאים:

  • DISK_NAME: שם הדיסק
  • LOCATION: האזור או האזור של הדיסק. בדיסקים אזוריים, משתמשים באזור. לדיסקים אזוריים, משתמשים באזור.
  • CONSISTENCY_GROUP: כתובת ה-URL של קבוצת העקביות. לדוגמה, projects/PROJECT/regions/REGION/resourcePolicies/CONSISTENCY_GROUP_NAME.

המאמרים הבאים