Operazioni di scrittura ottimizzate per la velocità effettiva

Questa pagina descrive come configurare il tempo di ritardo massimo di commit (scrittura) per ottimizzare la velocità effettiva di scrittura in Spanner.

Panoramica

Per garantire la coerenza dei dati, Spanner invia richieste di scrittura a tutte le repliche di voto nel database. Questo processo di replica può avere un overhead computazionale. Per ulteriori informazioni, consulta Replica.

Le scritture ottimizzate per la velocità effettiva offrono la possibilità di ammortizzare questi costi di calcolo eseguendo un gruppo di scritture insieme. A questo scopo, Spanner introduce un piccolo ritardo e raccoglie un gruppo di operazioni di scrittura che devono essere inviate agli stessi partecipanti votanti. L'esecuzione delle scritture in questo modo può fornire miglioramenti sostanziali della velocità effettiva a costo di una latenza leggermente maggiore.

Comportamento predefinito

Se non imposti un tempo di ritardo per il commit, Spanner potrebbe impostare un piccolo ritardo se ritiene che questo ammortirà il costo delle scritture.

Casi d'uso comuni

Puoi impostare manualmente il tempo di ritardo delle richieste di scrittura a seconda delle esigenze della tua applicazione. Puoi anche disabilitare i ritardi per il commit per le applicazioni sensibili alla latenza elevata impostando il tempo massimo di ritardo per il commit su 0 ms.

Se hai un'applicazione con tolleranza alla latenza e vuoi ottimizzare la velocità effettiva, l'impostazione di un tempo di ritardo per il commit più lungo migliora notevolmente la velocità effettiva, aumentando al contempo una latenza maggiore per ogni scrittura. Ad esempio, se stai eseguendo il caricamento collettivo di una grande quantità di dati e l'applicazione non si preoccupa della velocità con cui Spanner scrive i singoli dati, puoi impostare il tempo di ritardo del commit su un valore maggiore, ad esempio 100 ms. Ti consigliamo di iniziare con un valore di 100 ms, quindi di modificare l'impostazione fino a quando i compromessi relativi a latenza e velocità effettiva soddisfano le tue esigenze. Per la maggior parte delle applicazioni, è preferibile un valore compreso tra 20 ms e 100 ms.

Se hai un'applicazione sensibile alla latenza, Spanner è anche sensibile alla latenza per impostazione predefinita. Se il carico di lavoro è elevato, Spanner potrebbe impostare un piccolo ritardo. Puoi provare a impostare un valore pari a 0 ms per determinare se la latenza ridotta a fronte di una maggiore velocità effettiva è ragionevole per la tua applicazione.

Imposta tempi di ritardo per commit misto

Puoi configurare diversi tempi di ritardo massimo per il commit nei sottoinsiemi delle scritture. In questo caso, Spanner utilizza il tempo di ritardo più breve configurato per il set di scritture. Tuttavia, consigliamo di scegliere un singolo valore per la maggior parte dei casi d'uso poiché ciò si traduce in un comportamento più prevedibile.

Limitazioni

Puoi impostare un tempo di ritardo per il commit compreso tra 0 e 500 ms. L'impostazione di ritardi per il commit superiori a 500 ms genera un errore.

Imposta il ritardo massimo per il commit delle richieste di commit

Il parametro di ritardo massimo del commit fa parte del metodo CommitRequest. Puoi accedere a questo metodo con l'API RPC, l'API REST o la libreria client 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)
)

Ruby

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

Monitora la latenza delle richieste di scrittura

Puoi monitorare l'utilizzo e la latenza della CPU di Spanner utilizzando la console Google Cloud. Quando imposti un tempo di ritardo più lungo per le richieste di scrittura, dovresti notare che l'utilizzo della CPU potrebbe diminuire, mentre la latenza aumenta. Per scoprire di più sulla latenza nelle richieste di Spanner, consulta Acquisire e visualizzare la latenza delle richieste dell'API Spanner.