Cassandra for Java Developers 
DataStax Driver & DevCenter 
Michaël Figuière 
Drivers & Developer Tools Architect
Client / Server Communication 
© 2014 DataStax, All Rights Reserved. 
2 
Client 
Client 
Client 
Client 
Node 
Node Replica 
Replica 
Replica 
Node 
Coordinator node: 
Forwards all R/W requests 
to corresponding replicas
Request Pipelining 
© 2014 DataStax, All Rights Reserved. 
3 
Client 
Without 
Request Pipelining 
Cassandra 
Client Cassandra 
With 
Request Pipelining
Notifications 
© 2014 DataStax, All Rights Reserved. 
4 
Client 
Without 
Notifications 
With 
Notifications 
Node 
Node 
Node 
Client 
Node 
Node 
Node
Asynchronous Driver Architecture 
© 2014 DataStax, All Rights Reserved. 
5 
Client 
Thread 
Node 
Node 
Node 
Client 
Thread 
Client 
Thread 
Node 
Driver
Asynchronous Driver Architecture 
© 2014 DataStax, All Rights Reserved. 
6 
Client 
Thread 
Node 
Node 
Node 
Client 
Thread 
Client 
Thread 
Node 
6 
2 
3 
4 
5 
1 
Driver
Failover 
© 2014 DataStax, All Rights Reserved. 
7 
Client 
Thread 
Node 
Node 
Node 
Client 
Thread 
Client 
Thread 
Node 
7 
2 
4 
3 5 1 
Driver 
6
Java Driver Highlights 
• Reference implementation 
• Asynchronous architecture based on Netty 
• Prepared Statements Support 
• Automatic Failover 
• Node Discovery 
• Tunable Load Balancing 
• Round Robin, Multi Data Centers, Latency Awareness, Replica Awareness 
• Cassandra Tracing Support 
• Compression & SSL 
© 2014 DataStax, All Rights Reserved. 
8
DataStax Driver in Practice 
<dependency> 
<groupId>com.datastax.cassandra</groupId> 
<artifactId>cassandra-­‐driver-­‐core</artifactId> 
<version>2.1.0</version> 
</dependency> 
Available in Maven 
Central. Depends on 
Netty, Guava, Metrics 
Supports Apache Cassandra 1.2 to 2.1 
© 2014 DataStax, All Rights Reserved. 9
Connect and Write 
Cluster cluster = Cluster.builder() 
.addContactPoints("127.0.0.1", “127.0.0.2") 
.build(); 
Session session = cluster.connect(“my_keyspace"); 
session.execute( 
"INSERT INTO user (user_id, name, email) 
VALUES (12345, 'johndoe', 'john@doe.com')" 
); 
The rest of the 
nodes will be 
discovered by 
the driver 
A keyspace is 
just like a 
schema in the 
SQL world 
© 2014 DataStax, All Rights Reserved. 10
Read 
Session is a thread safe 
object. A singleton should 
be instantiated at startup 
ResultSet resultSet = session.execute("SELECT * FROM user"); 
List<Row> rows = resultSet.all(); 
for (Row row : rows) { 
String userId = row.getString("user_id"); 
String name = row.getString("name"); 
String email = row.getString("email"); 
} 
Actually ResultSet also 
implements Iterable<Row> 
© 2014 DataStax, All Rights Reserved. 11
Write with Prepared Statements 
PreparedStatement objects 
are also threadsafe, just create 
a singleton at startup 
PreparedStatement insertUser = session.prepare( 
"INSERT INTO user (user_id, name, email) 
VALUES (?, ?, ?)" 
); 
BoundStatement statement = insertUser 
.bind(12345, "johndoe", "john@doe.com") 
.setConsistencyLevel(ConsistencyLevel.QUORUM); 
session.execute(statement); 
Parameters can 
be named as well 
BoundStatement 
is a stateful, NON 
threadsafe object 
Consistency Level can be 
set for each statement 
© 2014 DataStax, All Rights Reserved. 12
Asynchronous Read 
ResultSetFuture future = 
session.executeAsync("SELECT * FROM user"); 
ResultSet resultSet = future.get(); 
List<Row> rows = resultSet.all(); 
for (Row row : rows) { 
String userId = row.getString("user_id"); 
String name = row.getString("name"); 
String email = row.getString("email"); 
} 
Will NOT block unless 
all the connections are 
busy 
Will block until less all 
the connections are 
busy 
© 2014 DataStax, All Rights Reserved. 13
Asynchronous Read with Callbacks 
ResultSetFuture future = 
session.executeAsync("SELECT * FROM user"); 
future.addListener(new Runnable() { 
public void run() { 
// Process the results here 
} 
}, executor); 
ResultSetFuture 
implements Guava’s 
ListenableFuture 
executor = 
Executors 
.newCachedThreadPool(); 
executor = 
MoreExecutors 
.sameThreadExecutor(); 
Only if your listener code 
is trivial and non blocking 
as it’ll be executed in the 
IO Thread 
…Or any thread pool that 
you prefer 
© 2014 DataStax, All Rights Reserved. 14
Query Builder 
import static of 
QueryBuilder is required in 
order to use the DSL 
import static 
com.datastax.driver.core.querybuilder.QueryBuilder.*; 
Statement selectAll = 
select().all().from("user").where(eq("user_id", userId)); 
session.execute(selectAll); 
Statement insert = insertInto("user") 
.value("user_id", 2) 
.value("name", "johndoe") 
.value("email", "john@doe.com"); 
session.execute(insert); 
© 2014 DataStax, All Rights Reserved. 15
Object Mapper 
• Avoid boilerplate for common use cases 
• Map Objects to Statements and ResultSets to Objects 
• Do NOT hide Cassandra from the developer 
• No “clever tricks” à la Hibernate 
• Not JPA compatible, but JPA-ish API 
© 2014 DataStax, All Rights Reserved. 
16
Object Mapper in Practice 
<dependency> 
<groupId>com.datastax.cassandra</groupId> 
<artifactId>cassandra-­‐driver-­‐mapping</artifactId> 
<version>2.1.0</version> 
</dependency> 
Additional artifact for 
object mapping 
Available from Driver 2.1.0 
© 2014 DataStax, All Rights Reserved. 17
Basic Object Mapping 
CREATE 
TYPE 
address 
( 
street 
text, 
city 
text, 
zip 
int 
); 
CREATE 
TABLE 
users 
( 
email 
text 
PRIMARY 
KEY, 
address 
address 
); 
@UDT(keyspace 
= 
"ks", 
name 
= 
"address") 
public 
class 
Address 
{ 
private 
String 
street; 
private 
String 
city; 
private 
int 
zip; 
// 
getters 
and 
setters 
omitted... 
} 
@Table(keyspace 
= 
"ks", 
name 
= 
"users") 
public 
class 
User 
{ 
@PartitionKey 
private 
String 
email; 
private 
Address 
address; 
// 
getters 
and 
setters 
omitted... 
} 
© 2014 DataStax, All Rights Reserved. 18
Basic Object Mapping 
MappingManager 
manager 
= 
new 
MappingManager(session); 
Mapper 
mapper 
= 
manager.mapper(User.class); 
UserProfile 
myProfile 
= 
mapper.get("xyz@example.com"); 
ListenableFuture 
saveFuture 
= 
mapper.saveAsync(anotherProfile); 
mapper.delete("xyz@example.com"); 
Mapper, just like Session, is 
a thread-safe object. Create 
a singleton at startup. 
get() returns a mapped row 
for the given Primary Key 
ListenableFuture from 
Guava. Completed when the 
write is acknowledged. 
© 2014 DataStax, All Rights Reserved. 19
Accessors 
@Accessor 
interface 
UserAccessor 
{ 
@Query("SELECT 
* 
FROM 
user_profiles 
LIMIT 
:max") 
Result<User> 
firstN(@Param("max") 
int 
limit); 
} 
UserAccessor 
accessor 
= 
manager.createAccessor(UserAccessor.class); 
Result<User> 
users 
= 
accessor.firstN(10); 
for 
(User 
user 
: 
users) 
{ 
System.out.println( 
profile.getAddress().getZip() 
); 
} 
Result is like ResultSet 
but specialized for a 
mapped class… 
…so we iterate over it 
just like we would with a 
ResultSet 
© 2014 DataStax, All Rights Reserved. 20
DataStax DevCenter 
Demo
We’re Hiring! 
github.com/datastax 
blog.datastax.com 
@mfiguiere

Geneva JUG - Cassandra for Java Developers

  • 1.
    Cassandra for JavaDevelopers DataStax Driver & DevCenter Michaël Figuière Drivers & Developer Tools Architect
  • 2.
    Client / ServerCommunication © 2014 DataStax, All Rights Reserved. 2 Client Client Client Client Node Node Replica Replica Replica Node Coordinator node: Forwards all R/W requests to corresponding replicas
  • 3.
    Request Pipelining ©2014 DataStax, All Rights Reserved. 3 Client Without Request Pipelining Cassandra Client Cassandra With Request Pipelining
  • 4.
    Notifications © 2014DataStax, All Rights Reserved. 4 Client Without Notifications With Notifications Node Node Node Client Node Node Node
  • 5.
    Asynchronous Driver Architecture © 2014 DataStax, All Rights Reserved. 5 Client Thread Node Node Node Client Thread Client Thread Node Driver
  • 6.
    Asynchronous Driver Architecture © 2014 DataStax, All Rights Reserved. 6 Client Thread Node Node Node Client Thread Client Thread Node 6 2 3 4 5 1 Driver
  • 7.
    Failover © 2014DataStax, All Rights Reserved. 7 Client Thread Node Node Node Client Thread Client Thread Node 7 2 4 3 5 1 Driver 6
  • 8.
    Java Driver Highlights • Reference implementation • Asynchronous architecture based on Netty • Prepared Statements Support • Automatic Failover • Node Discovery • Tunable Load Balancing • Round Robin, Multi Data Centers, Latency Awareness, Replica Awareness • Cassandra Tracing Support • Compression & SSL © 2014 DataStax, All Rights Reserved. 8
  • 9.
    DataStax Driver inPractice <dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-­‐driver-­‐core</artifactId> <version>2.1.0</version> </dependency> Available in Maven Central. Depends on Netty, Guava, Metrics Supports Apache Cassandra 1.2 to 2.1 © 2014 DataStax, All Rights Reserved. 9
  • 10.
    Connect and Write Cluster cluster = Cluster.builder() .addContactPoints("127.0.0.1", “127.0.0.2") .build(); Session session = cluster.connect(“my_keyspace"); session.execute( "INSERT INTO user (user_id, name, email) VALUES (12345, 'johndoe', 'john@doe.com')" ); The rest of the nodes will be discovered by the driver A keyspace is just like a schema in the SQL world © 2014 DataStax, All Rights Reserved. 10
  • 11.
    Read Session isa thread safe object. A singleton should be instantiated at startup ResultSet resultSet = session.execute("SELECT * FROM user"); List<Row> rows = resultSet.all(); for (Row row : rows) { String userId = row.getString("user_id"); String name = row.getString("name"); String email = row.getString("email"); } Actually ResultSet also implements Iterable<Row> © 2014 DataStax, All Rights Reserved. 11
  • 12.
    Write with PreparedStatements PreparedStatement objects are also threadsafe, just create a singleton at startup PreparedStatement insertUser = session.prepare( "INSERT INTO user (user_id, name, email) VALUES (?, ?, ?)" ); BoundStatement statement = insertUser .bind(12345, "johndoe", "john@doe.com") .setConsistencyLevel(ConsistencyLevel.QUORUM); session.execute(statement); Parameters can be named as well BoundStatement is a stateful, NON threadsafe object Consistency Level can be set for each statement © 2014 DataStax, All Rights Reserved. 12
  • 13.
    Asynchronous Read ResultSetFuturefuture = session.executeAsync("SELECT * FROM user"); ResultSet resultSet = future.get(); List<Row> rows = resultSet.all(); for (Row row : rows) { String userId = row.getString("user_id"); String name = row.getString("name"); String email = row.getString("email"); } Will NOT block unless all the connections are busy Will block until less all the connections are busy © 2014 DataStax, All Rights Reserved. 13
  • 14.
    Asynchronous Read withCallbacks ResultSetFuture future = session.executeAsync("SELECT * FROM user"); future.addListener(new Runnable() { public void run() { // Process the results here } }, executor); ResultSetFuture implements Guava’s ListenableFuture executor = Executors .newCachedThreadPool(); executor = MoreExecutors .sameThreadExecutor(); Only if your listener code is trivial and non blocking as it’ll be executed in the IO Thread …Or any thread pool that you prefer © 2014 DataStax, All Rights Reserved. 14
  • 15.
    Query Builder importstatic of QueryBuilder is required in order to use the DSL import static com.datastax.driver.core.querybuilder.QueryBuilder.*; Statement selectAll = select().all().from("user").where(eq("user_id", userId)); session.execute(selectAll); Statement insert = insertInto("user") .value("user_id", 2) .value("name", "johndoe") .value("email", "john@doe.com"); session.execute(insert); © 2014 DataStax, All Rights Reserved. 15
  • 16.
    Object Mapper •Avoid boilerplate for common use cases • Map Objects to Statements and ResultSets to Objects • Do NOT hide Cassandra from the developer • No “clever tricks” à la Hibernate • Not JPA compatible, but JPA-ish API © 2014 DataStax, All Rights Reserved. 16
  • 17.
    Object Mapper inPractice <dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-­‐driver-­‐mapping</artifactId> <version>2.1.0</version> </dependency> Additional artifact for object mapping Available from Driver 2.1.0 © 2014 DataStax, All Rights Reserved. 17
  • 18.
    Basic Object Mapping CREATE TYPE address ( street text, city text, zip int ); CREATE TABLE users ( email text PRIMARY KEY, address address ); @UDT(keyspace = "ks", name = "address") public class Address { private String street; private String city; private int zip; // getters and setters omitted... } @Table(keyspace = "ks", name = "users") public class User { @PartitionKey private String email; private Address address; // getters and setters omitted... } © 2014 DataStax, All Rights Reserved. 18
  • 19.
    Basic Object Mapping MappingManager manager = new MappingManager(session); Mapper mapper = manager.mapper(User.class); UserProfile myProfile = mapper.get("xyz@example.com"); ListenableFuture saveFuture = mapper.saveAsync(anotherProfile); mapper.delete("xyz@example.com"); Mapper, just like Session, is a thread-safe object. Create a singleton at startup. get() returns a mapped row for the given Primary Key ListenableFuture from Guava. Completed when the write is acknowledged. © 2014 DataStax, All Rights Reserved. 19
  • 20.
    Accessors @Accessor interface UserAccessor { @Query("SELECT * FROM user_profiles LIMIT :max") Result<User> firstN(@Param("max") int limit); } UserAccessor accessor = manager.createAccessor(UserAccessor.class); Result<User> users = accessor.firstN(10); for (User user : users) { System.out.println( profile.getAddress().getZip() ); } Result is like ResultSet but specialized for a mapped class… …so we iterate over it just like we would with a ResultSet © 2014 DataStax, All Rights Reserved. 20
  • 21.
  • 22.
    We’re Hiring! github.com/datastax blog.datastax.com @mfiguiere