Durchsatzoptimierte Schreibvorgänge

Auf dieser Seite wird beschrieben, wie Sie die maximale Commit- bzw. Schreibverzögerungszeit konfigurieren, um den Schreibdurchsatz in Spanner zu optimieren.

Überblick

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

Mit durchsatzoptimierten Schreibvorgängen können Sie diese Berechnungskosten durch Ausführen einer Gruppe von Schreibvorgängen amortisieren. Zu diesem Zweck führt Spanner eine kleine Verzögerung ein und erfasst eine Gruppe von Schreibvorgängen, die an dieselben Abstimmungsteilnehmer gesendet werden müssen. Wenn Sie Schreibvorgänge auf diese Weise ausführen, kann der Durchsatz erheblich verbessert werden, allerdings auf Kosten einer leicht erhöhten Latenz.

Standardverhalten

Wenn Sie keine Zeit für die Commit-Verzögerung festlegen, kann Spanner eine kleine Verzögerung festlegen, wenn sie davon ausgeht, dass sich die Kosten für Ihre Schreibvorgänge amortisieren.

Gängige Anwendungsfälle

Sie können die Verzögerungszeit Ihrer Schreibanfragen je nach den Anforderungen Ihrer Anwendung manuell festlegen. Sie können Commit-Verzögerungen auch für Anwendungen deaktivieren, die sehr latenzempfindlich sind. Legen Sie dazu die maximale Commit-Verzögerungszeit auf 0 ms fest.

Wenn Sie eine latenztolerante Anwendung haben und den Durchsatz optimieren möchten, wird durch das Festlegen einer längeren Commit-Verzögerungszeit der Durchsatz deutlich verbessert, während für jeden Schreibvorgang eine höhere Latenz entsteht. Wenn Sie beispielsweise eine große Datenmenge im Bulk laden und der Anwendung nicht wichtig ist, wie schnell Spanner einzelne Daten schreibt, können Sie die Commit-Verzögerungszeit auf einen längeren Wert wie 100 ms festlegen. Wir empfehlen, mit einem Wert von 100 ms zu beginnen und dann nach oben und unten anzupassen, bis die Latenz und der Durchsatz Ihren Anforderungen entsprechen. Für die meisten Anwendungen eignet sich ein Wert zwischen 20 ms und 100 ms am besten.

Bei latenzempfindlichen Anwendungen ist Spanner standardmäßig ebenfalls latenzempfindlich. Bei Arbeitslasten mit starken Auffälligkeiten kann Spanner eine kurze Verzögerung festlegen. Sie können mit einem Wert von 0 ms experimentieren, um festzustellen, ob die reduzierte Latenz auf Kosten eines erhöhten Durchsatzes für Ihre Anwendung angemessen ist.

Verzögerungszeiten für gemischte Commits festlegen

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

Beschränkungen

Sie können eine Commit-Verzögerung zwischen 0 und 500 ms festlegen. Wenn die Commit-Verzögerungen höher als 500 ms sind, wird ein Fehler ausgegeben.

Maximale Commit-Verzögerung bei Commit-Anfragen festlegen

Der Parameter „max_commit_de“ ist Teil der Methode CommitRequest. Sie können auf diese Methode mit der RPC API, der REST API oder der Cloud Spanner-Clientbibliothek zugreifen.

Einfach loslegen (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

Latenz von Schreibanfragen überwachen

Sie können die Spanner-CPU-Auslastung und -Latenz mit der Google Cloud Console überwachen. Wenn Sie eine längere Verzögerungszeit für Ihre Schreibanfragen festlegen, kann sich die CPU-Auslastung möglicherweise verringern, während die Latenz zunimmt. Weitere Informationen zur Latenz in Spanner-Anfragen finden Sie unter Latenz von Spanner API-Anfragen erfassen und visualisieren.