Separate keyspaces with Spring Data Cassandra

Following on from my previous post Getting started with Spring Data Cassandra we will look into using multiple keyspaces within an application. This will be a relatively short post due to most of the content being covered in the earlier post allowing us to focus on the code needed to allow multiple keyspaces and reasons why you might want to switch from a single one to using multiple.

As mentioned a minute ago, Getting started with Spring Data Cassandra contains fundamental information required in this post, including dependencies and code snippets that are not shown here.

Firstly lets start off with why you might want to use multiple keyspaces. When creating a multi tenant application there are a few ways to separate each tenant’s data from each other; including a column in the partition key to distinguish each tenant, creating individual tables for each tenant or using a keyspace for each tenant. Each come with their advantages and disadvantages for example sharing a table between tenants is efficient and easy to use but more active tenants will take over all the key and row caches due to the volume of data they have and the higher number of queries they run.

As mentioned earlier we will be focusing on using multiple keyspaces which come with the advantages of allowing each tenant to have different schemas as well as replication settings. It also comes with the disadvantages of requiring a larger amount of tables when compared to sharing tables between tenants which in turn increases the number of SSTables and MemTables that are created leading to more memory being used. The advantages and disadvantages described for separate keyspaces are very similar to those of sharing a keyspace but with the exception of not being able to set different replication factors.

Now that there is some context we can carry on and look at how to implement multiple keyspaces when using Spring Data Cassandra.

There isn’t to much code to add upon my previous post as it just requires a few tweaks to the beans used. That being said I was hoping it would be a bit more elegant to write but hopefully the solution I produced is good enough. Anyway lets get on with looking at the code and you can decide how it looks.

If you did view my previous post this class might look familiar. This was originally the main configuration class for a application that was designed to work for a single keyspace. To make the application suitable for multiple keyspaces I turned it into an abstract class and removed the @Configuration and @EnableCassandraRepositories annotations. It is then extended by other configuration classes which provide alterations to a few beans to allow them to point to their chosen keyspace. It is worth mentioning that getEntityBasePackages is defined here so that all entities can be defined in a single place where they can be used from whatever keyspaces are defined.

This configuration class is the smaller of the two shown in this post (the other can be found further below) as I chose to allow it to use the beans defined in AbstractCassandraConfiguration that are created due to extending CassandraConfig. The only configuration actually included in this class is the definition of the keyspace it is using. getKeyspace is used in the session bean created in AbstractCassandraConfiguration which leads onto a important point about how I have gone about writing this code.

In this post I chose to tie each keyspace to a session, so as the number of keyspaces increases the amount of sessions running also goes up. This could become problematic when connecting to a large amount of keyspaces due to the overhead of running so many independent sessions. It is also possible to use a single session for multiple keyspaces (which I might cover in a later post) by using the CassandraTemplate and specify the keyspace name in the query, but this requires you to write your own query implementations as you cannot use the inferred queries that the Spring Data repositories provide.

Continuing onto the other keyspace configuration.

This class is still pretty similar to the previous configuration but obviously it has some additions to it. Firstly it defines two beans which are also created in AbstractCassandraConfiguration. A new implementation of session is added that uses the super implementation but provides the bean with a new name of “keyspaceBSession” instead of “session”. If this name was not provided it would get mixed up with the other session used in KeyspaceACassandraConfig. As before getKeyspaceName is used in the original session method meaning that it doesn’t need to be explicitly set inside this class. The other created bean is the CassandraAdminOperations which is an interface that CassandraTemplate implements. @Qualifier needs to be used here to specify that the session created here is the one that is used and not the session tied to the other keyspace. The cassandraTemplateRef property inside @EnableCassandraRepositories defines what CassandraTemplate bean is used for all CassandraRepository methods and is crucial for allowing multiple keyspaces to be used. If this property was not set the repositories would look for a bean named “cassandraTemplate” which in this scenario is tied to a different keyspace.

After these configuration classes are finished the only task remaining is creating some repositories. Due to wanting to provide the same methods in each keyspace a base repository has been created to reduce duplication.

To be used by the keyspace repositories, for example.

This allows the keyspaces to diverge in functionality if required but keeps any shared requirements in a central location. Remember what I mentioned a minute ago, setting the cassandraTemplateRef in the @EnableCassandraRepositories annotation specifies which CassandraTemplate to use allowing the repositories themselves to be left bare and not require any extra configuration or annotations to make them work.

Now when each repository is used their queries will be directed towards the correct keyspaces.

That brings us to the end of this shorter post. We looked at how to configure the Spring Data Cassandra repositories to allow multiple keyspaces to be used and briefly touched on why you might want to use more keyspaces within your application. The method used in this post revolved around creating a new session and template for each keyspace which can be set up without to much extra configuration when compared to using a singular keyspace.

The code used in this post can be found on my GitHub profile.

  1. […] on from my last post Separate keyspaces with Spring Data Cassandra we will continue looking into using multiple keyspaces in Cassandra but this time focusing on using […]

    Like

    Reply

  2. Thank you Dan for your great post. Do you see any possibility to configurate the tenant specific repositories dynamically at runtime?
    I have my tenants by configuration and I want to access the corresponding keyspaces flexible at runtime. I can not find any way to do this.

    Like

    Reply

    1. Hi Markus,

      Thanks for your comment.

      If I understand your question correctly, I believe you need to use CassandraTemplate directly. The methods on CassandraTemplate allow you to specify a keyspace when creating Statements or you could even write the CQL yourself.

      Have a look at my other post Mulitple keyspaces using a single Spring Data CassandraTemplate, while I do not think it directly answers your question it provides insight into how to use CassandraTemplate. You could also modify the code shown in SimpleCassandraKeyspaceRepository (from the post) to take in a keyspace for each method rather than into it’s constructor, so you can have the flexibility you want.

      I hope that answers your question and feel free to ask anything else.

      Thanks
      Dan

      Like

      Reply

      1. Thanks Dan,
        that was also my first thought to do it like in your third post.
        But I liked your approach of owning a separate session per tenant. So that’s possibly to put tenants in differentes cassandra clusters. I think it somehow gets but just not so easy

        Thanks for your great support,
        Markus

        Like

      2. Yeah, if you want to use separate sessions and get the keyspaces at runtime then I do not think it can be done. The sessions are beans so are created at startup so I don’t see a simple way to create a new session dynamically depending on the keyspace. If the keyspaces are all known at startup then it will be fine as you can just create multiple instances of the SimpleCassandraKeyspaceRepository like I did in the post.

        There might be a way to create a new session when the application is running that uses the chosen keyspace, but I am not sure if that is a good idea and it is beyond me how to get that working.

        Thanks
        Dan

        Like

  3. Hi Dan,

    I was wondering, how can I configure a class indicating a materialized view. It would be great, if you could help me with that.

    Like

    Reply

  4. Hi Dan, Thanks for the post. I was wondering, how to create class for materialized view, so that is also created automatically from the code itself,.

    Like

    Reply

    1. Hi Nitin,

      I’m on my phone right now so can’t try anything myself. The docs don’t seem to mention materialized views but I came across this post that looks promising http://www.java-allandsundry.com/2017/01/spring-data-support-for-cassandra-3.html?m=1.

      But in terms of automatically creating the materialized view directly via an entity doesn’t seem possible.

      I will check this when I have more time and add another comment if needed.

      I hope this helps a little bit.

      Thanks
      Dan

      Like

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: