Durchsatzoptimierte Schreibvorgänge

Auf dieser Seite wird beschrieben, wie Sie die maximale Verzögerungszeit für Commits (Schreibvorgänge) für den Schreibdurchsatz in Spanner zu optimieren.

Übersicht

Zur Gewährleistung der Datenkonsistenz sendet Spanner Schreibanfragen an alle votierenden Replikate in der Datenbank. Dieser Replikationsprozess kann Rechenleistung. Weitere Informationen finden Sie unter Replikation.

Durch Durchsatzoptimierte Schreibvorgänge können diese Berechnungen amortisiert werden, durch die gemeinsame Ausführung einer Gruppe von Schreibvorgängen. Gehen Sie dazu wie folgt vor: Spanner führt eine kleine Verzögerung ein und erfasst eine Gruppe von Schreibvorgängen die an dieselben abstimmbaren Teilnehmer gesendet werden müssen. Schreibvorgänge ausführen in diesem erheblichen Durchsatzverbesserungen auf Kosten von zu einer erhöhten Latenz.

Standardverhalten

Wenn Sie keine Commit-Verzögerungszeit festlegen, legt Spanner möglicherweise eine wenn davon auszugehen ist, dass sich die Kosten für Ihre Schreibvorgänge amortisieren lassen.

Gängige Anwendungsfälle

Sie können die Verzögerungszeit Ihrer Schreibanfragen je nach Anwendungsanforderungen manuell festlegen. Sie können Commit-Verzögerungen auch für Anwendungen deaktivieren, die sehr latencianfällig sind, indem Sie die maximale Commit-Verzögerungszeit auf 0 ms festlegen.

Wenn Sie eine latenztolerante Anwendung haben und den Durchsatz optimieren möchten, können Sie mit einer längeren Commit-Verzögerung den Durchsatz deutlich verbessern, während die Latenz für jede Schreiboperation höher ist. Wenn Sie zum Beispiel eine große Datenmengen übertragen, und für die Anwendung ist es nicht wichtig, wie schnell Spanner schreibt einzelne Daten. Anschließend können Sie den Commit festlegen. auf einen längeren Wert wie 100 ms. Wir empfehlen, mit einer und dann nach oben und unten anpassen, bis die Kompromisse bei Latenz und Durchsatz Ihre Anforderungen erfüllen. Für die meisten Anwendungen eignet sich ein Wert zwischen 20 ms und 100 ms am besten.

Wenn Sie eine latenzempfindliche Anwendung haben, ist Spanner standardmäßig auch latenzempfindlich. Bei einer Arbeitslast mit Lastspitzen Spanner kann eine kleine Verzögerung festlegen. Sie können mit der Einrichtung eines von 0 ms, um festzustellen, ob die reduzierte Latenz auf Kosten einer erhöhten für Ihre Anwendung angemessen ist.

Verzögerungen für gemischte Commits festlegen

Sie können für Teilmengen Ihrer Schreibvorgänge unterschiedliche maximale Commit-Verzögerungen konfigurieren. In diesem Fall verwendet Spanner die kürzeste konfigurierte Verzögerungszeit für den Satz von Schreibvorgängen. Wir empfehlen jedoch, für die meisten Anwendungsfälle einen einzelnen Wert auszuwählen. da dies zu vorhersehbarem Verhalten führt.

Beschränkungen

Sie können eine Commit-Verzögerung zwischen 0 und 500 ms festlegen. Commit-Verzögerungen festlegen über 500 ms führt zu einem Fehler.

Maximale Commit-Verzögerung für Commit-Anfragen festlegen

Der Parameter für die maximale Commit-Verzögerung ist Teil der Methode CommitRequest. Sie können über die RPC API, die REST API oder die Cloud Spanner-Clientbibliothek auf diese Methode zugreifen.

Go


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

	"cloud.google.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

Schreiblatenz überwachen

Sie können die CPU-Auslastung und -Latenz von Spanner mit der Google Cloud Console Wenn Sie eine längere Verzögerungszeit für Ihre Schreibanfragen festlegen, ist mit einer potenziellen CPU-Auslastung zu rechnen nimmt, während die Latenz zunimmt. Um mehr über die Latenz Spanner-Anfragen, siehe Latenz von Spanner API-Anfragen erfassen und visualisieren