Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Throw Some Keys on It: Data Modeling for Key-Value Data Stores by Example

Hector Castro
February 21, 2014

Throw Some Keys on It: Data Modeling for Key-Value Data Stores by Example

Relational databases are a great tool, but they are just one tool among many. If you have more data than fits on a single server and need a database that is highly available, then you should consider key/value data-storage. You may discover that they are a better fit for your needs.

Many key/value databases are designed to withstand multiple server and network failures, and to scale to dozens or hundreds of servers. In order to take advantage of that power you need to think differently about data modeling.

You will be amazed as to how much can be achieved with a key/value data store.

In this session, you will learn how to model your data to meet latency, scale and high-availability requirements using a high volume use-case of a mobile app that connects passengers with drivers of vehicles for hire, as well as coordinates ridesharing services.

Hector Castro

February 21, 2014
Tweet

More Decks by Hector Castro

Other Decks in Technology

Transcript

  1. mapping  =  {  }   mapping["p_cool_databas"]  =  "riak"   p

     mapping["p_cool_databas"]   #  =>  "riak"
  2. buckets/20140221133500/keys                  

                                         1_-­‐2
  3. def  emit_car_location(car_id,  color,  lat,  lon)      current_timestamp  =  Time.now.utc

         bucket  =  $client.bucket(current_timestamp.strftime($timestamp_format))   !    puts  "%s[%s]:  %s  is  at  [  %s,  %s  ]"  %  [          color,          current_timestamp.strftime($timestamp_format),          car_id,          lat,          lon      ]   !    cars  =  GSet.new      cars.add(car_id)   !    object  =  bucket.new("%s_%s"  %  [  lat,  lon  ])      object.content_type  =  "application/json"      object.data  =  cars.to_json   !    object.store(returnbody:  false)   end
  4. def      current_timestamp      bucket   !  

     puts        color,          current_timestamp        car_id,          lat,          lon      ]   !    cars      cars !    object      object    object !    object end        emit_car_location(car_id,  color,  lat,  lon)
  5. def      current_timestamp      bucket   !  

     puts        color,          current_timestamp        car_id,          lat,          lon      ]   !    cars      cars !    object      object    object !    object end ! !    bucket  =  $client.bucket(current_timestamp.strftime($timestamp_format))  
  6. def      current_timestamp      bucket   !  

     puts        color,          current_timestamp        car_id,          lat,          lon      ]   !    cars      cars !    object      object    object !    object end ! ! ! !    puts  "%s[%s]:  %s  is  at  [  %s,  %s  ]"  %  [          color,          current_timestamp.strftime($timestamp_format),          car_id,          lat,          lon      ]
  7. def      current_timestamp      bucket   !  

     puts        color,          current_timestamp        car_id,          lat,          lon      ]   !    cars      cars !    object      object    object !    object end ! ! ! ! ! ! ! ! ! ! ! !    cars  =  GSet.new      cars.add(car_id)
  8. Set union is commutative and convergent; therefore it is always

    safe to have simultaneous writes to a set which only allows addition.
  9. 1. An alternative to locking 2. A useful abstraction (Set,

    Counter, Map) 3. A way to resolve automatically toward a
 single value Provides:
  10. def      current_timestamp      bucket   !  

     puts        color,          current_timestamp        car_id,          lat,          lon      ]   !    cars      cars !    object      object    object !    object end ! ! ! ! ! ! ! ! ! ! ! ! ! ! !    object  =  bucket.new("%s_%s"  %  [  lat,  lon  ])      object.content_type  =  "application/json"      object.data  =  cars.to_json
  11. def  request_car(request_lat,  request_lon)      local_grid  =  closest_blocks(request_lat,  request_lon)  

    !    puts  "%s\n%%  Car  requested  in  [  %s,  %s  ]!\n\n"  %            ANSI.yellow,          request_lat,          request_lon      ]   !    local_grid.keys.sort.each  do  |distance|          lat,  lon  =  local_grid[distance].split("_")          closest_car  =  get_cars_at_location(lat,  lon)   !        if  closest_car.members.length  >  0              puts  "\n%%  Cars  closest  to  you:\n\n"              puts  JSON.pretty_generate(closest_car.members.to_a)              puts   !            break          end      end   end
  12. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end        request_car(request_lat,  request_lon)  
  13. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end !    local_grid  =  closest_blocks(request_lat,  request_lon)  
  14. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! !    puts  "%s\n%%  Car  requested  in  [  %s,  %s  ]!\n\n"  %            ANSI.yellow,          request_lat,          request_lon      ]  
  15. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! ! ! ! ! ! ! !    local_grid.keys.sort.each  do  |distance|  
  16. {      1.2424  =>  "2_1",      2.7335  =>

     "2_2",      5.8733  =>  "5_-­‐5"   }
  17. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! ! ! ! ! ! ! !    local_grid.keys.sort.each  do  |distance|          lat,  lon  =  local_grid[distance].split("_")          closest_car  =  get_cars_at_location(lat,  lon)  
  18. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! ! ! ! ! ! ! ! ! !        closest_car  =  get_cars_at_location(lat,  lon)  
  19. def  get_cars_at_location(lat,  lon)      current_timestamp  =  Time.now.utc  -­‐  1

         bucket  =  $client.bucket(current_timestamp.strftime($timestamp_format))      object  =  bucket.get_or_new("%s_%s"  %  [  lat,  lon  ])   !    cars  =  GSet.new   !    if  object.siblings.length  >  1          object.siblings.each  do  |sibling|              unless  sibling.data.nil?                  cars.merge_json(sibling.data)              end          end   !        resolved_object  =  bucket.new("%s_%s"  %  [  lat,  lon  ])          resolved_object.vclock  =  object.vclock          resolved_object.content_type  =  "application/json"          resolved_object.data  =  cars.to_json   !        resolved_object.store(returnbody:  false)      elsif  !object.data.nil?          cars.merge_json(object.data)      end   !    cars   end
  20.        get_cars_at_location(lat,  lon)   def      current_timestamp

         bucket      object   !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end
  21. !    current_timestamp  =  Time.now.utc  -­‐  1      bucket

     =  $client.bucket(current_timestamp.strftime($timestamp_format))      object  =  bucket.get_or_new("%s_%s"  %  [  lat,  lon  ])   def      current_timestamp      bucket      object   !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end
  22. ! ! ! ! !    cars  =  GSet.new  

    def      current_timestamp      bucket      object   !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end
  23. def      current_timestamp      bucket      object

      !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end ! ! ! ! ! ! !    if  object.siblings.length  >  1  
  24. {      "type":  "GSet",      "a":  ["car1",  "car22"]

      }   {      "type":  "GSet",      "a":  ["car7"]   }  
  25. ! ! ! ! ! ! ! !    

       object.siblings.each  do  |sibling|              unless  sibling.data.nil?                  cars.merge_json(sibling.data)              end          end def      current_timestamp      bucket      object   !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end
  26. ! ! ! ! ! ! ! ! ! !

    ! ! ! !        resolved_object  =  bucket.new("%s_%s"  %  [  lat,  lon  ])          resolved_object.vclock  =  object.vclock          resolved_object.content_type  =  "application/json"          resolved_object.data  =  cars.to_json   !        resolved_object.store(returnbody:  false)   def      current_timestamp      bucket      object   !    cars   !    if        object                            cars                     !        resolved_object          resolved_object        resolved_object        resolved_object !        resolved_object    elsif        cars    end !    cars   end
  27. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! ! ! ! ! ! ! ! ! !        closest_car  =  get_cars_at_location(lat,  lon)  
  28. def      local_grid   !    puts    

               request_lat,          request_lon      ]   !    local_grid        lat,  lon          closest_car   !                                             !                        end end ! ! ! ! ! ! ! ! ! ! ! ! !        if  closest_car.members.length  >  0              puts  "\n%%  Cars  closest  to  you:\n\n"              puts  JSON.pretty_generate(closest_car.members.to_a)              puts   !            break          end  
  29. bucket  =  $client.bucket(current_timestamp.strftime($timestamp_format))   cars  =  Riak::Crdt::Set.new(bucket,  "%s_%s"  %  [

     lat,  lon  ])   cars.add(car_id)   ! #  -­‐-­‐   ! cars.members   ! #<Set:  {"car1",  "car22",  "car7"}>