Top Banner
Cassandra & CassandraObject Michael Koziarski [email protected]
135

Intro to Cassandra and CassandraObject

Dec 05, 2014

Download

Technology

nzkoz

Slides from my cassandra talk at Railsconf 2010, not sure how useful they'll be without context, but people were asking.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 2: Intro to Cassandra and CassandraObject

Intro to Me

Page 3: Intro to Cassandra and CassandraObject
Page 4: Intro to Cassandra and CassandraObject
Page 5: Intro to Cassandra and CassandraObject
Page 6: Intro to Cassandra and CassandraObject
Page 7: Intro to Cassandra and CassandraObject

I Don’t Have To Scale

Page 8: Intro to Cassandra and CassandraObject

Intro to Cassandra

Page 9: Intro to Cassandra and CassandraObject
Page 10: Intro to Cassandra and CassandraObject

Distributed

Page 11: Intro to Cassandra and CassandraObject

Fault Tolerant

Page 12: Intro to Cassandra and CassandraObject

Elastic

Page 13: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 14: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 15: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 16: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 17: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 18: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 19: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

Page 20: Intro to Cassandra and CassandraObject

The Ring

C

A

B

D

E

F

someKey

RandomPartitioner OrderPreservingPartitionerMD5(key) key

Page 21: Intro to Cassandra and CassandraObject

Replication Factor

RF = 2

C

A

B

D

E

F

someKey

Page 22: Intro to Cassandra and CassandraObject

Replication Factor

C

A

B

D

E

F

someKey

RF = 3

Page 23: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ONE

Page 24: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ONE

Page 25: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ONE

Page 26: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ONE

Page 27: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.QUORUM

Page 28: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.QUORUM

Page 29: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.QUORUM

Page 30: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ALL

Page 31: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ALL

Page 32: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ALL

Page 33: Intro to Cassandra and CassandraObject

Consistency Level

C

A

B

D

E

F

GET 'someKey'

ConsistencyLevel.ALL

Page 34: Intro to Cassandra and CassandraObject

Fault Tolerance

C

A

DEAD

D

E

F

GET 'someKey'

ConsistencyLevel.QUORUM

Page 35: Intro to Cassandra and CassandraObject

Fault Tolerance

C

A

DEAD

D

E

F

GET 'someKey'

ConsistencyLevel.QUORUM

Page 36: Intro to Cassandra and CassandraObject

Fault Tolerance

C

A

D

E

F

GET 'someKey'

Page 37: Intro to Cassandra and CassandraObject

Elastic

C

A

B

D

E

F

NEW

Page 38: Intro to Cassandra and CassandraObject

Elastic

C

A

B

D

E

F

NEW

Page 39: Intro to Cassandra and CassandraObject

Data Model

Page 40: Intro to Cassandra and CassandraObject

Key Value Store

someKey Some Value

Page 41: Intro to Cassandra and CassandraObject

Column Store

Page 42: Intro to Cassandra and CassandraObject

Column

Page 43: Intro to Cassandra and CassandraObject

Column

firstName Michael

Page 44: Intro to Cassandra and CassandraObject

Row (Column Family)

firstName Michael

lastName KoziarskisomeKey

Page 45: Intro to Cassandra and CassandraObject

Row (Super Column Family)

firstName Michael

lastName KoziarskisomeSubColumn

firstName Kate

lastName KoziarskiotherSubColumn

someKey

Page 46: Intro to Cassandra and CassandraObject

JSON

Page 47: Intro to Cassandra and CassandraObject

Column

{    'name':  'first_name',    'value':  'Michael',    'timestamp':  1276040575}

Page 48: Intro to Cassandra and CassandraObject

Column

{    'first_name':  "Michael"}

Page 49: Intro to Cassandra and CassandraObject

Users["koz"]  =  {    'first_name':  'Michael',    'last_name':  'Koziarski'}

Column Family

Page 50: Intro to Cassandra and CassandraObject

Users["koz"]  =  {    'first_name':  'Michael',    'last_name':  'Koziarski'}

Column Family

Page 51: Intro to Cassandra and CassandraObject

Users["koz"]  =  {    'first_name':  'Michael',    'last_name':  'Koziarski'}

Column Family

Page 52: Intro to Cassandra and CassandraObject

Users["koz"]  =  {    'first_name':  'Michael',    'last_name':  'Koziarski'}

Column Family

Page 53: Intro to Cassandra and CassandraObject

UserAddresses["koz"]  =  {    "home"  :  {        "suburb":  "Berhampore"        "city":  "Wellington",        "country":  "New  Zealand"    },    "office"  :  {        "suburb":  "CBD"        "city":  "Wellington",        "country":  "New  Zealand"    }}

Super Column Family

Page 54: Intro to Cassandra and CassandraObject

Don’t let the name fool you

Page 55: Intro to Cassandra and CassandraObject

One to Many

Timeline["nzkoz"]  =  {    uuid_one:      "http://twitter.com/chadfowler/status/15740739666",      uuid_two:      "http://twitter.com/dhh/status/15740689762",    uuid_three:  "http://twitter.com/glv/status/15740546908"}

<ColumnFamily  CompareWith="TimeUUIDType"  Name="Timeline"/>

Page 56: Intro to Cassandra and CassandraObject

Modeling

Page 57: Intro to Cassandra and CassandraObject

Schema Driven Modeling

Page 58: Intro to Cassandra and CassandraObject

Start with your Data

Page 59: Intro to Cassandra and CassandraObject

Model

firstNamelastNamedateOfBirth

User

Page 60: Intro to Cassandra and CassandraObject

Figure out the Queries

Page 61: Intro to Cassandra and CassandraObject

Query

SELECT  firstName,  lastName  FROM      `users`WHERE  dateOfBirth  <  '1992-­‐06-­‐09'

Page 62: Intro to Cassandra and CassandraObject

Query

SELECT  dateOfBirthFROM      `users`WHERE  firstName  =  'Michael'                  AND            lastName  =  'Koziarski'

Page 63: Intro to Cassandra and CassandraObject

Query

SELECT  firstName,  lastName  FROM      `users`WHERE  YEAR(dateOfBirth)  =  1980

Page 64: Intro to Cassandra and CassandraObject

Query

SELECT  COUNT(DISTINCT  firstName)FROM  `users`WHERE  dateOfBirth  <  '1992-­‐06-­‐09'

Page 65: Intro to Cassandra and CassandraObject

Cassandra Limitations

Page 66: Intro to Cassandra and CassandraObject

No WHERE

Page 67: Intro to Cassandra and CassandraObject

No WHERE

Kinda

Page 68: Intro to Cassandra and CassandraObject

No ORDER

Page 69: Intro to Cassandra and CassandraObject

No ORDER

Kinda

Page 70: Intro to Cassandra and CassandraObject

No COUNT

Page 71: Intro to Cassandra and CassandraObject

No COUNTKinda

Page 72: Intro to Cassandra and CassandraObject

No SUM

Page 73: Intro to Cassandra and CassandraObject

Query DrivenModeling

Page 74: Intro to Cassandra and CassandraObject

Start with the Queries

Page 75: Intro to Cassandra and CassandraObject

Populate a data model which enables them

Page 76: Intro to Cassandra and CassandraObject

Modeling Example

Page 77: Intro to Cassandra and CassandraObject

Users

Users["koz"]  =  {    'first_name':  "Michael",    'last_name':  "Koziarski"}

Page 78: Intro to Cassandra and CassandraObject

Users

Users["koz"]  =  {    'first_name':  "Michael",    'last_name':  "Koziarski"}

connection.get(:Users,  "koz")

Page 79: Intro to Cassandra and CassandraObject

Koziarski Family

UsersByLastName["koziarski"]  =  {    uuid_one:  "koz"    uuid_two:  "kate"}

Page 80: Intro to Cassandra and CassandraObject

Koziarski Family

UsersByLastName["koziarski"]  =  {    uuid_one:  "koz"    uuid_two:  "kate"}

connection.get(:UsersByLastName,  "koziarski").values.map  do  |key|    connection.get(:Users,  key)end

Page 81: Intro to Cassandra and CassandraObject

Share my BirthdayUsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

Page 82: Intro to Cassandra and CassandraObject

Share my BirthdayUsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

connection.get(:UsersByDOB,  "1980-­‐08-­‐15")

Page 83: Intro to Cassandra and CassandraObject

Users Born in 1980UsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

Page 84: Intro to Cassandra and CassandraObject

Users Born in 1980UsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

connection.get_range(:UsersByDOB,  :start=>"1980",  :finish=>"1981")

Page 85: Intro to Cassandra and CassandraObject

Users Born in 1980UsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

connection.get_range(:UsersByDOB,  :start=>"1980",  :finish=>"1981")

Only with OrderPreservingPartitioner

Page 86: Intro to Cassandra and CassandraObject

A Column Family per Query

Page 87: Intro to Cassandra and CassandraObject

Do you really need Cassandra?

Page 88: Intro to Cassandra and CassandraObject

CassandraObject

Page 89: Intro to Cassandra and CassandraObject

class  Customer  <  CassandraObject::Base    attribute  :first_name,        :type  =>  :string    attribute  :last_name,          :type  =>  :string    attribute  :date_of_birth,  :type  =>  :date    attribute  :signed_up_at,    :type  =>  :time_with_zone

   validate  :should_be_cool

   key  :uuid

   index  :date_of_birth

   association  :invoices,  :unique=>false,  :inverse_of=>:customer

   private

   def  should_be_cool        unless  ["Michael",  "Anika",  "Evan",  "James"].include?(first_name)            errors.add(:first_name,  "must  be  that  of  a  cool  person")        end    endend

Page 90: Intro to Cassandra and CassandraObject

Motivations

Page 91: Intro to Cassandra and CassandraObject

Prove ActiveModel

Page 92: Intro to Cassandra and CassandraObject

Learn Cassandra

Page 93: Intro to Cassandra and CassandraObject

Have a fun Side Project

Page 94: Intro to Cassandra and CassandraObject

Solve my Scaling Problems

Page 95: Intro to Cassandra and CassandraObject

Solve my Scaling Problems

Page 96: Intro to Cassandra and CassandraObject

Mostly AR Compatible

Page 97: Intro to Cassandra and CassandraObject

Not Compatible

def  index    @people  =  @customer.people.order(params[:order]).                                                          limit(params[:limit]).                                                          where(...)end

Page 98: Intro to Cassandra and CassandraObject

Compatible

def  create    @person  =  Customer.new  params[:customer]    if  @person.save        redirect_to  @person    else        render  :action=>'new'    endend

Page 99: Intro to Cassandra and CassandraObject

Compatible

<%=  form_for(@customer)  do  |customer|  %>    <%=  customer.error_messages  %>    <%=  customer.text_field  :first_name  %>    <%=  customer.submit  "Save"  %><%  end  %>

Page 100: Intro to Cassandra and CassandraObject

Walkthrough

Page 101: Intro to Cassandra and CassandraObject

class  Customer  <  CassandraObject::Base    attribute  :first_name,        :type  =>  :string    attribute  :last_name,          :type  =>  :string    attribute  :date_of_birth,  :type  =>  :date    attribute  :signed_up_at,    :type  =>  :time_with_zone

   validate  :should_be_cool

   key  :uuid

   index  :date_of_birth

   association  :invoices,  :unique=>false,  :inverse_of=>:customer

   private

   def  should_be_cool        unless  ["Michael",  "Anika",  "Evan",  "James"].include?(first_name)            errors.add(:first_name,  "must  be  that  of  a  cool  person")        end    endend

Page 102: Intro to Cassandra and CassandraObject

class  Invoice  <  CassandraObject::Base    attribute  :number,  :type=>:integer    attribute  :total,  :type=>:float    attribute  :gst_number,  :type=>:string

   #  indexes  can  have  a  single  entry  also.    index  :number,  :unique=>true

   #  bi-­‐directional  associations  with  read-­‐repair  support.    association  :customer,  :unique=>true,  :inverse_of=>:invoices

   #  Read  migration  support    migrate  1  do  |attrs|        attrs["total"]  ||=  rand(2000)  /  100.0    end

   migrate  2  do  |attrs|        attrs["gst_number"]  =  "66-­‐666-­‐666"    end

   key  :natural,  :attributes  =>  :numberend

Page 103: Intro to Cassandra and CassandraObject

Attributes

attribute  :first_name,        :type  =>  :stringattribute  :last_name,          :type  =>  :stringattribute  :date_of_birth,  :type  =>  :dateattribute  :signed_up_at,    :type  =>  :time_with_zoneattribute  :number,                :type  =>  :integerattribute  :total,                  :type  =>  :floatattribute  :gst_number,        :type  =>  :string

Page 104: Intro to Cassandra and CassandraObject

Attributes

@customer.first_name  =  "Michael"@customer.attributes=  {:first_name=>"Michael"}

attribute  :first_name,  :type  =>  :string

Page 105: Intro to Cassandra and CassandraObject

Validationsvalidate  :should_be_cool

def  should_be_cool    unless  ["Michael",  "Anika",  "Evan",  "James"].include?(first_name)        errors.add(:first_name,  "must  be  that  of  a  cool  person")    endend

Page 106: Intro to Cassandra and CassandraObject

Validationsvalidate  :should_be_cool

def  should_be_cool    unless  ["Michael",  "Anika",  "Evan",  "James"].include?(first_name)        errors.add(:first_name,  "must  be  that  of  a  cool  person")    endend

@customer.first_name  =  "Marcel"@customer.valid?  #  =>  false

Page 107: Intro to Cassandra and CassandraObject

Validations

validates_confirmation_of  :tosvalidates_format_of  :gst_number,  :with=>  /.../validates_length_of  :first_name,  :max=>123

Page 108: Intro to Cassandra and CassandraObject

Keys

Page 109: Intro to Cassandra and CassandraObject

Key Selection Matters

Page 110: Intro to Cassandra and CassandraObject

Key Selection Matters

UsersByDOB["1980-­‐08-­‐15"]  =  {    uuid_one:  "koz"}

connection.get_range(:UsersByDOB,  :start=>"1980",  :finish=>"1981")

Page 111: Intro to Cassandra and CassandraObject

Keys

key  :uuid

Page 112: Intro to Cassandra and CassandraObject

Keys

key  :uuid

"bf1ba5da-­‐735a-­‐11df-­‐8b47-­‐377649cf993b"

Page 113: Intro to Cassandra and CassandraObject

Keys

key  :natural,  :attributes  =>  :number

Page 114: Intro to Cassandra and CassandraObject

Custom Key Factories

key  RedisKeyFactory.new(REDIS_CONNECTION,  "customer_key")

Page 115: Intro to Cassandra and CassandraObject

Custom Key Factoriesclass  RedisKeyFactory    def  initialize(connection,  key)        @connection,  @key  =  connection,  key    end        def  next_key(object)        @connection.incr(@key)    end        #  Parse  should  create  a  new  key  object  from  the  'to_param'  format    def  parse(string)        string.to_i    end        #  create  should  create  a  new  key  object  from  the  cassandra  format.    def  create(string)        string.to_i    end    end

Page 116: Intro to Cassandra and CassandraObject

Migrations

Page 117: Intro to Cassandra and CassandraObject

Migrationsclass  AddLicenseNameToArticle  <  ActiveRecord::Migration    def  self.up        add_column  :articles,  :license_name,  :string,  :default=>"Exclusive"

       execute  "UPDATE  articles  SET  license_name  =  'Exclusive'                                WHERE  price_first  IS  NOT  NULL"        execute  "UPDATE  articles  SET  license_name  =  'Syndicated'                            WHERE  price_first  IS  NULL"    end

   def  self.down        remove_column  :articles,  :license_name    endend

Page 118: Intro to Cassandra and CassandraObject

Migrations

{    'price_first':  45,    'schema_version':  0}

Page 119: Intro to Cassandra and CassandraObject

Migrationsclass  Article  <  CassandraObject::Base    attribute  :price_first,  :type=>:float    attribute  :license_name,  :type=>:string

   migrate  1  do  |attrs|        if  attrs[:price_first]            attrs[:license_name]  =  "Exclusive"        else            attrs[:license_name]  =  "Syndicated"        end    endend

Page 120: Intro to Cassandra and CassandraObject

Migrationsclass  Article  <  CassandraObject::Base    attribute  :price_first,  :type=>:float    attribute  :license_name,  :type=>:string

   migrate  1  do  |attrs|        if  attrs[:price_first]            attrs[:license_name]  =  "Exclusive"        else            attrs[:license_name]  =  "Syndicated"        end    endend

@article  =  Article.get("some-­‐old-­‐story")@article.license_name  #  =>  "Exclusive"

Page 121: Intro to Cassandra and CassandraObject

Migrations

{    'price_first':  45,    'schema_version':  1,    'license_name':  'Exclusive'}

Page 122: Intro to Cassandra and CassandraObject

Indexes

Page 123: Intro to Cassandra and CassandraObject

Indexesclass  Article  <  CassandraObject::Base    attribute  :slug,  :type=>:string    key  :uuid    index  :slug,  :unique=>trueend

connection.insert(:ArticlesBySlug,  @article.slug,                                      {UUID.new  =>  @article.key})

Page 124: Intro to Cassandra and CassandraObject

Indexesclass  Article  <  CassandraObject::Base    attribute  :slug,  :type=>:string    key  :uuid    index  :slug,  :unique=>trueend

@article  =  Article.find_by_slug("some-­‐slug")

connection.insert(:ArticlesBySlug,  @article.slug,                                      {UUID.new  =>  @article.key})

Page 125: Intro to Cassandra and CassandraObject

Indexes

class  Article  <  CassandraObject::Base    attribute  :publication_date,  :type=>:date    key  :uuid    index  :publication_date,  :unique=>falseend

connection.insert(:ArticlesByPublicationDate,                                      @article.publication_date,  

   {UUID.new  =>  @article.key})

Page 126: Intro to Cassandra and CassandraObject

Indexes

class  Article  <  CassandraObject::Base    attribute  :publication_date,  :type=>:date    key  :uuid    index  :publication_date,  :unique=>falseend

connection.insert(:ArticlesByPublicationDate,                                      @article.publication_date,  

   {UUID.new  =>  @article.key})

@article  =  Article.find_all_by_publication_date(Date.today  -­‐  1)

Page 127: Intro to Cassandra and CassandraObject

Indexes

class  Article  <  CassandraObject::Base    attribute  :publication_date,  :type=>:date    key  :uuid    index  :publication_date,  :unique=>falseend

connection.insert(:ArticlesByPublicationDate,                                      @article.publication_date,  

   {UUID.new  =>  @article.key})

@article  =  Article.find_all_by_publication_date(Date.today  -­‐  1)

Page 128: Intro to Cassandra and CassandraObject

Read-Repairresults  =  []connection.get(:ArticlesByPublicationDate,  date).each  do  |(uuid,  key)|    article  =  Article.get(uuid)    if  article.publication_date  !=  date        connection.delete(:ArticlesByPublicationDate,  date,  uuid)    else        results  <<  article    endendresults

Page 129: Intro to Cassandra and CassandraObject

Associations

Page 130: Intro to Cassandra and CassandraObject

Associationsclass  Invoice  <  CassandraObject::Base    association  :customer,  :unique=>true,  :inverse_of=>:invoicesend

class  Customer  <  CassandraObject::Base    association  :invoices,  :unique=>false,  :inverse_of=>:customerend

@customer.invoices.create!  params[:invoice]

@invoice.customer

Page 131: Intro to Cassandra and CassandraObject

Project Status

Page 132: Intro to Cassandra and CassandraObject

Very Beta

Page 133: Intro to Cassandra and CassandraObject

In Flux

Page 134: Intro to Cassandra and CassandraObject

Taking Patches