SlideShare a Scribd company logo
©2013 DataStax Confidential. Do not distribute without consent.
@PatrickMcFadin
Patrick McFadin

Chief Evangelist, DataStax
Advanced Cassandra
1
Does Apache Cassandra Work?
Advanced Cassandra
Motivations
Advanced Cassandra
Cassandra is not…
6
A Data Ocean or Pond., Lake
An In-Memory Database
A Key-Value Store
A magical database unicorn that farts rainbows
7
When to use…
Loose data model (joins, sub-selects)
Absolute consistency (aka gotta have ACID)
No need to use anything else
You’ll miss the long, candle lit dinners with your Oracle rep
that always end with “what’s your budget look like this
year?”
Oracle, MySQL, Postgres or <RDBMS>
Uptime is a top priority
Unpredictable or high scaling requirements
Workload is transactional
Willing to put the time or effort into understanding how Cassandra works
and how to use it.
8
When to use…
Use Oracle when you want to count your money.
Use Cassandra when you want to make money.
Cassandra
Copy n Paste your relational model
APACHE
CASSANDRA
Advanced Cassandra
1000 Node Cluster
Scaling up
Stick the landing
12
Going to deploy in production!
Not sure about this!
Done!
Topology considerations
Replication Strategy
CREATE KEYSPACE killrvideo WITH
REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 };
Strategy
Copies
Topology considerations
• Default
• One data center
SimpleStrategy
NetworkTopologyStrategy
• Use for multi-data center
• Just use this always
NetworkTopologyStrategy
CREATE KEYSPACE Product_Catalog WITH
REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 3 };
CREATE KEYSPACE EU_Customer_Data WITH
REPLICATION = { 'class' : 'NetworkTopologyStrategy',
'eu1' : 3
‘eu2’ : 3
‘us1’ : 0 };
Symmetric
Asymmetric
No copies in the US
Application
• Closer to customers
• No downtime
Product_Catalog RF=3
Product_Catalog RF=3 EU_Customer_Data RF=3
EU_Customer_Data RF=0
Product_Catalog RF=3
EU_Customer_Data RF=3
Snitches
Snitches
DC1
DC1: RF=3
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
Client
Where do I place
this data?
?
Dynamic Snitching
Route based on node performance
Snitches
SimpleSnitch
GossipingPropertyFileSnitch
RackInferringSnitch
PropertyFileSnitch
EC2Snitch
GoogleCloudSnitch
CloudStackSnitch
EC2MultiRegionSnitch
Snitches
• Most typically used in production
• Absolute placement
GossipingPropertyFileSnitch
cassandra-rackdc.properties
dc=DC1
rack=RAC1
Booting a datacenter
DC1
DC1: RF=3
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
DC2
Pre-check
• Use NetworkTopologyStrategy
• In cassandra.yaml
• auto_bootstrap: false
• add seeds from other DC
• Set node location for Snitch
• GossipingPropertyFileSnitch:
cassandra-rackdc.properties
• PropertyFileSnitch: cassandra-
topology.properties
Booting a datacenter
DC1
DC1: RF=3
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
DC2
10.1.0.1
00-25
10.1.0.4
76-100
10.1.0.2
26-50
10.1.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
DC2: RF=3
ALTER KEYSPACE
Booting a datacenter
DC1
DC1: RF=3
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
DC2
10.1.0.1
00-25
10.1.0.4
76-100
10.1.0.2
26-50
10.1.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
DC2: RF=3
nodetool rebuild
Security
NoSQL == No Security
User Auth
Step 1 Turn it on
cassandra.yaml
authorizer:PasswordAuthorizerAllowAllAuthorizer
authenticator:AllowAllAuthenticatorPasswordAuthenticator
User Auth
cqlsh -u cassandra -p cassandra
Step 2 Create users
cqlsh> create user dude with password 'manager' superuser;
cqlsh> create user worker with password 'newhire';
cqlsh> list users;
name | super
----------+-------
cassandra | True
worker | False
dude | True
User Auth
cqlsh -u cassandra -p cassandra
Step 3 Grant permissions
cqlsh> create user ro_user with password '1234567';
cqlsh> grant all on killrvideo.user to dude;
cqlsh> grant select on killrvideo.user to ro_user;
SSL
http://thelastpickle.com/blog/2015/09/30/hardening-cassandra-step-by-step-part-1-server-to-server.html
10.0.0.1
10.0.0.4 10.0.0.2
10.0.0.3
• Create SSL certificates
• Copy to each server
• Start each node
Prepared Statements
• Built for speed an efficiency
How they work: Prepare
SELECT * FROM user WHERE id = ?
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
Client
Prepare
Parsed
Hashed Cached
Prepared Statement
How they work: Bind
id = 1 + PreparedStatement Hash
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
Client
Bind & Execute
Combine
Pre-parsed Query and
Variable
Execute
Result?
How to Prepare(Statements)
PreparedStatement userSelect = session.prepare(“SELECT * FROM user WHERE id = ?”);
BoundStatement userSelectStatement = new BoundStatement(userSelect);
session.execute(userSelectStatement.bind(1));
prepared_stmt = session.prepare (“SELECT * FROM user WHERE id = ?”)
bound_stmt = prepared_stmt.bind([1])
session.execute(bound_stmt)
Java
Python
Don’t do this
for (int i = 1; i < 100; i++) {
PreparedStatement userSelect = session.prepare(“SELECT * FROM user WHERE id = ?”);
BoundStatement userSelectStatement = new BoundStatement(userSelect);
session.execute(userSelectStatement.bind(1));
}
Execute vs Execute Async
• Very subtle difference
• Blocking vs non-blocking call
VS
Async
• Request pipelining
• One connection for requests
• Responses return whenever
Async
for (…) {
future = executeAsync(statement)
}
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
Client
Do something
for (…) {
result = future.get
}
Block
Batch vs Execute Async
VS
(Potentially)
Load Balancing Policies
cluster = Cluster
.builder()
.addContactPoint("192.168.0.30")
.withQueryOptions(new QueryOptions().setConsistencyLevel(ConsistencyLevel.ONE)
.withRetryPolicy(DefaultRetryPolicy.INSTANCE)
.withLoadBalancingPolicy(new TokenAwarePolicy(new DCAwareRoundRobinPolicy()))
.build();
session = cluster.connect("demo");
Data Locality
DC1
DC1: RF=3
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
Client
Read partition
15
DC2
10.1.0.1
00-25
10.1.0.4
76-100
10.1.0.2
26-50
10.1.0.3
51-75
76-100
51-75
00-25
76-100
26-50
00-25
51-75
26-50
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
DC2: RF=3
Client
Read partition
15
Batch (Logged)
• All statements collected on client
• Sent in one shot
• All done on 1 node
Batch is accepted
All actions are logged on
two replicas
Statements executed in
sequence
Results are collected and
returned
Batches: The good
• Great for denormalized inserts/updates
// Looking from the video side to many users
CREATE TABLE comments_by_video (
videoid uuid,
commentid timeuuid,
userid uuid,
comment text,
PRIMARY KEY (videoid, commentid)
) WITH CLUSTERING ORDER BY (commentid DESC);
// looking from the user side to many videos
CREATE TABLE comments_by_user (
userid uuid,
commentid timeuuid,
videoid uuid,
comment text,
PRIMARY KEY (userid, commentid)
) WITH CLUSTERING ORDER BY (commentid DESC);
Batches: The good
• Both inserts are run
• On failure, the batch log will replay
BEGIN BATCH
INSERT INTO comments_by_video (videoid, userid, commentid, comment)
VALUES (99051fe9-6a9c-46c2-b949-38ef78858dd0,d0f60aa8-54a9-4840-b70c-fe562b68842b,now(), 'Worst. Video. Ever.')
INSERT INTO comments_by_video (videoid, userid, commentid, comment)
VALUES (99051fe9-6a9c-46c2-b949-38ef78858dd0,d0f60aa8-54a9-4840-b70c-fe562b68842b,now(), 'Worst. Video. Ever.')
APPLY BATCH;
Batches: The bad
“I was doing a load test and nodes started blinking offline”
“Were you using a batch by any chance?”
“Why yes I was! How did you know?”
“How big was each batch?”
“1000 inserts each”
Batches: The bad
BEGIN BATCH
1000 inserts
APPLY BATCH;
10.0.0.1
00-25
10.0.0.4
76-100
10.0.0.2
26-50
10.0.0.3
51-75
Client
Batches: The rules
• Keep them small and for atomicity
CASSANDRA-6487 - Warn on large batches (5Kb default)
CASSANDRA-8011 - Fail on large batches (50Kb default)
The alternative
BEGIN BATCH
1000 inserts
APPLY BATCH;
while() {
future = session.executeAsync(statement)
}
Instead of:
Do this:
Old Row cache: The problem
• Reads an entire storage row of data
ID = 1
Partition Key
(Storage Row Key)
2014-09-08 12:00:00 :
name
SFO
2014-09-08 12:00:00 :
temp
63.4
2014-09-08 12:01:00 :
name
SFO
2014-09-08 12:00:00 :
temp
63.9
2014-09-08 12:02:00 :
name
SFO
2014-09-08 12:00:00 :
temp
64.0
Need this
Caches this
New Row Cache: The solution
• Stores just a few CQL rows
ID = 1
Partition Key
(Storage Row Key)
2014-09-08 12:00:00 :
name
SFO
2014-09-08 12:00:00 :
temp
63.4
2014-09-08 12:01:00 :
name
SFO
2014-09-08 12:00:00 :
temp
63.9
2014-09-08 12:02:00 :
name
SFO
2014-09-08 12:00:00 :
temp
64.0
Need this
Caches this
Using row cache
CREATE TABLE user_search_history_with_cache (
id int,
search_time timestamp,
search_text text,
search_results int,
PRIMARY KEY (id, search_time)
) WITH CLUSTERING ORDER BY (search_time DESC)
AND caching = { 'keys' : 'ALL', 'rows_per_partition' : '20' };
Perf increase
95th ms
Requests
Go make something awesome
Thank you!
Bring the questions
Follow me on twitter
@PatrickMcFadin

More Related Content

Advanced Cassandra

  • 1. ©2013 DataStax Confidential. Do not distribute without consent. @PatrickMcFadin Patrick McFadin
 Chief Evangelist, DataStax Advanced Cassandra 1
  • 6. Cassandra is not… 6 A Data Ocean or Pond., Lake An In-Memory Database A Key-Value Store A magical database unicorn that farts rainbows
  • 7. 7 When to use… Loose data model (joins, sub-selects) Absolute consistency (aka gotta have ACID) No need to use anything else You’ll miss the long, candle lit dinners with your Oracle rep that always end with “what’s your budget look like this year?” Oracle, MySQL, Postgres or <RDBMS>
  • 8. Uptime is a top priority Unpredictable or high scaling requirements Workload is transactional Willing to put the time or effort into understanding how Cassandra works and how to use it. 8 When to use… Use Oracle when you want to count your money. Use Cassandra when you want to make money. Cassandra
  • 9. Copy n Paste your relational model APACHE CASSANDRA
  • 12. Stick the landing 12 Going to deploy in production! Not sure about this! Done!
  • 13. Topology considerations Replication Strategy CREATE KEYSPACE killrvideo WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 }; Strategy Copies
  • 14. Topology considerations • Default • One data center SimpleStrategy NetworkTopologyStrategy • Use for multi-data center • Just use this always
  • 15. NetworkTopologyStrategy CREATE KEYSPACE Product_Catalog WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 3 }; CREATE KEYSPACE EU_Customer_Data WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'eu1' : 3 ‘eu2’ : 3 ‘us1’ : 0 }; Symmetric Asymmetric No copies in the US
  • 16. Application • Closer to customers • No downtime Product_Catalog RF=3 Product_Catalog RF=3 EU_Customer_Data RF=3 EU_Customer_Data RF=0 Product_Catalog RF=3 EU_Customer_Data RF=3
  • 18. Snitches DC1 DC1: RF=3 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 Client Where do I place this data? ? Dynamic Snitching Route based on node performance
  • 20. Snitches • Most typically used in production • Absolute placement GossipingPropertyFileSnitch cassandra-rackdc.properties dc=DC1 rack=RAC1
  • 21. Booting a datacenter DC1 DC1: RF=3 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 DC2 Pre-check • Use NetworkTopologyStrategy • In cassandra.yaml • auto_bootstrap: false • add seeds from other DC • Set node location for Snitch • GossipingPropertyFileSnitch: cassandra-rackdc.properties • PropertyFileSnitch: cassandra- topology.properties
  • 22. Booting a datacenter DC1 DC1: RF=3 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 DC2 10.1.0.1 00-25 10.1.0.4 76-100 10.1.0.2 26-50 10.1.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 DC2: RF=3 ALTER KEYSPACE
  • 23. Booting a datacenter DC1 DC1: RF=3 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 DC2 10.1.0.1 00-25 10.1.0.4 76-100 10.1.0.2 26-50 10.1.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 DC2: RF=3 nodetool rebuild
  • 25. NoSQL == No Security
  • 26. User Auth Step 1 Turn it on cassandra.yaml authorizer:PasswordAuthorizerAllowAllAuthorizer authenticator:AllowAllAuthenticatorPasswordAuthenticator
  • 27. User Auth cqlsh -u cassandra -p cassandra Step 2 Create users cqlsh> create user dude with password 'manager' superuser; cqlsh> create user worker with password 'newhire'; cqlsh> list users; name | super ----------+------- cassandra | True worker | False dude | True
  • 28. User Auth cqlsh -u cassandra -p cassandra Step 3 Grant permissions cqlsh> create user ro_user with password '1234567'; cqlsh> grant all on killrvideo.user to dude; cqlsh> grant select on killrvideo.user to ro_user;
  • 30. Prepared Statements • Built for speed an efficiency
  • 31. How they work: Prepare SELECT * FROM user WHERE id = ? 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 Client Prepare Parsed Hashed Cached Prepared Statement
  • 32. How they work: Bind id = 1 + PreparedStatement Hash 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 Client Bind & Execute Combine Pre-parsed Query and Variable Execute
  • 34. How to Prepare(Statements) PreparedStatement userSelect = session.prepare(“SELECT * FROM user WHERE id = ?”); BoundStatement userSelectStatement = new BoundStatement(userSelect); session.execute(userSelectStatement.bind(1)); prepared_stmt = session.prepare (“SELECT * FROM user WHERE id = ?”) bound_stmt = prepared_stmt.bind([1]) session.execute(bound_stmt) Java Python
  • 35. Don’t do this for (int i = 1; i < 100; i++) { PreparedStatement userSelect = session.prepare(“SELECT * FROM user WHERE id = ?”); BoundStatement userSelectStatement = new BoundStatement(userSelect); session.execute(userSelectStatement.bind(1)); }
  • 36. Execute vs Execute Async • Very subtle difference • Blocking vs non-blocking call VS
  • 37. Async • Request pipelining • One connection for requests • Responses return whenever
  • 38. Async for (…) { future = executeAsync(statement) } 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 Client Do something for (…) { result = future.get } Block
  • 39. Batch vs Execute Async VS (Potentially)
  • 40. Load Balancing Policies cluster = Cluster .builder() .addContactPoint("192.168.0.30") .withQueryOptions(new QueryOptions().setConsistencyLevel(ConsistencyLevel.ONE) .withRetryPolicy(DefaultRetryPolicy.INSTANCE) .withLoadBalancingPolicy(new TokenAwarePolicy(new DCAwareRoundRobinPolicy())) .build(); session = cluster.connect("demo");
  • 41. Data Locality DC1 DC1: RF=3 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 Client Read partition 15 DC2 10.1.0.1 00-25 10.1.0.4 76-100 10.1.0.2 26-50 10.1.0.3 51-75 76-100 51-75 00-25 76-100 26-50 00-25 51-75 26-50 Node Primary Replica Replica 10.0.0.1 00-25 76-100 51-75 10.0.0.2 26-50 00-25 76-100 10.0.0.3 51-75 26-50 00-25 10.0.0.4 76-100 51-75 26-50 DC2: RF=3 Client Read partition 15
  • 42. Batch (Logged) • All statements collected on client • Sent in one shot • All done on 1 node Batch is accepted All actions are logged on two replicas Statements executed in sequence Results are collected and returned
  • 43. Batches: The good • Great for denormalized inserts/updates // Looking from the video side to many users CREATE TABLE comments_by_video ( videoid uuid, commentid timeuuid, userid uuid, comment text, PRIMARY KEY (videoid, commentid) ) WITH CLUSTERING ORDER BY (commentid DESC); // looking from the user side to many videos CREATE TABLE comments_by_user ( userid uuid, commentid timeuuid, videoid uuid, comment text, PRIMARY KEY (userid, commentid) ) WITH CLUSTERING ORDER BY (commentid DESC);
  • 44. Batches: The good • Both inserts are run • On failure, the batch log will replay BEGIN BATCH INSERT INTO comments_by_video (videoid, userid, commentid, comment) VALUES (99051fe9-6a9c-46c2-b949-38ef78858dd0,d0f60aa8-54a9-4840-b70c-fe562b68842b,now(), 'Worst. Video. Ever.') INSERT INTO comments_by_video (videoid, userid, commentid, comment) VALUES (99051fe9-6a9c-46c2-b949-38ef78858dd0,d0f60aa8-54a9-4840-b70c-fe562b68842b,now(), 'Worst. Video. Ever.') APPLY BATCH;
  • 45. Batches: The bad “I was doing a load test and nodes started blinking offline” “Were you using a batch by any chance?” “Why yes I was! How did you know?” “How big was each batch?” “1000 inserts each”
  • 46. Batches: The bad BEGIN BATCH 1000 inserts APPLY BATCH; 10.0.0.1 00-25 10.0.0.4 76-100 10.0.0.2 26-50 10.0.0.3 51-75 Client
  • 47. Batches: The rules • Keep them small and for atomicity CASSANDRA-6487 - Warn on large batches (5Kb default) CASSANDRA-8011 - Fail on large batches (50Kb default)
  • 48. The alternative BEGIN BATCH 1000 inserts APPLY BATCH; while() { future = session.executeAsync(statement) } Instead of: Do this:
  • 49. Old Row cache: The problem • Reads an entire storage row of data ID = 1 Partition Key (Storage Row Key) 2014-09-08 12:00:00 : name SFO 2014-09-08 12:00:00 : temp 63.4 2014-09-08 12:01:00 : name SFO 2014-09-08 12:00:00 : temp 63.9 2014-09-08 12:02:00 : name SFO 2014-09-08 12:00:00 : temp 64.0 Need this Caches this
  • 50. New Row Cache: The solution • Stores just a few CQL rows ID = 1 Partition Key (Storage Row Key) 2014-09-08 12:00:00 : name SFO 2014-09-08 12:00:00 : temp 63.4 2014-09-08 12:01:00 : name SFO 2014-09-08 12:00:00 : temp 63.9 2014-09-08 12:02:00 : name SFO 2014-09-08 12:00:00 : temp 64.0 Need this Caches this
  • 51. Using row cache CREATE TABLE user_search_history_with_cache ( id int, search_time timestamp, search_text text, search_results int, PRIMARY KEY (id, search_time) ) WITH CLUSTERING ORDER BY (search_time DESC) AND caching = { 'keys' : 'ALL', 'rows_per_partition' : '20' };
  • 53. Go make something awesome
  • 54. Thank you! Bring the questions Follow me on twitter @PatrickMcFadin