Scylla 1.4 on Compose - Optimizing connectivity

Published

Compose is pleased to announce the availability of Scylla 1.4.2 on the Compose platform. This is the first update of the database since its arrival as a beta database on Compose. Compose databases are fully featured and managed while in beta as we continue to tune them and their user experience for optimal productivity.

For Compose users, the changes between Scylla 1.3 and 1.4 are mostly focussed on enhanced reliability. Beyond this, notable changes include support for CQL Snappy compression where client drivers support it and various new metrics that are now exposed. To upgrade to 1.4.2, simply go to the Compose console for your Scylla database, select Settings, select the new version in the Change Version panel and click Change Version.

Scylla 1.4.2 on Compose also comes with a user interface change that enables users to implement more reliable connection support by making an Address Translation Map available. Allow us to explain...

Optimizing Scylla Connectivity

To get the best out of a Scylla database client and for maximum reliability, it is best to connect to all the nodes of the database. This is why the ContactPoints or Hosts parameters for connections are arrays. But before populating your parameters with all your hosts, there's something you need to know.

When a Scylla/Cassandra client is connected to the cluster, it starts to explore its connections, querying the nodes for what nodes they know. That's great if the client is directly connected to the database cluster, but with the Compose Scylla database nodes safely on their own private network and talking to our access portals on that private network, the Compose nodes have no idea about the outside world. When they send the clients the internal IP addresses they are using, the client thinks these are new nodes and tries to connect, then can't and it all goes downhill from there.

What's needed is a translator that can turn those internal IP addresses into external names and save everyone from the confusion. AddressTranslator is a standard part of Cassandra/Scylla drivers and gives an interface for doing just that in the various languages that drivers are written in.

A translator is no use though if you haven't got a reference for your translating. That's where the Compose console comes in. If you bring up the overview for your Scylla database, below the Connection Strings and Cqlsh Command Line, you'll find a new Address Translation Map section.

The Translation Map

This code is designed to act as a snippet to be added to your application or placed in a configuration file. Here's an example:

{
    "10.0.24.69:9042": "sl-eu-lon-2-portal.3.dblayer.com:15227",
    "10.0.24.71:9042": "sl-eu-lon-2-portal.2.dblayer.com:15229",
    "10.0.24.70:9042": "sl-eu-lon-2-portal.1.dblayer.com:15228"
}

To use this for any driver that supports address translation, an application needs to create an address translator, load the translator with this information, and tell the driver to use the translator when connecting to a cluster.

To make it easier for developers, we've created address translation packages for Node.js, Java, and Groovy that work with Compose address translation maps.

In the process of adding support for this in Compose Scylla, we found that some drivers made an assumption that the port number of database nodes would be the same across all nodes. However, Compose's architecture is such that, for Scylla, we can't switch to using consistent port numbering without complicating future developments unnecessarily.

We are therefore seeking to improve driver support for variable port numbers within a cluster. We have already submitted modifications to some drivers to add this capability and we'll keep users informed as to the progress of those changes. We also invite Cassandra/Scylla driver authors to work with us to enhance and test their drivers.

Address translation with Node.js

To make it easier to do address translation in Node.js, we've created an npm package, composeaddresstranslator, to handle the translation map. Set up an application like so:

$ npm init
...
$ npm install cassandra-driver --save
$ npm install assert --save
$ npm install composeaddresstranslator --save

With the packages installed, we can create some code to connect to the cluster. Start by including the required packages and creating a password handler with credentials to log into Scylla.

var cassandra = require('cassandra-driver');  
var compose = require('composeaddresstranslator');  
var assert = require('assert');  
var authProvider = new cassandra.auth.PlainTextAuthProvider('scylla', 'password');  

Then use the address map from the Compose overview, assigning it a variable. This creates a plain JavaScript object.

addresses= {  
    "10.0.24.69:9042": "sl-eu-lon-2-portal.3.dblayer.com:15227",
    "10.0.24.71:9042": "sl-eu-lon-2-portal.2.dblayer.com:15229",
    "10.0.24.70:9042": "sl-eu-lon-2-portal.1.dblayer.com:15228"
}

With that created, create an instance of the ComposeAddressTranslator and, using the translator's setMap function, give it the address information it needs.

translator=new compose.ComposeAddressTranslator();

translator.setMap(addresses);  

We are now ready to create our Cassandra client. A feature of the ComposeAddressTranslator is that it also serves as a source for the contact point data. This means you can call the translator.getContactPoints function to get the array of addresses to connect to. The policies.addressResolution parameter should be set to the translator instance to get the client to use it for mapping addresses. The code should also pass the authProvider instance, which you created at the start, as the authProvider parameter. That looks like this:

client = new cassandra.Client({  
    contactPoints: translator.getContactPoints(),
    policies: {
        addressResolution: translator
    },
    authProvider: authProvider
});

With the client created, the code can go ahead and query the system. To keep things simple, this example just queries the cluster state:

client.execute("SELECT peer, data_center, host_id, rack, release_version FROM system.peers", function(err, result) {  
    assert.ifError(err);
    console.log(result);
    process.exit(0);
});

Save this and run it with Node and you should see a JavaScript object output with sections covering how the query was handled, the rows of the results and the columns of the results.

Address Translation with Java

A similar class has been created by Compose for Java. This can be found on the Compose-ex Github repository as https://github.com/compose-ex/java-composeaddresstranslator. There, you'll find the com.compose.scyllacompose.ComposeAddressTranslator class. There is also a simple connection example. After the inevitable Java preamble...

public class Connect {  
    public static void main(String args[]) {
        Cluster cluster = null;
        try {

...the ComposeAddressTranslator can get its translation map data by being passed a string representing a JSON object or array. The Compose UI offers an object, so we create a variable for that. Note that this is heavily escaped and concatenated to run over multiple lines since Java lacks multiline string support:

            String mapstring = "{\n"
                    + "    \"10.0.24.69:9042\": \"sl-eu-lon-2-portal.3.dblayer.com:15227\",\n"
                    + "    \"10.0.24.71:9042\": \"sl-eu-lon-2-portal.2.dblayer.com:15229\",\n"
                    + "    \"10.0.24.70:9042\": \"sl-eu-lon-2-portal.1.dblayer.com:15228\"\n"
                    + "}";

The code can then create a new ComposeAddressTranslator instance and pass the map to it using the setMap() method.

            ComposeAddressTranslator translator = new ComposeAddressTranslator();
            translator.setMap(mapstring);

It is now a simple task to use this translator to create the connection. We invoke the Cluster class builder() and, in a chained function, first add the contact points where we want the client to connect using the addContactPointsWithPorts() method. The ComposeAddressTranslator.getContactPoints() method makes this easier by using the right-hand side of the translation map as a list of contact points. The code then chains on setting the appropriate credentials using the withCredentials() method. Finally, the code tells the builder to use the translator it created with .withAddressTranslator() before building the cluster.

            cluster = Cluster.builder()
                    .addContactPointsWithPorts(translator.getContactPoints())
                    .withCredentials("scylla", "PASSWORD")
                    .withAddressTranslator(translator)
                    .build();

The code can now connect to the cluster. Here it does exactly that, retrieving the version number of the server as an example:

            Session session = cluster.connect();

            ResultSet rs = session.execute("select release_version from system.local");
            Row row = rs.one();
            System.out.println(row.getString("release_version"));

And then, of course, there's the cleaning up and closing down to be done in such a short example:

        } finally {
            if (cluster != null) {
                cluster.close();
            }
        }
    }
}

And now we are querying the cluster over all the available nodes.

Address translation with Groovy

For Groovy users, the Java code can work well for them, but for completeness, we include a Groovy version of the connection code as an example.

Wrapping up

The address translation map feature allows for more reliable client connections into Scylla. We've so far addressed some of the more popular languages and we'll be looking to make this capability available to as many drivers as possible in the future.


If you have any feedback about this or any other Compose article, drop the Compose Articles team a line at articles@compose.com. We're happy to hear from you.

Dj Walker-Morgan
Dj Walker-Morgan is Compose's resident Content Curator, and has been both a developer and writer since Apples came in II flavors and Commodores had Pets. Love this article? Head over to Dj Walker-Morgan’s author page to keep reading.

Conquer the Data Layer

Spend your time developing apps, not managing databases.