135
Cassandra & CassandraObject Michael Koziarski [email protected]

Intro to Cassandra and CassandraObject

  • Upload
    nzkoz

  • View
    5.461

  • Download
    1

Embed Size (px)

DESCRIPTION

Slides from my cassandra talk at Railsconf 2010, not sure how useful they'll be without context, but people were asking.

Citation preview

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