Data modelling
                                  workshop

                                  Richard Low



                           rlow@acunu.com @richardalow



Wednesday, 28 March 2012
Outline
                   • What is data modelling?
                   • What do I need to know to come up with a
                           model?
                   • Options and available tools
                   • Denormalisation
                   • Example and demo: scalable messaging
                           application


Wednesday, 28 March 2012
What is data modelling?




Wednesday, 28 March 2012
Data modelling

                   • How you organise your data
                   • Store all in one big value?
                   • Store as columns in one row or lots of rows?
                   • Use counters?
                   • Can I avoid read-modify-write?

Wednesday, 28 March 2012
Why care about it?

                   • Performance
                   • Ensure good load balancing
                   • Disk usage
                   • Future proofing

Wednesday, 28 March 2012
Performance

                        100
                 • Bad data model: do read-modify-write on
                              0x
                   large column im
                                      pro
                 • Good data model: just overwrite updated data
                                            vem
                 •                                  ent
                   Difference? Could be 100 ops/s vs. 100k ops/s




Wednesday, 28 March 2012
Performance

                   • Cacheability
                    • Ensure your cache isn’t polluted by
                             uncacheable things
                           • Cached reads are ~100x faster than
                             uncached



Wednesday, 28 March 2012
What do you need?



Wednesday, 28 March 2012
Optimise for queries


                   • Data model design starts with queries
                   • What are the common queries?


Wednesday, 28 March 2012
Workload

                   • How many inserts?
                   • How many reads?
                   • Do inserts depend on current data?
                   • Is data write-once?

Wednesday, 28 March 2012
Sizes
                   • How big are the values?
                   • Are some ‘users’ bigger than others?
                   • How cacheable is your data?




Wednesday, 28 March 2012
How do I get this?
        • Back of the envelope calculation
        • Monitor existing solution
        • Prototype a solution




Wednesday, 28 March 2012
Options and tools




Wednesday, 28 March 2012
Keyspaces and Column Families
                    SQL                                    Cassandra

          Database         row/key col_1    col_2
                                                            Keyspace
                              row/key col_1     col_1
                                   row/  col_1    col_1


                Table                                     Column Family




Wednesday, 28 March 2012
Options and tools

                   • Rows
                   • Columns
                    • Supercolumns
                    • Composite columns

Wednesday, 28 March 2012
Rows and columns
                           col1   col2   col3   col4   col5   col6   col7
                row1               x                    x      x
                row2        x      x      x      x      x
                row3               x      x             x      x      x
                row4               x      x      x             x
                row5               x             x      x      x
                row6               x
                row7        x      x             x



Wednesday, 28 March 2012
Column options

                   • Regular columns
                   • Super columns: columns within columns
                   • Composite columns: multi-dimensional
                           column names




Wednesday, 28 March 2012
Composite columns
                           alice: {
                              m2: {
                                 Sender: bob,
                                 Subject: ‘paper!’, ...
                              }
                           }

                           bob: {
                              m1: {
                                  Sender: alice,
                                  Subject: ‘rock?’, ...
                              }
                           }

                           charlie: {
                              m1: {
                                 Sender: alice,
                                 Subject: ‘rock?’, ...
                              },
                              m2: {
                                 Sender: bob,
                                 Subject: ‘paper!’, ...
                              }
                           }


Wednesday, 28 March 2012
Tools

                   • Counters: atomic inc and dec
                   • Expiring columns: TTL
                   • Secondary indexes: your WHERE clause


Wednesday, 28 March 2012
Rows vs columns
                   • Row key is the shard key
                   • Need lots of rows for scalability
                   • Don’t be afraid of large-ish rows
                    • But don’t make them too big
                   • Avoid range queries across rows, but use
                           them within rows


Wednesday, 28 March 2012
Range queries
               • Within a row:
                      SELECT col3..col5 FROM
                      Standard1 WHERE KEY=row1


             row1          col1   col2   col5   col6   col8




Wednesday, 28 March 2012
Range queries
             • Across rows:
                    SELECT * FROM table WHERE key >
                    row2 LIMIT 2




Wednesday, 28 March 2012
Range queries
    SELECT * FROM table
    WHERE key > row2                     row4
    LIMIT 2
     > row2, row1
                                                  row2


                                  row3          row1



Wednesday, 28 March 2012
Range queries

                   • Range queries within rows ‘get_slice’ are
                           fine
                   • Avoid range queries across rows
                           ‘get_range_slices’




Wednesday, 28 March 2012
Batching
                   • Overhead on each call
                   • Batch together inserts, better if in the same
                           row
                   • Reduce read ops, use large get_slice reads



Wednesday, 28 March 2012
Denormalisation




Wednesday, 28 March 2012
Denormalisation

                   • Hard drive performance constraints:
                    • Sequential IO at 100s MB/s
                    • Seek at 100 IO/s
                   • Avoid random IO

Wednesday, 28 March 2012
Denormalisation
                   • Store columns accessed at similar times near
                           to each other
                   • => put them in the same row
                   • Involves copying
                   • Copying isn’t bad - pre flood prices <$100
                           per TB



Wednesday, 28 March 2012
Messaging Application
Wednesday, 28 March 2012
Messaging application

                   • Users can send messages to other users
                   • Horizontally scalable
                   • Expect users to send to lots of recipients


Wednesday, 28 March 2012
Messaging

                   • In an RDBMS we might have a table for:
                    • Users
                    • Messages (sender is unique)
                    • Mappings, Message → Receiver


Wednesday, 28 March 2012
A relational model
                                         Msg_Receipt
                                               Id
                                           Message_Id   ∞
                                     ∞      User_Id
                       Users     1          Is_read
                                                            1   Messages
                           Id
                                                                   Id
                      username   1
                                                                 Subject
                                                                 Content
                                                                  Date
            Example Relational                              ∞
                                                                Sender_Id

               DB model

Wednesday, 28 March 2012
Querying
        Most recent 10 messages sent by a user:
                SELECT *
                    FROM Messages
                    WHERE Messages.Sender_Id = <id>
                    ORDER BY Messages.Date DESC
                    LIMIT 10;



         Most recent 10 messages received by a user:
                SELECT Messages.*
                    FROM Messages, Msg_Receipt
                    WHERE Msg_Receipt.User_Id = <id>
                    AND Msg_Receipt.Message_Id = Messages.Id
                    ORDER BY Messages.Date DESC
                    LIMIT 10;


Wednesday, 28 March 2012
Under the hood
                    Msg_Receipt                    Messages
              id           msg_id user_id    id     subject   ...
               0              0      0        0        a
               1              3      1        1        b
               2              4      2        2        c
               3            6000     0        3        d
                                              4        e
                                             ...
                                            6000      x


Wednesday, 28 March 2012
Under the hood

                   • Normalisation => seeks
                   • So denormalise
                    • Hit capacity limit of one node quickly


Wednesday, 28 March 2012
Back of the envelope...

                   • 1 M users
                   • Message size 1 KB
                   • Each user has 5000 messages
                   • => 5 TB data

Wednesday, 28 March 2012
Back of the envelope...

                   • Reading 10 messages => 10 seeks
                   • If 10k active at once, need 100k seeks/s
                   • => need 1000 disks
                   • With 8 disks per node, RF 3, that’s 375
                           nodes



Wednesday, 28 March 2012
Back of the envelope...

                   • Denormalize: messages are immutable
                   • Insert them into everyone’s inbox
                   • Read 10 messages is one seek
                   • Paging is sequential
                   • => 10x fewer nodes: 38 nodes now!

Wednesday, 28 March 2012
In Cassandra

                   • Use a row per user
                   • Composite columns, with TimeUUID as ID
                   • Gives time ordering on messages
                   • Inserts go to all recipients

Wednesday, 28 March 2012
Messaging example
                               From:    alice
                               To:      bob, charlie
                               Subject: rock?


                                                m1

                              alice

                                       sender        subject
                              bob
                                        alice         rock?
                                       sender        subject
                             charlie
                                        alice         rock?
Wednesday, 28 March 2012
Messaging example
                                From:    bob
                                To:      alice, charlie
                                Subject: paper!


                                    m1                      m2

                                                   sender        subject
     alice
                                                    bob          paper!
                           sender        subject
      bob
                            alice         rock?
                           sender        subject   sender        subject
  charlie
                            alice         rock?     bob          paper!
Wednesday, 28 March 2012
Data
                           alice: {
                              m2: {
                                 Sender: bob,
                                 Subject: ‘paper!’, ...
                              }
                           }

                           bob: {
                              m1: {
                                  Sender: alice,
                                  Subject: ‘rock?’, ...
                              }
                           }

                           charlie: {
                              m1: {
                                 Sender: alice,
                                 Subject: ‘rock?’, ...
                              },
                              m2: {
                                 Sender: bob,
                                 Subject: ‘paper!’, ...
                              }
                           }


Wednesday, 28 March 2012
Demo

                   • Pycassa
                   • Send message
                   • List messages
                   • Unread count

Wednesday, 28 March 2012

Cassandra EU 2012 - Data modelling workshop by Richard Low

  • 1.
    Data modelling workshop Richard Low rlow@acunu.com @richardalow Wednesday, 28 March 2012
  • 2.
    Outline • What is data modelling? • What do I need to know to come up with a model? • Options and available tools • Denormalisation • Example and demo: scalable messaging application Wednesday, 28 March 2012
  • 3.
    What is datamodelling? Wednesday, 28 March 2012
  • 4.
    Data modelling • How you organise your data • Store all in one big value? • Store as columns in one row or lots of rows? • Use counters? • Can I avoid read-modify-write? Wednesday, 28 March 2012
  • 5.
    Why care aboutit? • Performance • Ensure good load balancing • Disk usage • Future proofing Wednesday, 28 March 2012
  • 6.
    Performance 100 • Bad data model: do read-modify-write on 0x large column im pro • Good data model: just overwrite updated data vem • ent Difference? Could be 100 ops/s vs. 100k ops/s Wednesday, 28 March 2012
  • 7.
    Performance • Cacheability • Ensure your cache isn’t polluted by uncacheable things • Cached reads are ~100x faster than uncached Wednesday, 28 March 2012
  • 8.
    What do youneed? Wednesday, 28 March 2012
  • 9.
    Optimise for queries • Data model design starts with queries • What are the common queries? Wednesday, 28 March 2012
  • 10.
    Workload • How many inserts? • How many reads? • Do inserts depend on current data? • Is data write-once? Wednesday, 28 March 2012
  • 11.
    Sizes • How big are the values? • Are some ‘users’ bigger than others? • How cacheable is your data? Wednesday, 28 March 2012
  • 12.
    How do Iget this? • Back of the envelope calculation • Monitor existing solution • Prototype a solution Wednesday, 28 March 2012
  • 13.
  • 14.
    Keyspaces and ColumnFamilies SQL Cassandra Database row/key col_1 col_2 Keyspace row/key col_1 col_1 row/ col_1 col_1 Table Column Family Wednesday, 28 March 2012
  • 15.
    Options and tools • Rows • Columns • Supercolumns • Composite columns Wednesday, 28 March 2012
  • 16.
    Rows and columns col1 col2 col3 col4 col5 col6 col7 row1 x x x row2 x x x x x row3 x x x x x row4 x x x x row5 x x x x row6 x row7 x x x Wednesday, 28 March 2012
  • 17.
    Column options • Regular columns • Super columns: columns within columns • Composite columns: multi-dimensional column names Wednesday, 28 March 2012
  • 18.
    Composite columns alice: { m2: { Sender: bob, Subject: ‘paper!’, ... } } bob: { m1: { Sender: alice, Subject: ‘rock?’, ... } } charlie: { m1: { Sender: alice, Subject: ‘rock?’, ... }, m2: { Sender: bob, Subject: ‘paper!’, ... } } Wednesday, 28 March 2012
  • 19.
    Tools • Counters: atomic inc and dec • Expiring columns: TTL • Secondary indexes: your WHERE clause Wednesday, 28 March 2012
  • 20.
    Rows vs columns • Row key is the shard key • Need lots of rows for scalability • Don’t be afraid of large-ish rows • But don’t make them too big • Avoid range queries across rows, but use them within rows Wednesday, 28 March 2012
  • 21.
    Range queries • Within a row: SELECT col3..col5 FROM Standard1 WHERE KEY=row1 row1 col1 col2 col5 col6 col8 Wednesday, 28 March 2012
  • 22.
    Range queries • Across rows: SELECT * FROM table WHERE key > row2 LIMIT 2 Wednesday, 28 March 2012
  • 23.
    Range queries SELECT * FROM table WHERE key > row2 row4 LIMIT 2 > row2, row1 row2 row3 row1 Wednesday, 28 March 2012
  • 24.
    Range queries • Range queries within rows ‘get_slice’ are fine • Avoid range queries across rows ‘get_range_slices’ Wednesday, 28 March 2012
  • 25.
    Batching • Overhead on each call • Batch together inserts, better if in the same row • Reduce read ops, use large get_slice reads Wednesday, 28 March 2012
  • 26.
  • 27.
    Denormalisation • Hard drive performance constraints: • Sequential IO at 100s MB/s • Seek at 100 IO/s • Avoid random IO Wednesday, 28 March 2012
  • 28.
    Denormalisation • Store columns accessed at similar times near to each other • => put them in the same row • Involves copying • Copying isn’t bad - pre flood prices <$100 per TB Wednesday, 28 March 2012
  • 29.
  • 30.
    Messaging application • Users can send messages to other users • Horizontally scalable • Expect users to send to lots of recipients Wednesday, 28 March 2012
  • 31.
    Messaging • In an RDBMS we might have a table for: • Users • Messages (sender is unique) • Mappings, Message → Receiver Wednesday, 28 March 2012
  • 32.
    A relational model Msg_Receipt Id Message_Id ∞ ∞ User_Id Users 1 Is_read 1 Messages Id Id username 1 Subject Content Date Example Relational ∞ Sender_Id DB model Wednesday, 28 March 2012
  • 33.
    Querying Most recent 10 messages sent by a user: SELECT * FROM Messages WHERE Messages.Sender_Id = <id> ORDER BY Messages.Date DESC LIMIT 10; Most recent 10 messages received by a user: SELECT Messages.* FROM Messages, Msg_Receipt WHERE Msg_Receipt.User_Id = <id> AND Msg_Receipt.Message_Id = Messages.Id ORDER BY Messages.Date DESC LIMIT 10; Wednesday, 28 March 2012
  • 34.
    Under the hood Msg_Receipt Messages id msg_id user_id id subject ... 0 0 0 0 a 1 3 1 1 b 2 4 2 2 c 3 6000 0 3 d 4 e ... 6000 x Wednesday, 28 March 2012
  • 35.
    Under the hood • Normalisation => seeks • So denormalise • Hit capacity limit of one node quickly Wednesday, 28 March 2012
  • 36.
    Back of theenvelope... • 1 M users • Message size 1 KB • Each user has 5000 messages • => 5 TB data Wednesday, 28 March 2012
  • 37.
    Back of theenvelope... • Reading 10 messages => 10 seeks • If 10k active at once, need 100k seeks/s • => need 1000 disks • With 8 disks per node, RF 3, that’s 375 nodes Wednesday, 28 March 2012
  • 38.
    Back of theenvelope... • Denormalize: messages are immutable • Insert them into everyone’s inbox • Read 10 messages is one seek • Paging is sequential • => 10x fewer nodes: 38 nodes now! Wednesday, 28 March 2012
  • 39.
    In Cassandra • Use a row per user • Composite columns, with TimeUUID as ID • Gives time ordering on messages • Inserts go to all recipients Wednesday, 28 March 2012
  • 40.
    Messaging example From: alice To: bob, charlie Subject: rock? m1 alice sender subject bob alice rock? sender subject charlie alice rock? Wednesday, 28 March 2012
  • 41.
    Messaging example From: bob To: alice, charlie Subject: paper! m1 m2 sender subject alice bob paper! sender subject bob alice rock? sender subject sender subject charlie alice rock? bob paper! Wednesday, 28 March 2012
  • 42.
    Data alice: { m2: { Sender: bob, Subject: ‘paper!’, ... } } bob: { m1: { Sender: alice, Subject: ‘rock?’, ... } } charlie: { m1: { Sender: alice, Subject: ‘rock?’, ... }, m2: { Sender: bob, Subject: ‘paper!’, ... } } Wednesday, 28 March 2012
  • 43.
    Demo • Pycassa • Send message • List messages • Unread count Wednesday, 28 March 2012