SlideShare a Scribd company logo
1 of 64
Download to read offline
©2013 DataStax Confidential. Do not distribute without consent.
@chbatey
Christopher Batey

Technical Evangelist for Apache Cassandra
Avoiding anti-patterns: Staying in love with
Cassandra
@chbatey
Who am I?
• Technical Evangelist for Apache Cassandra
•Work on Stubbed Cassandra
•Help out Apache Cassandra users
• Built systems using Java/Spring/Dropwizard
with Cassandra @ Sky
• Follow me on twitter @chbatey
@chbatey
Anti patterns
• Client side joins
• Multi partition queries
• Batches
• Mutable data
• Retry policies
• Tombstones
• Secondary indices
• Includes home work + prize
@chbatey
Distributed joins
@chbatey
Cassandra can not join or aggregate
Client
Where do I go for the max?
@chbatey
Storing customer events
• Customer event
- customer_id - ChrisBatey
- staff_id - Charlie
- event_type - login, logout, add_to_basket, remove_from_basket
- time
• Store
- name
- store_type - Website, PhoneApp, Phone, Retail
- location
@chbatey
Model
CREATE TABLE customer_events(
customer_id text,
staff_id text,
time timeuuid,
event_type text,
store_name text,
PRIMARY KEY ((customer_id), time));
CREATE TABLE store(
store_name text,
location text,
store_type text,
PRIMARY KEY (store_name));
@chbatey
Reading this
client
RF3
C
Read latest customer event
CL = QUORUM
Read store information
C
@chbatey
One to one vs one to many
• This required possibly 6 out of 8 of our nodes to be up
• Imagine if there were multiple follow up queries
@chbatey
Multi-partition queries
• Client side joins normally end up falling into the more
general anti-pattern of multi partition queries
@chbatey
Adding staff link
CREATE TABLE customer_events(
customer_id text,
staff set<text>,
time timeuuid,
event_type text,
store_name text,
PRIMARY KEY ((customer_id), time));
CREATE TYPE staff(
name text,
favourite_colour text,
job_title text);
CREATE TYPE store(
store_name text,
location text,
store_type text);
@chbatey
Queries
select * from customer_events where customer_id = ‘chbatey’
limit 1
select * from staff where name in (staff1, staff2, staff3,
staff4)
Any one of these fails the whole query fails
@chbatey
Use a multi node cluster locally
@chbatey
Use a multi node cluster locally
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns Host ID
Rack
UN 127.0.0.1 102.27 KB 256 ? 15ad7694-3e76-4b74-aea0-fa3c0fa59532
rack1
UN 127.0.0.2 102.18 KB 256 ? cca7d0bb-e884-49f9-b098-e38fbe895cbc
rack1
UN 127.0.0.3 93.16 KB 256 ? 1f9737d3-c1b8-4df1-be4c-d3b1cced8e30
rack1
UN 127.0.0.4 102.1 KB 256 ? fe27b958-5d3a-4f78-9880-76cb7c9bead1
rack1
UN 127.0.0.5 93.18 KB 256 ? 66eb3f23-8889-44d6-a9e7-ecdd57ed61d0
rack1
UN 127.0.0.6 102.12 KB 256 ? e2e99a7b-c1fb-4f2a-9e4f-7a4666f8245e
rack1
@chbatey
Let’s see with with a 6 node cluster
INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'chbatey', 'red',
'Technical Evangelist' );
INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'luket', 'red',
'Technical Evangelist' );
INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'jonh', 'blue',
'Technical Evangelist' );
select * from staff where name in ('chbatey', 'luket', 'jonh');
@chbatey
Trace with CL ONE = 4 nodes used
Execute CQL3 query | 2015-02-02 06:39:58.759000 | 127.0.0.1 | 0
Parsing select * from staff where name in ('chbatey', 'luket', 'jonh'); [SharedPool-Worker-1] | 2015-02-02
06:39:58.766000 | 127.0.0.1 | 7553
Preparing statement [SharedPool-Worker-1] | 2015-02-02 06:39:58.768000 | 127.0.0.1 | 9249
Executing single-partition query on staff [SharedPool-Worker-3] | 2015-02-02 06:39:58.773000 | 127.0.0.1 | 14255
Sending message to /127.0.0.3 [WRITE-/127.0.0.3] | 2015-02-02 06:39:58.773001 | 127.0.0.1 | 14756
Sending message to /127.0.0.5 [WRITE-/127.0.0.5] | 2015-02-02 06:39:58.773001 | 127.0.0.1 | 14928
Sending message to /127.0.0.3 [WRITE-/127.0.0.3] | 2015-02-02 06:39:58.774000 | 127.0.0.1 | 16035
Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.777000 | 127.0.0.5 | 1156
Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.777001 | 127.0.0.5 | 1681
Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.778000 | 127.0.0.5 | 1944
Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.778000 | 127.0.0.3 | 1554
Processing response from /127.0.0.5 [SharedPool-Worker-3] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 20762
Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.779000 | 127.0.0.3 | 2425
Sending message to /127.0.0.5 [WRITE-/127.0.0.5] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 21198
Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.779000 | 127.0.0.3 | 2639
Sending message to /127.0.0.6 [WRITE-/127.0.0.6] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 21208
Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.780000 | 127.0.0.5 | 304
Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.780001 | 127.0.0.5 | 574
Executing single-partition query on staff [SharedPool-Worker-2] | 2015-02-02 06:39:58.781000 | 127.0.0.3 | 4075
Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.781000 | 127.0.0.5 | 708
Enqueuing response to /127.0.0.1 [SharedPool-Worker-2] | 2015-02-02 06:39:58.781001 | 127.0.0.3 | 4348
Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.782000 | 127.0.0.3 | 5371
Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.783000 | 127.0.0.6 | 2463
Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.784000 | 127.0.0.6 | 2905
Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.784001 | 127.0.0.6 | 3160
Processing response from /127.0.0.6 [SharedPool-Worker-2] | 2015-02-02 06:39:58.785000 | 127.0.0.1 | --
Request complete | 2015-02-02 06:39:58.782995 | 127.0.0.1 | 23995
@chbatey
Denormalise with UDTs
CREATE TYPE store (name text, type text, postcode text)
CREATE TYPE staff (name text, fav_colour text, job_title text)


CREATE TABLE customer_events(
customer_id text,
time timeuuid,
event_type text,
store store,
staff set<staff>,
PRIMARY KEY ((customer_id), time));
User defined types
@chbatey
Less obvious example
• A good pattern for time series: Bucketing
@chbatey
Adding a time bucket
CREATE TABLE customer_events_bucket(
customer_id text,
time_bucket text
time timeuuid,
event_type text,
store store,
staff set<staff>,
PRIMARY KEY ((customer_id, time_bucket), time));
@chbatey
Queries
select * from customer_events_bucket where customer_id =
‘chbatey’ and time_bucket IN (‘2015-01-01|0910:01’,
‘2015-01-01|0910:02’, ‘2015-01-01|0910:03’, ‘2015-01-01|
0910:04’)
Often better as multiple async queries
@chbatey
Tips for avoiding joins & multi gets
• Say no to client side joins by denormalising
- Much easier with UDTs
• When bucketing aim for at most two buckets for a query
• Get in the habit of reading trace + using a multi node
cluster locally
@chbatey
Unlogged Batches
@chbatey
Unlogged Batches
• Unlogged batches
- Send many statements as one
@chbatey
Customer events table
CREATE TABLE if NOT EXISTS customer_events (
customer_id text,
statff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (customer_id, time))
@chbatey
Inserting events
INSERT INTO events.customer_events (customer_id, time , event_type , statff_id , store_type ) VALUES
( ?, ?, ?, ?, ?)
public void storeEvent(ConsistencyLevel consistencyLevel, CustomerEvent customerEvent) {

BoundStatement boundInsert = insertStatement.bind(
customerEvent.getCustomerId(),
customerEvent.getTime(),
customerEvent.getEventType(),
customerEvent.getStaffId(),
customerEvent.getStaffId());



boundInsert.setConsistencyLevel(consistencyLevel);

session.execute(boundInsert);

}
@chbatey
Batch insert - Good idea?
public void storeEvents(ConsistencyLevel consistencyLevel, CustomerEvent... events) {

BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);



for (CustomerEvent event : events) {
BoundStatement boundInsert = insertStatement.bind(
customerEvent.getCustomerId(),
customerEvent.getTime(),
customerEvent.getEventType(),
customerEvent.getStaffId(),
customerEvent.getStaffId());



batchStatement.add(boundInsert);
}
session.execute(batchStatement);
}
@chbatey
Not so much
client
C
Very likely to fail if nodes are
down / over loaded
Gives far too much work for the coordinator
Ruins performance gains of
token aware driver
@chbatey
Individual queries
client
@chbatey
Unlogged batch use case
public void storeEvents(String customerId, ConsistencyLevel consistencyLevel, CustomerEvent...
events) {

BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);

batchStatement.enableTracing();



for (CustomerEvent event : events) {

BoundStatement boundInsert = insertStatement.bind(

customerId,

event.getTime(),

event.getEventType(),

event.getStaffId(),

event.getStaffId());

boundInsert.enableTracing();

boundInsert.setConsistencyLevel(consistencyLevel);

batchStatement.add(boundInsert);

}



ResultSet execute = session.execute(batchStatement);

logTraceInfo(execute.getExecutionInfo());

}
Partition Key!!
@chbatey
Writing this
client
C
All for the same partition :)
@chbatey
Logged Batches
@chbatey
Logged Batches
• Once accepted the statements will eventually succeed
• Achieved by writing them to a distributed batchlog
• 30% slower than unlogged batches
@chbatey
Batch insert - Good idea?
public void storeEvents(ConsistencyLevel consistencyLevel, CustomerEvent... events) {

BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.LOGGED);



for (CustomerEvent event : events) {
BoundStatement boundInsert = insertStatement.bind(
customerEvent.getCustomerId(),
customerEvent.getTime(),
customerEvent.getEventType(),
customerEvent.getStaffId(),
customerEvent.getStaffId());



batchStatement.add(boundInsert);
}
session.execute(batchStatement);
}
@chbatey
Not so much
client
C BATCH LOG
BL-R
BL-R
BL-R: Batch log replica
@chbatey
Use case?
CREATE TABLE if NOT EXISTS customer_events (
customer_id text,
statff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (customer_id, time))
CREATE TABLE if NOT EXISTS customer_events_by_staff (
customer_id text,
statff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (staff_id, time))
@chbatey
Storing events to both tables in a batch
public void storeEventLogged(ConsistencyLevel consistencyLevel, CustomerEvent customerEvent) {

BoundStatement boundInsertForCustomerId = insertByCustomerId.bind(customerEvent.getCustomerId(),
customerEvent.getTime(),
customerEvent.getEventType(),
customerEvent.getStaffId(),
customerEvent.getStaffId());

BoundStatement boundInsertForStaffId = insertByStaffId.bind(customerEvent.getCustomerId(),
customerEvent.getTime(),
customerEvent.getEventType(),
customerEvent.getStaffId(),
customerEvent.getStaffId());


BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.LOGGED);

batchStatement.enableTracing();

batchStatement.setConsistencyLevel(consistencyLevel);

batchStatement.add(boundInsertForCustomerId);

batchStatement.add(boundInsertForStaffId);





ResultSet execute = session.execute(batchStatement);

}
@chbatey
Mutable data
@chbatey
Distributed mutable state :-(
create TABLE accounts(customer text PRIMARY KEY, balance_in_pence int);
Overly naive example
• Cassandra uses last write wins (no Vector clocks)
• Read before write is an anti-pattern - race conditions and latency
@chbatey
Take a page from Event sourcing
create table accounts_log(
customer text,
time timeuuid,
delta int,
primary KEY (customer, time)); All records for the same customer in the same storage row
Transactions ordered by TIMEUUID - UUIDs are your friends in distributed systems
@chbatey
Tips
• Avoid mutable state in distributed system, favour
immutable log
• Can roll up and snapshot to avoid calculation getting too
big
• If you really have to then checkout LWTs and do via CAS
- this will be slower
@chbatey
Understanding failures
(crazy retry policies)
@chbatey
Write timeout
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
timeout
timeout
Write timeout
@chbatey
Retrying writes
• Cassandra does not roll back!
• R3 has the data and the coordinator has hinted for R1
and R2
@chbatey
Write timeout
• Received acknowledgements
• Required acknowledgements
• Consistency level
• CAS and Batches are more complicated:
- WriteType: SIMPLE, BATCH, UNLOGGED_BATCH,
BATCH_LOG, CAS
@chbatey
Batches
• BATCH_LOG
- Timed out waiting for batch log replicas
• BATCH
- Written to batch log but timed out waiting for actual replica
- Will eventually be committed
• UNLOGGED_BATCH
@chbatey
Idempotent writes
• All writes are idempotent with the following exceptions:
- Counters
- lists
@chbatey
Cassandra as a Queue (tombstones)
@chbatey
Well documented anti-pattern
• http://www.datastax.com/dev/blog/cassandra-anti-
patterns-queues-and-queue-like-datasets
• http://lostechies.com/ryansvihla/2014/10/20/domain-
modeling-around-deletes-or-using-cassandra-as-a-
queue-even-when-you-know-better/
@chbatey
Requirements
• Produce data in one DC
• Consume it once and delete from another DC
• Use Cassandra?
@chbatey
Datamodel
CREATE TABLE queues (
name text,
enqueued_at timeuuid,
payload blob,
PRIMARY KEY (name, enqueued_at)
);
SELECT enqueued_at, payload
FROM queues
WHERE name = 'queue-1'
LIMIT 1;
@chbatey
Trace
activity | source | elapsed
-------------------------------------------+-----------+--------
execute_cql3_query | 127.0.0.3 | 0
Parsing statement | 127.0.0.3 | 48
Peparing statement | 127.0.0.3 | 362
Message received from /127.0.0.3 | 127.0.0.1 | 42
Sending message to /127.0.0.1 | 127.0.0.3 | 718
Executing single-partition query on queues | 127.0.0.1 | 145
Acquiring sstable references | 127.0.0.1 | 158
Merging memtable contents | 127.0.0.1 | 189
Merging data from memtables and 0 sstables | 127.0.0.1 | 235
Read 1 live and 19998 tombstoned cells | 127.0.0.1 | 251102
Enqueuing response to /127.0.0.3 | 127.0.0.1 | 252976
Sending message to /127.0.0.3 | 127.0.0.1 | 253052
Message received from /127.0.0.1 | 127.0.0.3 | 324314
Not good :(
@chbatey
Tips
• Lots of deletes + range queries in the same partition
• Avoid it with data modelling / query pattern:
- Move partition
- Add a start for your range: e.g. enqueued_at >
9d1cb818-9d7a-11b6-96ba-60c5470cbf0e
@chbatey
Secondary Indices
@chbatey
Customer events table
CREATE TABLE if NOT EXISTS customer_events (
customer_id text,
staff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (customer_id, time))
create INDEX on customer_events (staff_id) ;
@chbatey
Indexes to the rescue?
customer_id time staff_id
chbatey 2015-03-03 08:52:45 trevor
chbatey 2015-03-03 08:52:54 trevor
chbatey 2015-03-03 08:53:11 bill
chbatey 2015-03-03 08:53:18 bill
rusty 2015-03-03 08:56:57 bill
rusty 2015-03-03 08:57:02 bill
rusty 2015-03-03 08:57:20 trevor
staff_id customer_id
trevor chbatey
trevor chbatey
bill chbatey
bill chbatey
bill rusty
bill rusty
trevor rusty
@chbatey
Inserts
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'rusty', 42730bf0-c183-11e4-a4c6-1971740a12cd, 'SELL', 'trevor', 'WEB');
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'rusty', 3f07cd70-c183-11e4-a4c6-1971740a12cd, 'BUY', 'trevor', 'WEB');
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'chbatey', a9550c70-c182-11e4-a4c6-1971740a12cd, 'BUY', 'trevor', 'WEB');
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'chbatey', aebbf3e0-c182-11e4-a4c6-1971740a12cd, 'SELL', 'trevor', 'WEB');
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'chbatey', b8c2f050-c182-11e4-a4c6-1971740a12cd, 'VIEW', 'bill', 'WEB');
INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES
( 'chbatey', bcb5ae50-c182-11e4-a4c6-1971740a12cd, 'BUY', 'bill', 'WEB');
@chbatey
Secondary index are local
• The staff_id partition in the secondary index is not
distributed like a normal table
• The secondary index entries are only stored on the node
that contains the customer_id partition
@chbatey
Indexes to the rescue?
staff_id customer_id
trevor chbatey
trevor chbatey
bill chbatey
bill chbatey
staff_id customer_id
bill rusty
bill rusty
trevor rusty
A B
chbatey rusty
customer_id time staff_id
chbatey 2015-03-03 08:52:45 trevor
chbatey 2015-03-03 08:52:54 trevor
chbatey 2015-03-03 08:53:11 bill
chbatey 2015-03-03 08:53:18 bill
rusty 2015-03-03 08:56:57 bill
rusty 2015-03-03 08:57:02 bill
rusty 2015-03-03 08:57:20 trevor
customer_events table
staff_id customer_id
trevor chbatey
trevor chbatey
bill chbatey
bill chbatey
bill rusty
bill rusty
trevor rusty
staff_id index
@chbatey
Homework
1. Use a cluster with 6 nodes (CCM)
2. Create the customer events table and add the secondary index
3. Insert the data (insert statements are in a hidden slide I’ll
distribute)
4. Turn tracing on and execute the following queries:
A. select * from customer_events where staff_id = 'trevor' ;
B. select * from customer_events where staff_id = 'trevor' and
customer_id = ‘chbatey’
5. How many partitions queried and nodes were used for each
query?
6. Send me the answer on twitter, first couple get SWAG!
@chbatey
Do it your self index
CREATE TABLE if NOT EXISTS customer_events (
customer_id text,
statff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (customer_id, time))
CREATE TABLE if NOT EXISTS customer_events_by_staff (
customer_id text,
statff_id text,
store_type text,
time timeuuid ,
event_type text,
PRIMARY KEY (staff_id, time))
@chbatey
Possibly in 3.0 - Global indexes
@chbatey
Anti patterns summary
• Most anti patterns are very obvious in trace output
• Don’t test on small clusters, most problems only occur at
scale
@chbatey
Thanks for listening
• Check out my blog: http://christopher-
batey.blogspot.co.uk/
- Answers for all questions
- Detailed posts on most of the anti patterns + full working code
• More questions? Contact me on twitter: @chbatey
• Learn more about read / write path, CCM checkout
DataStax academy
- https://academy.datastax.com/
Webinar Cassandra Anti-Patterns

More Related Content

Similar to Webinar Cassandra Anti-Patterns

LA Cassandra Day 2015 - Cassandra for developers
LA Cassandra Day 2015  - Cassandra for developersLA Cassandra Day 2015  - Cassandra for developers
LA Cassandra Day 2015 - Cassandra for developersChristopher Batey
 
MariaDB and Clickhouse Percona Live 2019 talk
MariaDB and Clickhouse Percona Live 2019 talkMariaDB and Clickhouse Percona Live 2019 talk
MariaDB and Clickhouse Percona Live 2019 talkAlexander Rubin
 
Introduction to Vitess on Kubernetes for MySQL - Webinar
Introduction to Vitess on Kubernetes for MySQL -  WebinarIntroduction to Vitess on Kubernetes for MySQL -  Webinar
Introduction to Vitess on Kubernetes for MySQL - WebinarAlkin Tezuysal
 
Apache Cassandra for Timeseries- and Graph-Data
Apache Cassandra for Timeseries- and Graph-DataApache Cassandra for Timeseries- and Graph-Data
Apache Cassandra for Timeseries- and Graph-DataGuido Schmutz
 
MySQL 8.0.19 - New Features Summary
MySQL 8.0.19 - New Features SummaryMySQL 8.0.19 - New Features Summary
MySQL 8.0.19 - New Features SummaryOlivier DASINI
 
AWS Cost Control
AWS Cost ControlAWS Cost Control
AWS Cost ControlBob Brown
 
Confoo 2021 -- MySQL New Features
Confoo 2021 -- MySQL New FeaturesConfoo 2021 -- MySQL New Features
Confoo 2021 -- MySQL New FeaturesDave Stokes
 
Deploying to Oracle SOA Suite 12c - Everything You Need To Know
Deploying to Oracle SOA Suite 12c - Everything You Need To KnowDeploying to Oracle SOA Suite 12c - Everything You Need To Know
Deploying to Oracle SOA Suite 12c - Everything You Need To KnowRevelation Technologies
 
Building a SaaS based product in Azure - Challenges and decisions made
Building a SaaS based product in Azure - Challenges and decisions madeBuilding a SaaS based product in Azure - Challenges and decisions made
Building a SaaS based product in Azure - Challenges and decisions madeBizTalk360
 
MySQL 8.0.22 - New Features Summary
MySQL 8.0.22 - New Features SummaryMySQL 8.0.22 - New Features Summary
MySQL 8.0.22 - New Features SummaryOlivier DASINI
 
Secret Techniques to Manage Apache Cloudstack with ActOnCloud
Secret Techniques to Manage Apache Cloudstack with ActOnCloudSecret Techniques to Manage Apache Cloudstack with ActOnCloud
Secret Techniques to Manage Apache Cloudstack with ActOnCloudMadan Ganesh Velayudham
 
Observability of InfluxDB IOx: Tracing, Metrics and System Tables
Observability of InfluxDB IOx: Tracing, Metrics and System TablesObservability of InfluxDB IOx: Tracing, Metrics and System Tables
Observability of InfluxDB IOx: Tracing, Metrics and System TablesInfluxData
 
Paris Day Cassandra: Use case
Paris Day Cassandra: Use caseParis Day Cassandra: Use case
Paris Day Cassandra: Use caseChristopher Batey
 
Migrating Customers to Microsoft Azure: Lessons Learned From the Field
Migrating Customers to Microsoft Azure: Lessons Learned From the FieldMigrating Customers to Microsoft Azure: Lessons Learned From the Field
Migrating Customers to Microsoft Azure: Lessons Learned From the FieldIdo Flatow
 
SQL Server & la virtualisation : « 45 minutes inside » !
SQL Server & la virtualisation :  « 45 minutes inside » !SQL Server & la virtualisation :  « 45 minutes inside » !
SQL Server & la virtualisation : « 45 minutes inside » !Microsoft Décideurs IT
 
SQL Server & la virtualisation : « 45 minutes inside » !
SQL Server & la virtualisation :  « 45 minutes inside » !SQL Server & la virtualisation :  « 45 minutes inside » !
SQL Server & la virtualisation : « 45 minutes inside » !Microsoft Technet France
 
Macy's: Changing Engines in Mid-Flight
Macy's: Changing Engines in Mid-FlightMacy's: Changing Engines in Mid-Flight
Macy's: Changing Engines in Mid-FlightDataStax Academy
 
You got a couple Microservices, now what? - Adding SRE to DevOps
You got a couple Microservices, now what?  - Adding SRE to DevOpsYou got a couple Microservices, now what?  - Adding SRE to DevOps
You got a couple Microservices, now what? - Adding SRE to DevOpsGonzalo Maldonado
 

Similar to Webinar Cassandra Anti-Patterns (20)

Advanced Cassandra
Advanced CassandraAdvanced Cassandra
Advanced Cassandra
 
LA Cassandra Day 2015 - Cassandra for developers
LA Cassandra Day 2015  - Cassandra for developersLA Cassandra Day 2015  - Cassandra for developers
LA Cassandra Day 2015 - Cassandra for developers
 
MariaDB and Clickhouse Percona Live 2019 talk
MariaDB and Clickhouse Percona Live 2019 talkMariaDB and Clickhouse Percona Live 2019 talk
MariaDB and Clickhouse Percona Live 2019 talk
 
Azure from scratch part 4
Azure from scratch part 4Azure from scratch part 4
Azure from scratch part 4
 
Introduction to Vitess on Kubernetes for MySQL - Webinar
Introduction to Vitess on Kubernetes for MySQL -  WebinarIntroduction to Vitess on Kubernetes for MySQL -  Webinar
Introduction to Vitess on Kubernetes for MySQL - Webinar
 
Apache Cassandra for Timeseries- and Graph-Data
Apache Cassandra for Timeseries- and Graph-DataApache Cassandra for Timeseries- and Graph-Data
Apache Cassandra for Timeseries- and Graph-Data
 
MySQL 8.0.19 - New Features Summary
MySQL 8.0.19 - New Features SummaryMySQL 8.0.19 - New Features Summary
MySQL 8.0.19 - New Features Summary
 
AWS Cost Control
AWS Cost ControlAWS Cost Control
AWS Cost Control
 
Confoo 2021 -- MySQL New Features
Confoo 2021 -- MySQL New FeaturesConfoo 2021 -- MySQL New Features
Confoo 2021 -- MySQL New Features
 
Deploying to Oracle SOA Suite 12c - Everything You Need To Know
Deploying to Oracle SOA Suite 12c - Everything You Need To KnowDeploying to Oracle SOA Suite 12c - Everything You Need To Know
Deploying to Oracle SOA Suite 12c - Everything You Need To Know
 
Building a SaaS based product in Azure - Challenges and decisions made
Building a SaaS based product in Azure - Challenges and decisions madeBuilding a SaaS based product in Azure - Challenges and decisions made
Building a SaaS based product in Azure - Challenges and decisions made
 
MySQL 8.0.22 - New Features Summary
MySQL 8.0.22 - New Features SummaryMySQL 8.0.22 - New Features Summary
MySQL 8.0.22 - New Features Summary
 
Secret Techniques to Manage Apache Cloudstack with ActOnCloud
Secret Techniques to Manage Apache Cloudstack with ActOnCloudSecret Techniques to Manage Apache Cloudstack with ActOnCloud
Secret Techniques to Manage Apache Cloudstack with ActOnCloud
 
Observability of InfluxDB IOx: Tracing, Metrics and System Tables
Observability of InfluxDB IOx: Tracing, Metrics and System TablesObservability of InfluxDB IOx: Tracing, Metrics and System Tables
Observability of InfluxDB IOx: Tracing, Metrics and System Tables
 
Paris Day Cassandra: Use case
Paris Day Cassandra: Use caseParis Day Cassandra: Use case
Paris Day Cassandra: Use case
 
Migrating Customers to Microsoft Azure: Lessons Learned From the Field
Migrating Customers to Microsoft Azure: Lessons Learned From the FieldMigrating Customers to Microsoft Azure: Lessons Learned From the Field
Migrating Customers to Microsoft Azure: Lessons Learned From the Field
 
SQL Server & la virtualisation : « 45 minutes inside » !
SQL Server & la virtualisation :  « 45 minutes inside » !SQL Server & la virtualisation :  « 45 minutes inside » !
SQL Server & la virtualisation : « 45 minutes inside » !
 
SQL Server & la virtualisation : « 45 minutes inside » !
SQL Server & la virtualisation :  « 45 minutes inside » !SQL Server & la virtualisation :  « 45 minutes inside » !
SQL Server & la virtualisation : « 45 minutes inside » !
 
Macy's: Changing Engines in Mid-Flight
Macy's: Changing Engines in Mid-FlightMacy's: Changing Engines in Mid-Flight
Macy's: Changing Engines in Mid-Flight
 
You got a couple Microservices, now what? - Adding SRE to DevOps
You got a couple Microservices, now what?  - Adding SRE to DevOpsYou got a couple Microservices, now what?  - Adding SRE to DevOps
You got a couple Microservices, now what? - Adding SRE to DevOps
 

More from Christopher Batey

Docker and jvm. A good idea?
Docker and jvm. A good idea?Docker and jvm. A good idea?
Docker and jvm. A good idea?Christopher Batey
 
LJC: Microservices in the real world
LJC: Microservices in the real worldLJC: Microservices in the real world
LJC: Microservices in the real worldChristopher Batey
 
Think your software is fault-tolerant? Prove it!
Think your software is fault-tolerant? Prove it!Think your software is fault-tolerant? Prove it!
Think your software is fault-tolerant? Prove it!Christopher Batey
 
Manchester Hadoop Meetup: Cassandra Spark internals
Manchester Hadoop Meetup: Cassandra Spark internalsManchester Hadoop Meetup: Cassandra Spark internals
Manchester Hadoop Meetup: Cassandra Spark internalsChristopher Batey
 
Cassandra London - 2.2 and 3.0
Cassandra London - 2.2 and 3.0Cassandra London - 2.2 and 3.0
Cassandra London - 2.2 and 3.0Christopher Batey
 
Cassandra London - C* Spark Connector
Cassandra London - C* Spark ConnectorCassandra London - C* Spark Connector
Cassandra London - C* Spark ConnectorChristopher Batey
 
3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developersChristopher Batey
 
Cassandra Day London: Building Java Applications
Cassandra Day London: Building Java ApplicationsCassandra Day London: Building Java Applications
Cassandra Day London: Building Java ApplicationsChristopher Batey
 
Data Science Lab Meetup: Cassandra and Spark
Data Science Lab Meetup: Cassandra and SparkData Science Lab Meetup: Cassandra and Spark
Data Science Lab Meetup: Cassandra and SparkChristopher Batey
 
Devoxx France: Fault tolerant microservices on the JVM with Cassandra
Devoxx France: Fault tolerant microservices on the JVM with CassandraDevoxx France: Fault tolerant microservices on the JVM with Cassandra
Devoxx France: Fault tolerant microservices on the JVM with CassandraChristopher Batey
 
Manchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationManchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationChristopher Batey
 
Manchester Hadoop User Group: Cassandra Intro
Manchester Hadoop User Group: Cassandra IntroManchester Hadoop User Group: Cassandra Intro
Manchester Hadoop User Group: Cassandra IntroChristopher Batey
 
Munich March 2015 - Cassandra + Spark Overview
Munich March 2015 -  Cassandra + Spark OverviewMunich March 2015 -  Cassandra + Spark Overview
Munich March 2015 - Cassandra + Spark OverviewChristopher Batey
 
Reading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkReading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkChristopher Batey
 
LA Cassandra Day 2015 - Testing Cassandra
LA Cassandra Day 2015  - Testing CassandraLA Cassandra Day 2015  - Testing Cassandra
LA Cassandra Day 2015 - Testing CassandraChristopher Batey
 
Voxxed Vienna 2015 Fault tolerant microservices
Voxxed Vienna 2015 Fault tolerant microservicesVoxxed Vienna 2015 Fault tolerant microservices
Voxxed Vienna 2015 Fault tolerant microservicesChristopher Batey
 

More from Christopher Batey (20)

Cassandra summit LWTs
Cassandra summit  LWTsCassandra summit  LWTs
Cassandra summit LWTs
 
Docker and jvm. A good idea?
Docker and jvm. A good idea?Docker and jvm. A good idea?
Docker and jvm. A good idea?
 
LJC: Microservices in the real world
LJC: Microservices in the real worldLJC: Microservices in the real world
LJC: Microservices in the real world
 
Think your software is fault-tolerant? Prove it!
Think your software is fault-tolerant? Prove it!Think your software is fault-tolerant? Prove it!
Think your software is fault-tolerant? Prove it!
 
Manchester Hadoop Meetup: Cassandra Spark internals
Manchester Hadoop Meetup: Cassandra Spark internalsManchester Hadoop Meetup: Cassandra Spark internals
Manchester Hadoop Meetup: Cassandra Spark internals
 
Cassandra London - 2.2 and 3.0
Cassandra London - 2.2 and 3.0Cassandra London - 2.2 and 3.0
Cassandra London - 2.2 and 3.0
 
Cassandra London - C* Spark Connector
Cassandra London - C* Spark ConnectorCassandra London - C* Spark Connector
Cassandra London - C* Spark Connector
 
IoT London July 2015
IoT London July 2015IoT London July 2015
IoT London July 2015
 
1 Dundee - Cassandra 101
1 Dundee - Cassandra 1011 Dundee - Cassandra 101
1 Dundee - Cassandra 101
 
2 Dundee - Cassandra-3
2 Dundee - Cassandra-32 Dundee - Cassandra-3
2 Dundee - Cassandra-3
 
3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers3 Dundee-Spark Overview for C* developers
3 Dundee-Spark Overview for C* developers
 
Cassandra Day London: Building Java Applications
Cassandra Day London: Building Java ApplicationsCassandra Day London: Building Java Applications
Cassandra Day London: Building Java Applications
 
Data Science Lab Meetup: Cassandra and Spark
Data Science Lab Meetup: Cassandra and SparkData Science Lab Meetup: Cassandra and Spark
Data Science Lab Meetup: Cassandra and Spark
 
Devoxx France: Fault tolerant microservices on the JVM with Cassandra
Devoxx France: Fault tolerant microservices on the JVM with CassandraDevoxx France: Fault tolerant microservices on the JVM with Cassandra
Devoxx France: Fault tolerant microservices on the JVM with Cassandra
 
Manchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra IntegrationManchester Hadoop Meetup: Spark Cassandra Integration
Manchester Hadoop Meetup: Spark Cassandra Integration
 
Manchester Hadoop User Group: Cassandra Intro
Manchester Hadoop User Group: Cassandra IntroManchester Hadoop User Group: Cassandra Intro
Manchester Hadoop User Group: Cassandra Intro
 
Munich March 2015 - Cassandra + Spark Overview
Munich March 2015 -  Cassandra + Spark OverviewMunich March 2015 -  Cassandra + Spark Overview
Munich March 2015 - Cassandra + Spark Overview
 
Reading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache SparkReading Cassandra Meetup Feb 2015: Apache Spark
Reading Cassandra Meetup Feb 2015: Apache Spark
 
LA Cassandra Day 2015 - Testing Cassandra
LA Cassandra Day 2015  - Testing CassandraLA Cassandra Day 2015  - Testing Cassandra
LA Cassandra Day 2015 - Testing Cassandra
 
Voxxed Vienna 2015 Fault tolerant microservices
Voxxed Vienna 2015 Fault tolerant microservicesVoxxed Vienna 2015 Fault tolerant microservices
Voxxed Vienna 2015 Fault tolerant microservices
 

Recently uploaded

Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....kzayra69
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 

Recently uploaded (20)

Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 

Webinar Cassandra Anti-Patterns

  • 1. ©2013 DataStax Confidential. Do not distribute without consent. @chbatey Christopher Batey
 Technical Evangelist for Apache Cassandra Avoiding anti-patterns: Staying in love with Cassandra
  • 2. @chbatey Who am I? • Technical Evangelist for Apache Cassandra •Work on Stubbed Cassandra •Help out Apache Cassandra users • Built systems using Java/Spring/Dropwizard with Cassandra @ Sky • Follow me on twitter @chbatey
  • 3. @chbatey Anti patterns • Client side joins • Multi partition queries • Batches • Mutable data • Retry policies • Tombstones • Secondary indices • Includes home work + prize
  • 5. @chbatey Cassandra can not join or aggregate Client Where do I go for the max?
  • 6. @chbatey Storing customer events • Customer event - customer_id - ChrisBatey - staff_id - Charlie - event_type - login, logout, add_to_basket, remove_from_basket - time • Store - name - store_type - Website, PhoneApp, Phone, Retail - location
  • 7. @chbatey Model CREATE TABLE customer_events( customer_id text, staff_id text, time timeuuid, event_type text, store_name text, PRIMARY KEY ((customer_id), time)); CREATE TABLE store( store_name text, location text, store_type text, PRIMARY KEY (store_name));
  • 8. @chbatey Reading this client RF3 C Read latest customer event CL = QUORUM Read store information C
  • 9. @chbatey One to one vs one to many • This required possibly 6 out of 8 of our nodes to be up • Imagine if there were multiple follow up queries
  • 10. @chbatey Multi-partition queries • Client side joins normally end up falling into the more general anti-pattern of multi partition queries
  • 11. @chbatey Adding staff link CREATE TABLE customer_events( customer_id text, staff set<text>, time timeuuid, event_type text, store_name text, PRIMARY KEY ((customer_id), time)); CREATE TYPE staff( name text, favourite_colour text, job_title text); CREATE TYPE store( store_name text, location text, store_type text);
  • 12. @chbatey Queries select * from customer_events where customer_id = ‘chbatey’ limit 1 select * from staff where name in (staff1, staff2, staff3, staff4) Any one of these fails the whole query fails
  • 13. @chbatey Use a multi node cluster locally
  • 14. @chbatey Use a multi node cluster locally Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns Host ID Rack UN 127.0.0.1 102.27 KB 256 ? 15ad7694-3e76-4b74-aea0-fa3c0fa59532 rack1 UN 127.0.0.2 102.18 KB 256 ? cca7d0bb-e884-49f9-b098-e38fbe895cbc rack1 UN 127.0.0.3 93.16 KB 256 ? 1f9737d3-c1b8-4df1-be4c-d3b1cced8e30 rack1 UN 127.0.0.4 102.1 KB 256 ? fe27b958-5d3a-4f78-9880-76cb7c9bead1 rack1 UN 127.0.0.5 93.18 KB 256 ? 66eb3f23-8889-44d6-a9e7-ecdd57ed61d0 rack1 UN 127.0.0.6 102.12 KB 256 ? e2e99a7b-c1fb-4f2a-9e4f-7a4666f8245e rack1
  • 15. @chbatey Let’s see with with a 6 node cluster INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'chbatey', 'red', 'Technical Evangelist' ); INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'luket', 'red', 'Technical Evangelist' ); INSERT INTO staff (name, favourite_colour , job_title ) VALUES ( 'jonh', 'blue', 'Technical Evangelist' ); select * from staff where name in ('chbatey', 'luket', 'jonh');
  • 16. @chbatey Trace with CL ONE = 4 nodes used Execute CQL3 query | 2015-02-02 06:39:58.759000 | 127.0.0.1 | 0 Parsing select * from staff where name in ('chbatey', 'luket', 'jonh'); [SharedPool-Worker-1] | 2015-02-02 06:39:58.766000 | 127.0.0.1 | 7553 Preparing statement [SharedPool-Worker-1] | 2015-02-02 06:39:58.768000 | 127.0.0.1 | 9249 Executing single-partition query on staff [SharedPool-Worker-3] | 2015-02-02 06:39:58.773000 | 127.0.0.1 | 14255 Sending message to /127.0.0.3 [WRITE-/127.0.0.3] | 2015-02-02 06:39:58.773001 | 127.0.0.1 | 14756 Sending message to /127.0.0.5 [WRITE-/127.0.0.5] | 2015-02-02 06:39:58.773001 | 127.0.0.1 | 14928 Sending message to /127.0.0.3 [WRITE-/127.0.0.3] | 2015-02-02 06:39:58.774000 | 127.0.0.1 | 16035 Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.777000 | 127.0.0.5 | 1156 Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.777001 | 127.0.0.5 | 1681 Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.778000 | 127.0.0.5 | 1944 Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.778000 | 127.0.0.3 | 1554 Processing response from /127.0.0.5 [SharedPool-Worker-3] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 20762 Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.779000 | 127.0.0.3 | 2425 Sending message to /127.0.0.5 [WRITE-/127.0.0.5] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 21198 Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.779000 | 127.0.0.3 | 2639 Sending message to /127.0.0.6 [WRITE-/127.0.0.6] | 2015-02-02 06:39:58.779000 | 127.0.0.1 | 21208 Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.780000 | 127.0.0.5 | 304 Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.780001 | 127.0.0.5 | 574 Executing single-partition query on staff [SharedPool-Worker-2] | 2015-02-02 06:39:58.781000 | 127.0.0.3 | 4075 Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.781000 | 127.0.0.5 | 708 Enqueuing response to /127.0.0.1 [SharedPool-Worker-2] | 2015-02-02 06:39:58.781001 | 127.0.0.3 | 4348 Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.782000 | 127.0.0.3 | 5371 Executing single-partition query on staff [SharedPool-Worker-1] | 2015-02-02 06:39:58.783000 | 127.0.0.6 | 2463 Enqueuing response to /127.0.0.1 [SharedPool-Worker-1] | 2015-02-02 06:39:58.784000 | 127.0.0.6 | 2905 Sending message to /127.0.0.1 [WRITE-/127.0.0.1] | 2015-02-02 06:39:58.784001 | 127.0.0.6 | 3160 Processing response from /127.0.0.6 [SharedPool-Worker-2] | 2015-02-02 06:39:58.785000 | 127.0.0.1 | -- Request complete | 2015-02-02 06:39:58.782995 | 127.0.0.1 | 23995
  • 17. @chbatey Denormalise with UDTs CREATE TYPE store (name text, type text, postcode text) CREATE TYPE staff (name text, fav_colour text, job_title text) 
 CREATE TABLE customer_events( customer_id text, time timeuuid, event_type text, store store, staff set<staff>, PRIMARY KEY ((customer_id), time)); User defined types
  • 18. @chbatey Less obvious example • A good pattern for time series: Bucketing
  • 19. @chbatey Adding a time bucket CREATE TABLE customer_events_bucket( customer_id text, time_bucket text time timeuuid, event_type text, store store, staff set<staff>, PRIMARY KEY ((customer_id, time_bucket), time));
  • 20. @chbatey Queries select * from customer_events_bucket where customer_id = ‘chbatey’ and time_bucket IN (‘2015-01-01|0910:01’, ‘2015-01-01|0910:02’, ‘2015-01-01|0910:03’, ‘2015-01-01| 0910:04’) Often better as multiple async queries
  • 21. @chbatey Tips for avoiding joins & multi gets • Say no to client side joins by denormalising - Much easier with UDTs • When bucketing aim for at most two buckets for a query • Get in the habit of reading trace + using a multi node cluster locally
  • 23. @chbatey Unlogged Batches • Unlogged batches - Send many statements as one
  • 24. @chbatey Customer events table CREATE TABLE if NOT EXISTS customer_events ( customer_id text, statff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (customer_id, time))
  • 25. @chbatey Inserting events INSERT INTO events.customer_events (customer_id, time , event_type , statff_id , store_type ) VALUES ( ?, ?, ?, ?, ?) public void storeEvent(ConsistencyLevel consistencyLevel, CustomerEvent customerEvent) {
 BoundStatement boundInsert = insertStatement.bind( customerEvent.getCustomerId(), customerEvent.getTime(), customerEvent.getEventType(), customerEvent.getStaffId(), customerEvent.getStaffId());
 
 boundInsert.setConsistencyLevel(consistencyLevel);
 session.execute(boundInsert);
 }
  • 26. @chbatey Batch insert - Good idea? public void storeEvents(ConsistencyLevel consistencyLevel, CustomerEvent... events) {
 BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);
 
 for (CustomerEvent event : events) { BoundStatement boundInsert = insertStatement.bind( customerEvent.getCustomerId(), customerEvent.getTime(), customerEvent.getEventType(), customerEvent.getStaffId(), customerEvent.getStaffId());
 
 batchStatement.add(boundInsert); } session.execute(batchStatement); }
  • 27. @chbatey Not so much client C Very likely to fail if nodes are down / over loaded Gives far too much work for the coordinator Ruins performance gains of token aware driver
  • 29. @chbatey Unlogged batch use case public void storeEvents(String customerId, ConsistencyLevel consistencyLevel, CustomerEvent... events) {
 BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);
 batchStatement.enableTracing();
 
 for (CustomerEvent event : events) {
 BoundStatement boundInsert = insertStatement.bind(
 customerId,
 event.getTime(),
 event.getEventType(),
 event.getStaffId(),
 event.getStaffId());
 boundInsert.enableTracing();
 boundInsert.setConsistencyLevel(consistencyLevel);
 batchStatement.add(boundInsert);
 }
 
 ResultSet execute = session.execute(batchStatement);
 logTraceInfo(execute.getExecutionInfo());
 } Partition Key!!
  • 30. @chbatey Writing this client C All for the same partition :)
  • 32. @chbatey Logged Batches • Once accepted the statements will eventually succeed • Achieved by writing them to a distributed batchlog • 30% slower than unlogged batches
  • 33. @chbatey Batch insert - Good idea? public void storeEvents(ConsistencyLevel consistencyLevel, CustomerEvent... events) {
 BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.LOGGED);
 
 for (CustomerEvent event : events) { BoundStatement boundInsert = insertStatement.bind( customerEvent.getCustomerId(), customerEvent.getTime(), customerEvent.getEventType(), customerEvent.getStaffId(), customerEvent.getStaffId());
 
 batchStatement.add(boundInsert); } session.execute(batchStatement); }
  • 34. @chbatey Not so much client C BATCH LOG BL-R BL-R BL-R: Batch log replica
  • 35. @chbatey Use case? CREATE TABLE if NOT EXISTS customer_events ( customer_id text, statff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (customer_id, time)) CREATE TABLE if NOT EXISTS customer_events_by_staff ( customer_id text, statff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (staff_id, time))
  • 36. @chbatey Storing events to both tables in a batch public void storeEventLogged(ConsistencyLevel consistencyLevel, CustomerEvent customerEvent) {
 BoundStatement boundInsertForCustomerId = insertByCustomerId.bind(customerEvent.getCustomerId(), customerEvent.getTime(), customerEvent.getEventType(), customerEvent.getStaffId(), customerEvent.getStaffId());
 BoundStatement boundInsertForStaffId = insertByStaffId.bind(customerEvent.getCustomerId(), customerEvent.getTime(), customerEvent.getEventType(), customerEvent.getStaffId(), customerEvent.getStaffId()); 
 BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.LOGGED);
 batchStatement.enableTracing();
 batchStatement.setConsistencyLevel(consistencyLevel);
 batchStatement.add(boundInsertForCustomerId);
 batchStatement.add(boundInsertForStaffId);
 
 
 ResultSet execute = session.execute(batchStatement);
 }
  • 38. @chbatey Distributed mutable state :-( create TABLE accounts(customer text PRIMARY KEY, balance_in_pence int); Overly naive example • Cassandra uses last write wins (no Vector clocks) • Read before write is an anti-pattern - race conditions and latency
  • 39. @chbatey Take a page from Event sourcing create table accounts_log( customer text, time timeuuid, delta int, primary KEY (customer, time)); All records for the same customer in the same storage row Transactions ordered by TIMEUUID - UUIDs are your friends in distributed systems
  • 40. @chbatey Tips • Avoid mutable state in distributed system, favour immutable log • Can roll up and snapshot to avoid calculation getting too big • If you really have to then checkout LWTs and do via CAS - this will be slower
  • 43. @chbatey Retrying writes • Cassandra does not roll back! • R3 has the data and the coordinator has hinted for R1 and R2
  • 44. @chbatey Write timeout • Received acknowledgements • Required acknowledgements • Consistency level • CAS and Batches are more complicated: - WriteType: SIMPLE, BATCH, UNLOGGED_BATCH, BATCH_LOG, CAS
  • 45. @chbatey Batches • BATCH_LOG - Timed out waiting for batch log replicas • BATCH - Written to batch log but timed out waiting for actual replica - Will eventually be committed • UNLOGGED_BATCH
  • 46. @chbatey Idempotent writes • All writes are idempotent with the following exceptions: - Counters - lists
  • 47. @chbatey Cassandra as a Queue (tombstones)
  • 48. @chbatey Well documented anti-pattern • http://www.datastax.com/dev/blog/cassandra-anti- patterns-queues-and-queue-like-datasets • http://lostechies.com/ryansvihla/2014/10/20/domain- modeling-around-deletes-or-using-cassandra-as-a- queue-even-when-you-know-better/
  • 49. @chbatey Requirements • Produce data in one DC • Consume it once and delete from another DC • Use Cassandra?
  • 50. @chbatey Datamodel CREATE TABLE queues ( name text, enqueued_at timeuuid, payload blob, PRIMARY KEY (name, enqueued_at) ); SELECT enqueued_at, payload FROM queues WHERE name = 'queue-1' LIMIT 1;
  • 51. @chbatey Trace activity | source | elapsed -------------------------------------------+-----------+-------- execute_cql3_query | 127.0.0.3 | 0 Parsing statement | 127.0.0.3 | 48 Peparing statement | 127.0.0.3 | 362 Message received from /127.0.0.3 | 127.0.0.1 | 42 Sending message to /127.0.0.1 | 127.0.0.3 | 718 Executing single-partition query on queues | 127.0.0.1 | 145 Acquiring sstable references | 127.0.0.1 | 158 Merging memtable contents | 127.0.0.1 | 189 Merging data from memtables and 0 sstables | 127.0.0.1 | 235 Read 1 live and 19998 tombstoned cells | 127.0.0.1 | 251102 Enqueuing response to /127.0.0.3 | 127.0.0.1 | 252976 Sending message to /127.0.0.3 | 127.0.0.1 | 253052 Message received from /127.0.0.1 | 127.0.0.3 | 324314 Not good :(
  • 52. @chbatey Tips • Lots of deletes + range queries in the same partition • Avoid it with data modelling / query pattern: - Move partition - Add a start for your range: e.g. enqueued_at > 9d1cb818-9d7a-11b6-96ba-60c5470cbf0e
  • 54. @chbatey Customer events table CREATE TABLE if NOT EXISTS customer_events ( customer_id text, staff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (customer_id, time)) create INDEX on customer_events (staff_id) ;
  • 55. @chbatey Indexes to the rescue? customer_id time staff_id chbatey 2015-03-03 08:52:45 trevor chbatey 2015-03-03 08:52:54 trevor chbatey 2015-03-03 08:53:11 bill chbatey 2015-03-03 08:53:18 bill rusty 2015-03-03 08:56:57 bill rusty 2015-03-03 08:57:02 bill rusty 2015-03-03 08:57:20 trevor staff_id customer_id trevor chbatey trevor chbatey bill chbatey bill chbatey bill rusty bill rusty trevor rusty
  • 56. @chbatey Inserts INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'rusty', 42730bf0-c183-11e4-a4c6-1971740a12cd, 'SELL', 'trevor', 'WEB'); INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'rusty', 3f07cd70-c183-11e4-a4c6-1971740a12cd, 'BUY', 'trevor', 'WEB'); INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'chbatey', a9550c70-c182-11e4-a4c6-1971740a12cd, 'BUY', 'trevor', 'WEB'); INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'chbatey', aebbf3e0-c182-11e4-a4c6-1971740a12cd, 'SELL', 'trevor', 'WEB'); INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'chbatey', b8c2f050-c182-11e4-a4c6-1971740a12cd, 'VIEW', 'bill', 'WEB'); INSERT INTO customer_events (customer_id, time , event_type , staff_id, store_type ) VALUES ( 'chbatey', bcb5ae50-c182-11e4-a4c6-1971740a12cd, 'BUY', 'bill', 'WEB');
  • 57. @chbatey Secondary index are local • The staff_id partition in the secondary index is not distributed like a normal table • The secondary index entries are only stored on the node that contains the customer_id partition
  • 58. @chbatey Indexes to the rescue? staff_id customer_id trevor chbatey trevor chbatey bill chbatey bill chbatey staff_id customer_id bill rusty bill rusty trevor rusty A B chbatey rusty customer_id time staff_id chbatey 2015-03-03 08:52:45 trevor chbatey 2015-03-03 08:52:54 trevor chbatey 2015-03-03 08:53:11 bill chbatey 2015-03-03 08:53:18 bill rusty 2015-03-03 08:56:57 bill rusty 2015-03-03 08:57:02 bill rusty 2015-03-03 08:57:20 trevor customer_events table staff_id customer_id trevor chbatey trevor chbatey bill chbatey bill chbatey bill rusty bill rusty trevor rusty staff_id index
  • 59. @chbatey Homework 1. Use a cluster with 6 nodes (CCM) 2. Create the customer events table and add the secondary index 3. Insert the data (insert statements are in a hidden slide I’ll distribute) 4. Turn tracing on and execute the following queries: A. select * from customer_events where staff_id = 'trevor' ; B. select * from customer_events where staff_id = 'trevor' and customer_id = ‘chbatey’ 5. How many partitions queried and nodes were used for each query? 6. Send me the answer on twitter, first couple get SWAG!
  • 60. @chbatey Do it your self index CREATE TABLE if NOT EXISTS customer_events ( customer_id text, statff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (customer_id, time)) CREATE TABLE if NOT EXISTS customer_events_by_staff ( customer_id text, statff_id text, store_type text, time timeuuid , event_type text, PRIMARY KEY (staff_id, time))
  • 61. @chbatey Possibly in 3.0 - Global indexes
  • 62. @chbatey Anti patterns summary • Most anti patterns are very obvious in trace output • Don’t test on small clusters, most problems only occur at scale
  • 63. @chbatey Thanks for listening • Check out my blog: http://christopher- batey.blogspot.co.uk/ - Answers for all questions - Detailed posts on most of the anti patterns + full working code • More questions? Contact me on twitter: @chbatey • Learn more about read / write path, CCM checkout DataStax academy - https://academy.datastax.com/