Mais conteúdo relacionado
Semelhante a Geneva JUG - Cassandra for Java Developers (20)
Mais de Michaël Figuière (18)
Geneva JUG - Cassandra for Java Developers
- 1. Cassandra for Java Developers
DataStax Driver & DevCenter
Michaël Figuière
Drivers & Developer Tools Architect
- 2. 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
- 3. Request Pipelining
© 2014 DataStax, All Rights Reserved.
3
Client
Without
Request Pipelining
Cassandra
Client Cassandra
With
Request Pipelining
- 4. Notifications
© 2014 DataStax, All Rights Reserved.
4
Client
Without
Notifications
With
Notifications
Node
Node
Node
Client
Node
Node
Node
- 7. 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
- 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 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
- 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 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
- 12. 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
- 13. 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
- 14. 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
- 15. 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
- 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 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
- 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