Escrituras optimizadas para la capacidad de procesamiento

En esta página, se describe cómo configurar el tiempo de retraso máximo de confirmación (escritura) para optimizar la capacidad de procesamiento de escritura en Spanner.

Descripción general

Para garantizar la coherencia de los datos, Spanner envía solicitudes de escritura a todas las réplicas de votación en la base de datos. Este proceso de replicación puede tener sobrecarga computacional. Para obtener más información, consulta Replicación.

Las escrituras optimizadas para la capacidad de procesamiento ofrecen la opción de amortizar estos costos de procesamiento ejecutando un grupo de escrituras juntas. Para ello, Spanner introduce una pequeña demora y recopila un grupo de escrituras que se deben enviar a los mismos participantes votantes. Ejecutar escrituras de esta manera puede proporcionar mejoras sustanciales en la capacidad de procesamiento a costa de una latencia ligeramente aumentada.

Comportamiento predeterminado

Si no estableces un tiempo de retraso de confirmación, Spanner podría establecer un retraso pequeño si considera que amortizará el costo de las operaciones de escritura.

Casos de uso habituales

Puedes configurar de forma manual el tiempo de demora de las solicitudes de escritura según las necesidades de tu aplicación. También puedes inhabilitar los retrasos de confirmación para las aplicaciones que son muy sensibles a la latencia si estableces el tiempo máximo de retraso de confirmación en 0 ms.

Si tienes una aplicación tolerante a la latencia y deseas optimizar la capacidad de procesamiento, establecer un tiempo de retraso de confirmación más largo mejora de forma significativa la capacidad de procesamiento mientras se genera una mayor latencia para cada escritura. Por ejemplo, si cargas de forma masiva una gran cantidad de datos y a la aplicación no le importa la rapidez con la que Spanner escribe los datos individuales, puedes establecer el tiempo de retraso de confirmación en un valor más largo, como 100 ms. Te recomendamos que comiences con un valor de 100 ms y, luego, lo ajustes hacia arriba y hacia abajo hasta que satisfagas tus necesidades de latencia y capacidad de procesamiento. En la mayoría de las aplicaciones, un valor entre 20 ms y 100 ms funciona mejor.

Si tienes una aplicación sensible a la latencia, Spanner también es sensible a la latencia de forma predeterminada. Si tienes una carga de trabajo con un aumento repentino, Spanner puede establecer una pequeña demora. Puedes experimentar con la configuración de un valor de 0 ms para determinar si la latencia reducida a costa de un aumento de la capacidad de procesamiento es razonable para tu aplicación.

Configurar tiempos de retraso de confirmación mixta

Puedes configurar diferentes tiempos de retraso máximo de confirmación en subconjuntos de escrituras. Si haces esto, Spanner usa el tiempo de retraso más corto configurado para el conjunto de escrituras. Sin embargo, te recomendamos elegir un solo valor para la mayoría de los casos de uso, ya que esto genera un comportamiento más predecible.

Limitaciones

Puedes establecer un tiempo de retraso de confirmación de entre 0 y 500 ms. Si se configuran retrasos de confirmación superiores a 500 ms, se generará un error.

Configurar el retraso máximo de confirmación en las solicitudes de confirmación

El parámetro de retraso máximo de confirmación forma parte del método CommitRequest. Puedes acceder a este método con la API de RPC, la API de REST o con la biblioteca cliente de Cloud Spanner.

Go


import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.go888ogle.com.fqhub.com/go/spanner"
)

// maxCommitDelay sets the maximum commit delay for a transaction.
func maxCommitDelay(w io.Writer, db string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	ctx := context.Background()
	client, err := spanner.NewClient(ctx, db)
	if err != nil {
		return fmt.Errorf("maxCommitDelay.NewClient: %w", err)
	}
	defer client.Close()

	// Set the maximum commit delay to 100ms.
	// This is the amount of latency this request is willing to incur in order
	// to improve throughput. If this field is not set, Spanner assumes requests
	// are relatively latency sensitive and automatically determines an
	// appropriate delay time. You can specify a batching delay value between 0 and 500 ms.
	// The transaction will also return the commit statistics.
	commitDelay := 100 * time.Millisecond
	resp, err := client.ReadWriteTransactionWithOptions(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		stmt := spanner.Statement{
			SQL: `INSERT Singers (SingerId, FirstName, LastName)
					VALUES (111, 'Virginia', 'Watson')`,
		}
		rowCount, err := txn.Update(ctx, stmt)
		if err != nil {
			return err
		}
		fmt.Fprintf(w, "%d record(s) inserted.\n", rowCount)
		return nil
	}, spanner.TransactionOptions{CommitOptions: spanner.CommitOptions{MaxCommitDelay: &commitDelay, ReturnCommitStats: true}})
	if err != nil {
		return fmt.Errorf("maxCommitDelay.ReadWriteTransactionWithOptions: %w", err)
	}
	fmt.Fprintf(w, "%d mutations in transaction\n", resp.CommitStats.MutationCount)
	return nil
}

Node.js

// Imports the Google Cloud client library.
const {Spanner, protos} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';

// Creates a client.
const spanner = new Spanner({
  projectId: projectId,
});

async function spannerSetMaxCommitDelay() {
  // Gets a reference to a Cloud Spanner instance and database.
  const instance = spanner.instance(instanceId);
  const database = instance.database(databaseId);

  database.runTransaction(async (err, transaction) => {
    if (err) {
      console.error(err);
      return;
    }
    try {
      const [rowCount] = await transaction.runUpdate({
        sql: 'INSERT Singers (SingerId, FirstName, LastName) VALUES (111, @firstName, @lastName)',
        params: {
          firstName: 'Virginia',
          lastName: 'Watson',
        },
      });

      console.log(
        `Successfully inserted ${rowCount} record into the Singers table.`
      );

      await transaction.commit({
        // The maximum amount of time to delay the transaction to improve
        // throughput.
        maxCommitDelay: protos.google.protobuf.Duration({
          seconds: 0, // 0 seconds
          nanos: 100000000, // 100,000,000 nanoseconds = 100 milliseconds
        }),
      });
    } catch (err) {
      console.error('ERROR:', err);
    } finally {
      // Close the database when finished.
      database.close();
    }
  });
}
spannerSetMaxCommitDelay();

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def insert_singers(transaction):
    row_ct = transaction.execute_update(
        "INSERT Singers (SingerId, FirstName, LastName) "
        " VALUES (111, 'Grace', 'Bennis')"
    )

    print("{} record(s) inserted.".format(row_ct))

database.run_in_transaction(
    insert_singers, max_commit_delay=datetime.timedelta(milliseconds=100)
)

Rita

require "google/cloud/spanner"

##
# This is a snippet for showcasing how to pass max_commit_delay in  commit_options.
#
# @param project_id  [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
def spanner_set_max_commit_delay project_id:, instance_id:, database_id:
  # Instantiates a client
  spanner = Google::Cloud::Spanner.new project: project_id
  client  = spanner.client instance_id, database_id

  records = [
    { SingerId: 1, AlbumId: 1, MarketingBudget: 200_000 },
    { SingerId: 2, AlbumId: 2, MarketingBudget: 400_000 }
  ]
  # max_commit_delay is the amount of latency in millisecond, this request
  # is willing to incur in order to improve throughput.
  # The commit delay must be at least 0ms and at most 500ms.
  # Default value is nil.
  commit_options = {
    return_commit_stats: true,
    max_commit_delay: 100
  }
  resp = client.upsert "Albums", records, commit_options: commit_options
  puts "Updated data with #{resp.stats.mutation_count} mutations."
end

Supervisa la latencia de las solicitudes de escritura

Puedes supervisar el uso y la latencia de CPU de Spanner con la consola de Google Cloud. Cuando establezcas un tiempo de demora más largo para tus solicitudes de escritura, es probable que se produzca una disminución potencial del uso de CPU mientras aumenta la latencia. Para obtener información sobre la latencia en las solicitudes de Spanner, consulta Captura y visualiza la latencia de las solicitudes a la API de Spanner.