Über den Cassandra-Adapter eine Verbindung zu Spanner herstellen

Auf dieser Seite wird der Cassandra-Adapter beschrieben und es wird erläutert, wie Sie Spanner darüber verwenden und verbinden.

Der Cassandra-Adapter ist für die Ausführung auf demselben Computer wie Ihre Anwendung konzipiert. Der Adapter macht einen Endpunkt auf localhost verfügbar, der das CQL-Wire-Protokoll (Cassandra Query Language) unterstützt. Es übersetzt das CQL-Wire-Protokoll in gRPC, das Spanner-Wire-Protokoll. Wenn dieser Proxy lokal ausgeführt wird, kann ein Cassandra-Client eine Verbindung zu einer Spanner-Datenbank herstellen.

Sie können den Cassandra-Adapter auf folgende Weise starten:

  • In-Process mit Ihrer Go-Anwendung
  • In-Process mit Ihrer Java-Anwendung
  • Als eigenständiger Prozess
  • In einem Docker-Container

Hinweise

Bevor Sie den Cassandra-Adapter starten, müssen Sie sich auf dem Computer, auf dem der Cassandra-Adapter ausgeführt wird, entweder mit einem Nutzerkonto oder einem Dienstkonto authentifizieren. Wenn Sie ein Dienstkonto verwenden, müssen Sie den Speicherort der JSON-Schlüsseldatei (der Anmeldedatendatei) kennen. Sie legen die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS fest, um den Anmeldedatenpfad anzugeben.

Weitere Informationen finden Sie unter:

Cassandra-Adapter mit Ihrer Anwendung verbinden

Für den Cassandra-Adapter sind die folgenden Informationen erforderlich:

  • Projektname
  • Name der Cloud Spanner-Instanz
  • Datenbank, zu der eine Verbindung hergestellt werden soll

Wenn Sie Docker verwenden, benötigen Sie den Pfad für eine JSON-formatierte Datei mit Anmeldedaten (Schlüsseldatei).

Java In-Process

  1. Wenn Sie ein Dienstkonto für die Authentifizierung verwenden, achten Sie darauf, dass die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS auf den Pfad der Datei mit den Anmeldedaten festgelegt ist.

  2. Bei Java-Anwendungen können Sie den Cassandra-Adapter direkt mit der Anwendung verknüpfen, indem Sie google-cloud-spanner-cassandra als Abhängigkeit zu Ihrem Projekt hinzufügen.

Fügen Sie für Maven die folgende neue Abhängigkeit unter dem Abschnitt <dependencies> hinzu:

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

Fügen Sie für Gradle Folgendes hinzu:

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

  1. Ändern Sie den Erstellungscode für CqlSession. Verwenden Sie anstelle von CqlSessionBuilder die Option SpannerCqlSessionBuilder und geben Sie den Spanner-Datenbank-URI an:
    
    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();
        }
      }
    }
    

In-Process-Modus

Für Go-Anwendungen müssen Sie eine einzeilige Änderung an der Clusterinitialisierungsdatei vornehmen, um den Spanner-Cassandra-Go-Client einzubinden. Anschließend können Sie den Cassandra-Adapter direkt mit der Anwendung verknüpfen.

  1. Importieren Sie das spanner-Paket des Adapters aus dem Spanner-Cassandra-Go-Client in Ihre Go-Anwendung.
import spanner "github.com/googleapis/go-spanner-cassandra/cassandra/gocql"
  1. Ändern Sie den Code zum Erstellen des Clusters so, dass spanner.NewCluster anstelle von gocql.NewCluster verwendet wird, und geben Sie den Spanner-Datenbank-URI an:
    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
    }

Nachdem Sie eine Verbindung zu Ihrer Spanner-Datenbank hergestellt haben, können Sie Ihren Cluster wie gewohnt konfigurieren.

Eigenständig

  1. Klonen Sie das Repository:
git clone https://github.com/googleapis/go-spanner-cassandra.git
cd go-spanner-cassandra
  1. Führen Sie cassandra_launcher.go mit dem erforderlichen Flag -db aus:
go run cassandra_launcher.go \
-db "projects/my_project/instances/my_instance/databases/my_database"
  1. Ersetzen Sie -db durch Ihren Spanner-Datenbank-URI.

Docker

Starten Sie den Cassandra-Adapter mit dem folgenden Befehl.

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

Die folgende Liste enthält die am häufigsten verwendeten Startoptionen für den Spanner Cassandra-Adapter:

  • -db <DatabaseUri>

Der URI der Spanner-Datenbank (erforderlich). Damit wird die Spanner-Datenbank angegeben, zu der der Client eine Verbindung herstellt. Beispiel: projects/YOUR_PROJECT/instances/YOUR_INSTANCE/databases/YOUR_DATABASE

  • -tcp <TCPEndpoint>

Die Listener-Adresse des Clientproxys. Dies definiert den TCP-Endpunkt, an dem der Client auf eingehende Cassandra-Clientverbindungen wartet. Standard:localhost:9042

  • -grpc-channels <NumGrpcChannels>

Die Anzahl der gRPC-Channels, die für die Verbindung mit Spanner verwendet werden sollen. Standard: 4

Mit dem folgenden Befehl wird beispielsweise der Cassandra-Adapter auf Port 9042 mit den Anmeldedaten der Anwendung gestartet und der Adapter mit der Datenbank projects/my_project/instances/my_instance/databases/my_database verbunden:

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

Empfehlungen

Die folgenden Empfehlungen helfen Ihnen, die Nutzung des Cassandra-Adapters zu optimieren. Diese Empfehlungen beziehen sich auf Java, insbesondere auf den Cassandra-Clienttreiber für Java-Version 4.

Zeitlimit für Anfragen erhöhen

Ein Anfrage-Timeout von mindestens fünf Sekunden bietet eine bessere Erfahrung mit dem Cassandra-Adapter als der Standardwert von zwei Sekunden.

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

Verbindungs-Pooling optimieren

Die Standardkonfigurationen für die maximale Anzahl von Verbindungen und die maximale Anzahl gleichzeitiger Anfragen pro Verbindung oder Host sind für Entwicklungs-, Test- und Produktions- oder Staging-Umgebungen mit geringem Volumen geeignet. Wir empfehlen jedoch, diese Werte zu erhöhen, da der Cassandra-Adapter sich als einzelner Knoten ausgibt, im Gegensatz zu einem Pool von Knoten in einem Cassandra-Cluster.

Wenn Sie diese Werte erhöhen, sind mehr gleichzeitige Verbindungen zwischen dem Client und der Cassandra-Schnittstelle möglich. So kann eine Erschöpfung des Verbindungspools bei hoher Last verhindert werden.

# 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
  }
}

gRPC-Channels optimieren

gRPC-Channels werden vom Spanner-Client für die Kommunikation verwendet. Ein gRPC-Kanal entspricht in etwa einer TCP-Verbindung. Ein gRPC-Kanal kann bis zu 100 gleichzeitige Anfragen verarbeiten. Das bedeutet, dass eine Anwendung mindestens so viele gRPC-Kanäle benötigt wie die Anzahl der gleichzeitigen Anfragen, die die Anwendung ausführt, geteilt durch 100.

Tokenbasiertes Routing deaktivieren

Bei Treibern, die Token-basierten Lastenausgleich verwenden, wird möglicherweise eine Warnung ausgegeben oder sie funktionieren nicht, wenn der Cassandra-Adapter verwendet wird. Da der Cassandra-Adapter als einzelner Knoten fungiert, funktioniert er nicht immer gut mit tokenbewussten Treibern, die mindestens so viele Knoten im Cluster erwarten, wie der Replikationsfaktor angibt. Einige Treiber geben möglicherweise eine Warnung aus, die ignoriert werden kann, und greifen auf eine Ausgleichsrichtlinie wie „Round-Robin“ zurück. Andere Treiber schlagen möglicherweise mit einem Fehler fehl. Bei den Treibern, bei denen ein Fehler auftritt, müssen Sie die tokenbasierte Funktion deaktivieren oder die Round-Robin-Load-Balancing-Richtlinie konfigurieren.

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

Protokollversion an V4 anpinnen

Der Cassandra-Adapter ist mit jedem Open-Source-Apache Cassandra-Clienttreiber kompatibel, der dem CQL Binary v4-Wire-Protokoll entspricht. PROTOCOL_VERSION muss an V4 angepinnt sein, da sonst möglicherweise Verbindungsfehler auftreten.

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

Nächste Schritte