Récupérer les statistiques de commit d'une transaction

Pour vous aider à mieux comprendre, optimiser et diagnostiquer les problèmes de transaction, Spanner vous permet d'accéder aux statistiques de commit des transactions. Actuellement, vous pouvez récupérer le nombre total de mutations pour une transaction.

Quand utiliser les statistiques de commit ?

La connaissance du nombre de mutations pour une transaction peut être utile dans les scénarios suivants.

Optimiser les conteneurs pour les allers-retours

Pour améliorer les performances de votre application, vous pouvez réduire le nombre d'allers-retours vers la base de données en effectuant autant de travail que possible dans chaque transaction. Dans ce scénario, vous souhaitez optimiser le nombre de mutations par transaction, tout en respectant les limites du système.

Pour déterminer le nombre de lignes que vous pouvez valider par transaction tout en restant en deçà de la limite, commencez par valider une ligne d'une transaction. Vous obtenez ainsi une référence du nombre de mutations par ligne. Vous devez ensuite diviser la limite système par votre référence pour obtenir un nombre de lignes par transaction. Pour plus d'informations sur le comptage des mutations, reportez-vous à cette note.

Lorsque vous utilisez le LMD, la limite de 80 000 (y compris les index) s'applique par instruction, et non par transaction. Vous pouvez exécuter plusieurs instructions LMD dans une seule transaction pour valider plus de 80 000 mutations, sous réserve de la limite de taille de transaction de 100 Mio. Dans ce cas, le mutation_count renvoyé dans les statistiques de commit reflète le total cumulé des mutations (y compris les index) sur toutes les instructions et peut dépasser 80 000.

Notez que l'optimisation des allers-retours n'est pas toujours bénéfique, en particulier si elle entraîne davantage de conflits de verrouillage. Vous pouvez résoudre les conflits de verrouillage dans votre base de données à l'aide des statistiques de verrouillage.

Surveiller vos transactions pour éviter d'atteindre les limites du système

À mesure que l'utilisation des applications augmente, il est possible que le nombre de mutations dans vos transactions augmente également. Pour éviter d'atteindre la limite du système et de créer des échecs de transaction, vous pouvez surveiller de manière proactive la statistique de commit du nombre de mutations au fil du temps. Si vous constatez que cette valeur augmente pour la même transaction, il est peut-être temps de l'optimiser comme décrit dans la section précédente.

Accéder aux statistiques de commit

Les statistiques de commit ne sont pas renvoyées par défaut. Au lieu de cela, vous devez définir l' return_commit_stats indicateur sur "true" pour chaque CommitRequest. Si vous utilisez l'API Mutation et que votre tentative de commit dépasse le nombre maximal de mutations autorisé (y compris les index), le commit échoue et une erreur INVALID_ARGUMENT est renvoyée. Pour le LMD, le dépassement de la limite de mutations (y compris les index) entraîne l'échec de l'instruction LMD individuelle lors de l'exécution avec une erreur BadUsage, plutôt qu'un échec au moment du commit.

Voici un exemple de renvoi de statistiques de commit à l'aide des bibliothèques clientes Spanner.

Récupérer les statistiques de commit

L'exemple suivant montre comment obtenir des statistiques de commit à l'aide des bibliothèques clientes Spanner.

C++

Le code suivant appelle set_return_stats() sur CommitOptions et renvoie un nombre de mutations de 6, car nous insérons ou mettons à jour deux lignes et trois colonnes dans chaque ligne.

void GetCommitStatistics(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  auto commit = client.Commit(
      spanner::Mutations{
          spanner::UpdateMutationBuilder(
              "Albums", {"SingerId", "AlbumId", "MarketingBudget"})
              .EmplaceRow(1, 1, 200000)
              .EmplaceRow(2, 2, 400000)
              .Build()},
      google::cloud::Options{}.set<spanner::CommitReturnStatsOption>(true));

  if (!commit) throw std::move(commit).status();
  if (commit->commit_stats) {
    std::cout << "Updated data with " << commit->commit_stats->mutation_count
              << " mutations.\n";
  }
  std::cout << "Update was successful [spanner_get_commit_stats]\n";
}

C#

En C#, les statistiques de commit ne sont pas renvoyées directement via l'API. Au lieu de cela, elles sont enregistrées au niveau du journal Informations par l'enregistreur par défaut.

Le code suivant active la journalisation des statistiques de commit pour toutes les transactions en définissant la propriété LogCommitStats de SpannerConnectionStringBuilder sur "true". Le code met également en œuvre un exemple d'enregistreur qui conserve une référence à la dernière réponse de commit observée. Le MutationCount est ensuite extrait de cette réponse et affiché.


using Google.Cloud.Spanner.Data;
using Google.Cloud.Spanner.V1;
using Google.Cloud.Spanner.V1.Internal.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

public class LogCommitStatsAsyncSample
{
    public async Task<long> LogCommitStatsAsync(string projectId, string instanceId, string databaseId)
    {
        // Commit statistics are logged at level Info by the default logger.
        // This sample uses a custom logger to access the commit statistics.
        // See https://googleapis.github.io/google-cloud-dotnet/docs/Google.Cloud.Spanner.Data/logging.html
        // for more information on how to use loggers.
        var logger = new CommitStatsSampleLogger();
        var options = new SessionPoolOptions();
        var poolManager = SessionPoolManager.Create(options, logger);
        var connectionStringBuilder = new SpannerConnectionStringBuilder
        {
            ConnectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}",
            // Set LogCommitStats to true to enable logging commit statistics for all transactions on the connection.
            // LogCommitStats can also be enabled/disabled for individual Spanner transactions.
            LogCommitStats = true,
            SessionPoolManager = poolManager,
        };

        using var connection = new SpannerConnection(connectionStringBuilder);
        await connection.OpenAsync();

        using var cmd = connection.CreateDmlCommand("INSERT Singers (SingerId, FirstName, LastName) VALUES (110, 'Virginia', 'Watson')");
        var rowCount = await cmd.ExecuteNonQueryAsync();
        var mutationCount = logger._lastCommitResponse.CommitStats.MutationCount;

        Console.WriteLine($"{rowCount} row(s) inserted...");
        Console.WriteLine($"{mutationCount} mutation(s) in transaction...");

        return mutationCount;
    }

    /// <summary>
    /// Sample logger that keeps a reference to the last seen commit response.
    /// Use the default logger if you only want to log the commit stats.
    /// </summary>
    public class CommitStatsSampleLogger : Logger
    {
        internal CommitResponse _lastCommitResponse;

        /// <summary>
        /// This method is called when a transaction that requested commit stats is committed.
        /// </summary>
        public override void LogCommitStats(CommitRequest request, CommitResponse response)
        {
            _lastCommitResponse = response;
            base.LogCommitStats(request, response);
        }

        protected override void LogImpl(LogLevel level, string message, Exception exception) =>
            WriteLine(exception == null ? $"{level}: {message}" : $"{level}: {message}, Exception: {exception}");

        protected override void LogPerformanceEntries(IEnumerable<string> entries)
        {
            string separator = Environment.NewLine + "  ";
            WriteLine($"Performance:{separator}{string.Join(separator, entries)}");
        }

        private void WriteLine(string line) => Trace.TraceInformation(line);
    }
}

Go

Le code suivant définit l'option ReturnCommitStats et affiche le nombre de mutations une fois la transaction validée.


import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/spanner"
)

func commitStats(w io.Writer, db string) error {
	ctx := context.Background()
	client, err := spanner.NewClient(ctx, db)
	if err != nil {
		return fmt.Errorf("commitStats.NewClient: %w", err)
	}
	defer client.Close()

	resp, err := client.ReadWriteTransactionWithOptions(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		stmt := spanner.Statement{
			SQL: `INSERT Singers (SingerId, FirstName, LastName)
					VALUES (110, '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