Se connecter à Spanner à l'aide de l'adaptateur Cassandra

Cette page décrit l'adaptateur Cassandra et explique comment l'utiliser et comment vous connecter à Spanner à partir de celui-ci.

L'adaptateur Cassandra est conçu pour s'exécuter sur la même machine que votre application. L'adaptateur expose un point de terminaison sur localhost qui est compatible avec le protocole filaire CQL (Cassandra Query Language). Il traduit le protocole filaire CQL en gRPC, le protocole filaire Spanner. Lorsque ce proxy s'exécute localement, un client Cassandra peut se connecter à une base de données Spanner.

Vous pouvez démarrer l'adaptateur Cassandra de différentes manières :

  • En cours avec votre application Go
  • En cours avec votre application Java
  • En tant que processus autonome
  • Dans un conteneur Docker

Avant de commencer

Avant de démarrer l'adaptateur Cassandra, assurez-vous de vous être authentifié avec un compte utilisateur ou un compte de service sur la machine sur laquelle l'adaptateur Cassandra s'exécutera. Si vous utilisez un compte de service, vous devez connaître l'emplacement du fichier de clé JSON (le fichier d'identifiants). Définissez la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS pour spécifier le chemin d'accès aux identifiants. Avant de démarrer l'adaptateur Cassandra, assurez-vous de vous être authentifié avec un compte utilisateur ou un compte de service sur la machine sur laquelle l'adaptateur Cassandra s'exécutera. Si vous utilisez un compte de service, vous devez connaître l'emplacement du fichier de clé JSON (le fichier d'identifiants). Définissez la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS pour spécifier le chemin d'accès aux identifiants.

Pour en savoir plus, consultez les pages suivantes :

Connecter l'adaptateur Cassandra à votre application

L'adaptateur Cassandra nécessite les informations suivantes :

  • Nom du projet
  • Nom de l'instance Spanner
  • Base de données à laquelle se connecter

Si vous utilisez Docker, vous avez besoin du chemin d'accès à un fichier d'identifiants au format JSON (fichier de clé).

En cours avec Java

  1. Si vous utilisez un compte de service pour l'authentification, assurez-vous que la variable d'environnement GOOGLE_APPLICATION_CREDENTIALS est définie sur le chemin d'accès au fichier d'identifiants.

  2. Pour les applications Java, vous pouvez lier directement l'adaptateur Cassandra à l'application en ajoutant google-cloud-spanner-cassandra en tant que dépendance à votre projet.

Pour Maven, ajoutez la nouvelle dépendance suivante dans la <dependencies> section :

<dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-spanner-cassandra</artifactId>
    <version>1.2.0</version>
</dependency>

Pour Gradle, ajoutez l'extrait suivant :

dependencies {
    implementation 'com.google.cloud:google-cloud-spanner-cassandra:1.2.0'
}

  1. Modifiez le code de création de votre CqlSession. Au lieu d'utiliser CqlSessionBuilder, utilisez SpannerCqlSessionBuilder et fournissez l' URI de la base de données Spanner :
    
    import com.datastax.oss.driver.api.core.CqlSession;
    import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
    import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
    import com.datastax.oss.driver.api.core.cql.ResultSet;
    import com.datastax.oss.driver.api.core.cql.Row;
    import com.google.cloud.spanner.adapter.SpannerCqlSession;
    import java.net.InetSocketAddress;
    import java.time.Duration;
    import java.util.Random;
    
    // This sample assumes your spanner database <my_db> contains a table <users>
    // with the following schema:
    
    // CREATE TABLE users (
    //  id        INT64          OPTIONS (cassandra_type = 'int'),
    //  active    BOOL           OPTIONS (cassandra_type = 'boolean'),
    //  username  STRING(MAX)    OPTIONS (cassandra_type = 'text'),
    // ) PRIMARY KEY (id);
    
    class QuickStartSample {
    
      public static void main(String[] args) {
    
        // TODO(developer): Replace these variables before running the sample.
        final String projectId = "my-gcp-project";
        final String instanceId = "my-spanner-instance";
        final String databaseId = "my_db";
    
        final String databaseUri =
            String.format("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId);
    
        try (CqlSession session =
            SpannerCqlSession.builder() // `SpannerCqlSession` instead of `CqlSession`
                .setDatabaseUri(databaseUri) // Set spanner database URI.
                .addContactPoint(new InetSocketAddress("localhost", 9042))
                .withLocalDatacenter("datacenter1")
                .withKeyspace(databaseId) // Keyspace name should be the same as spanner database name
                .withConfigLoader(
                    DriverConfigLoader.programmaticBuilder()
                        .withString(DefaultDriverOption.PROTOCOL_VERSION, "V4")
                        .withDuration(
                            DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT, Duration.ofSeconds(5))
                        .build())
                .build()) {
    
          final int randomUserId = new Random().nextInt(Integer.MAX_VALUE);
    
          System.out.printf("Inserting user with ID: %d%n", randomUserId);
    
          // INSERT data
          session.execute(
              "INSERT INTO users (id, active, username) VALUES (?, ?, ?)",
              randomUserId,
              true,
              "John Doe");
    
          System.out.printf("Successfully inserted user: %d%n", randomUserId);
          System.out.printf("Querying user: %d%n", randomUserId);
    
          // SELECT data
          ResultSet rs =
              session.execute("SELECT id, active, username FROM users WHERE id = ?", randomUserId);
    
          // Get the first row from the result set
          Row row = rs.one();
    
          System.out.printf(
              "%d %b %s%n", row.getInt("id"), row.getBoolean("active"), row.getString("username"));
    
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    

En cours avec Go

Pour les applications Go, vous devez modifier une ligne du fichier d'initialisation du cluster afin d'intégrer le client Spanner Cassandra Go. Vous pouvez ensuite lier directement l'adaptateur Cassandra à l'application.

  1. Importez le package spanner de l'adaptateur à partir du client Spanner Cassandra Go dans votre application Go.
import spanner "github.com/googleapis/go-spanner-cassandra/cassandra/gocql"
  1. Modifiez le code de création de votre cluster pour utiliser spanner.NewCluster au lieu de gocql.NewCluster, puis fournissez l'URI de la base de données Spanner :
    import (
    	"fmt"
    	"io"
    	"math"
    	"math/rand/v2"
    	"time"
    
    	spanner "github.com/googleapis/go-spanner-cassandra/cassandra/gocql"
    )
    
    // This sample assumes your spanner database <your_db> contains a table <users>
    // with the following schema:
    //
    // CREATE TABLE users (
    //	id   	 	INT64          OPTIONS (cassandra_type = 'int'),
    //	active    	BOOL           OPTIONS (cassandra_type = 'boolean'),
    //	username  	STRING(MAX)    OPTIONS (cassandra_type = 'text'),
    // ) PRIMARY KEY (id);
    
    func quickStart(databaseURI string, w io.Writer) error {
    	opts := &spanner.Options{
    		DatabaseUri: databaseURI,
    	}
    	cluster := spanner.NewCluster(opts)
    	if cluster == nil {
    		return fmt.Errorf("failed to create cluster")
    	}
    	defer spanner.CloseCluster(cluster)
    
    	// You can still configure your cluster as usual after connecting to your
    	// spanner database
    	cluster.Timeout = 5 * time.Second
    	cluster.Keyspace = "your_db_name"
    
    	session, err := cluster.CreateSession()
    
    	if err != nil {
    		return err
    	}
    
    	randomUserId := rand.IntN(math.MaxInt32)
    	if err = session.Query("INSERT INTO users (id, active, username) VALUES (?, ?, ?)",
    			       randomUserId, true, "John Doe").
    		Exec(); err != nil {
    		return err
    	}
    
    	var id int
    	var active bool
    	var username string
    	if err = session.Query("SELECT id, active, username FROM users WHERE id = ?",
    			       randomUserId).
    		Scan(&id, &active, &username); err != nil {
    		return err
    	}
    	fmt.Fprintf(w, "%d %v %s\n", id, active, username)
    	return nil
    }

Vous pouvez configurer votre cluster comme d'habitude après vous être connecté à votre base de données Spanner.

Autonome

  1. Clonez le dépôt :
git clone https://github.com/googleapis/go-spanner-cassandra.git
cd go-spanner-cassandra
  1. Exécutez cassandra_launcher.go avec l'indicateur -db requis :
go run cassandra_launcher.go \
-db "projects/my_project/instances/my_instance/databases/my_database"
  1. Remplacez -db par l'URI de votre base de données Spanner.

Docker

Exécutez la commande suivante pour démarrer l'adaptateur Cassandra.

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
docker run -d -p 9042:9042 \
-e GOOGLE_APPLICATION_CREDENTIALS \
-v ${GOOGLE_APPLICATION_CREDENTIALS}:${GOOGLE_APPLICATION_CREDENTIALS}:ro \
gcr.io/cloud-spanner-adapter/cassandra-adapter \
-db DATABASE_URI

La liste suivante contient les options de démarrage les plus fréquemment utilisées pour l'adaptateur Spanner Cassandra :

  • -db <DatabaseUri>

URI de la base de données Spanner (obligatoire). Spécifie la base de données Spanner à laquelle le client se connecte. Par exemple, projects/YOUR_PROJECT/instances/YOUR_INSTANCE/databases/YOUR_DATABASE.

  • -tcp <TCPEndpoint>

Adresse de l'écouteur du proxy client. Définit le point de terminaison TCP où le client écoute les connexions entrantes du client Cassandra. Valeur par défaut : localhost:9042

  • -grpc-channels <NumGrpcChannels>

Nombre de canaux gRPC à utiliser lors de la connexion à Spanner. Valeur par défaut : 4

Par exemple, la commande suivante démarre l'adaptateur Cassandra sur le port 9042 à l'aide des identifiants de l'application et connecte l'adaptateur à la base de données projects/my_project/instances/my_instance/databases/my_database :

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
docker run -d -p 9042:9042 \
-e GOOGLE_APPLICATION_CREDENTIALS \
-v ${GOOGLE_APPLICATION_CREDENTIALS}:${GOOGLE_APPLICATION_CREDENTIALS}:ro \
gcr.io/cloud-spanner-adapter/cassandra-adapter \
-db projects/my_project/instances/my_instance/databases/my_database

Recommandations

Les recommandations suivantes vous aideront à améliorer votre expérience avec l'adaptateur Cassandra. Elles sont axées sur Java, en particulier sur le pilote client Cassandra pour Java version 4.

Augmenter le délai avant expiration des requêtes

Un délai avant expiration des requêtes de cinq secondes ou plus offre une meilleure expérience avec l'adaptateur Cassandra que la valeur par défaut de deux secondes.

# Sample application.conf: increases request timeout to five seconds
datastax-java-driver {
  basic {
    request {
      timeout = 5 seconds
    }
  }
}

Ajuster le regroupement de connexions

Les configurations par défaut pour le nombre maximal de connexions et le nombre maximal de requêtes simultanées par connexion ou hôte sont appropriées pour les environnements de développement, de test et de production ou de préproduction à faible volume. Toutefois, nous vous recommandons d'augmenter ces valeurs, car l'adaptateur Cassandra se fait passer pour un seul nœud, contrairement à un pool de nœuds dans un cluster Cassandra.

L'augmentation de ces valeurs permet d'établir davantage de connexions simultanées entre le client et l'interface Cassandra. Cela peut éviter l'épuisement du pool de connexions en cas de forte charge.

# Sample application.conf: increases maximum number of requests that can be
# executed concurrently on a connection
advanced.connection {
  max-requests-per-connection = 32000
  pool {
    local.size = 10
  }
}

Ajuster les canaux gRPC

Les canaux gRPC sont utilisés par le client Spanner pour la communication. Un canal gRPC équivaut à peu près à une connexion TCP. Un canal gRPC peut gérer jusqu'à 100 requêtes simultanées. Cela signifie qu'une application aura besoin d'au moins autant de canaux gRPC que le nombre de requêtes simultanées qu'elle exécutera, divisé par 100.

Désactiver le routage basé sur les jetons

Les pilotes qui utilisent l'équilibrage de charge basé sur les jetons peuvent afficher un avertissement ou ne pas fonctionner lorsque vous utilisez l'adaptateur Cassandra. Étant donné que l'adaptateur Cassandra se fait passer pour un seul nœud, il ne fonctionne pas toujours bien avec les pilotes basés sur les jetons qui s'attendent à ce qu'il y ait au moins un nombre de nœuds égal au facteur de réplication dans le cluster. Certains pilotes peuvent afficher un avertissement (qui peut être ignoré) et revenir à une stratégie d'équilibrage de charge de type "round robin", tandis que d'autres peuvent échouer avec une erreur. Pour les pilotes qui échouent avec une erreur, vous devez désactiver le routage basé sur les jetons ou configurer la stratégie d'équilibrage de charge de type "round robin".

# Sample application.conf: disables token-aware routing
metadata {
  token-map {
    enabled = false
  }
}

Épingler la version du protocole sur V4

L'adaptateur Cassandra est compatible avec n'importe quel protocole filaire CQL Binary v4 conforme, pilote client Apache Cassandra Open Source. Veillez à épingler PROTOCOL_VERSION sur V4, sinon vous risquez de voir des erreurs de connexion.

# Sample application.conf: overrides protocol version to V4
datastax-java-driver {
  advanced.protocol.version = V4
}

Étape suivante