SlideShare a Scribd company logo
DISTRIBUTED
PATTERNS IN
ACTION
Eric Redmond
@coderoshi
http://git.io/MYrjpQ
basho
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
RESOURCE EXPANSION
(SOLUTION: SHARDING)
Thursday, July 25, 13
SHARDING INCREASES RISK
Thursday, July 25, 13
FAULT-TOLERANCE
(SOLUTION: REPLICATION)
Thursday, July 25, 13
REPLICATION ISTHE
ROOT OF ALL EVIL
Thursday, July 25, 13
THE CAUSE OF MOST
NETWORK PARTITIONS
Thursday, July 25, 13
THE CAPTHEOREM SUCKS
• Consistent
• Available
• Partition-Tolerant*
* http://codahale.com/you-cant-sacrifice-partition-tolerance
Thursday, July 25, 13
DON’T DISTRIBUTE DATASTORES,
STORE DISTRIBUTED DATA
Thursday, July 25, 13
IF IT CAN HAPPEN,
AT SCALE IT WILL HAPPEN
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
h	
  =	
  NaiveHash.new(("A".."J").to_a)
tracknodes	
  =	
  Array.new(100000)
100000.times	
  do	
  |i|
	
  	
  tracknodes[i]	
  =	
  h.node(i)
end
h.add("K")
misses	
  =	
  0
100000.times	
  do	
  |i|
	
  	
  misses	
  +=	
  1	
  if	
  tracknodes[i]	
  !=	
  h.node(i)
end
puts	
  "misses:	
  #{(misses.to_f/100000)	
  *	
  100}%"
misses:	
  90.922%
Thursday, July 25, 13
0
2160/2
2160
a single partition
SHA1(Key)
ring with 32 partitions
Node 0
Node 1
Node 2
Thursday, July 25, 13
0
2160/2
2160
a single partition
ring with 32 partitions
Node 0
Node 1
Node 2
Node 3
SHA1(Key)
Thursday, July 25, 13
SHA1BITS	
  =	
  160
class	
  PartitionedConsistentHash
	
  	
  def	
  initialize(nodes=[],	
  partitions=32)
	
  	
  	
  	
  @partitions	
  =	
  partitions
	
  	
  	
  	
  @nodes,	
  @ring	
  =	
  nodes.clone.sort,	
  {}
	
  	
  	
  	
  @power	
  =	
  SHA1BITS	
  -­‐	
  Math.log2(partitions).to_i
	
  	
  	
  	
  @partitions.times	
  do	
  |i|
	
  	
  	
  	
  	
  	
  @ring[range(i)]	
  =	
  @nodes[0]
	
  	
  	
  	
  	
  	
  @nodes	
  <<	
  @nodes.shift
	
  	
  	
  	
  end
	
  	
  	
  	
  @nodes.sort!
	
  	
  end
	
  	
  def	
  range(partition)
	
  	
  	
  	
  (partition*(2**@power)..(partition+1)*(2**@power)-­‐1)
	
  	
  end
	
  	
  def	
  hash(key)
	
  	
  	
  	
  Digest::SHA1.hexdigest(key.to_s).hex
	
  	
  end
	
  	
  def	
  add(node)
	
  	
  	
  	
  @nodes	
  <<	
  node
	
  	
  	
  	
  partition_pow	
  =	
  Math.log2(@partitions)
	
  	
  	
  	
  pow	
  =	
  SHA1BITS	
  -­‐	
  partition_pow.to_i
	
  	
  	
  	
  (0..@partitions).step(@nodes.length)	
  do	
  |i|
	
  	
  	
  	
  	
  	
  @ring[range(i,	
  pow)]	
  =	
  node
	
  	
  	
  	
  end
	
  	
  end
	
  	
  def	
  node(keystr)
	
  	
  	
  	
  return	
  nil	
  if	
  @ring.empty?
	
  	
  	
  	
  key	
  =	
  hash(keystr)
	
  	
  	
  	
  @ring.each	
  do	
  |range,	
  node|
	
  	
  	
  	
  	
  	
  return	
  node	
  if	
  range.cover?(key)
	
  	
  	
  	
  end
	
  	
  end
end
h	
  =	
  PartitionedConsistentHash.new(("A".."J").to_a)
nodes	
  =	
  Array.new(100000)
100000.times	
  do	
  |i|
	
  	
  nodes[i]	
  =	
  h.node(i)
end
puts	
  "add	
  K"
h.add("K")
misses	
  =	
  0
100000.times	
  do	
  |i|
	
  	
  misses	
  +=	
  1	
  if	
  nodes[i]	
  !=	
  h.node(i)
end
puts	
  "misses:	
  #{(misses.to_f/100000)	
  *	
  100}%n"
misses:	
  9.473%
Thursday, July 25, 13
class	
  Node
	
  	
  def	
  initialize(name,	
  nodes=[],	
  partitions=32)
	
  	
  	
  	
  @name	
  =	
  name
	
  	
  	
  	
  @data	
  =	
  {}
	
  	
  	
  	
  @ring	
  =	
  ConsistentHash.new(nodes,	
  partitions)
	
  	
  end
	
  	
  def	
  put(key,	
  value)
	
  	
  	
  	
  if	
  @name	
  ==	
  @ring.node(key)
	
  	
  	
  	
  	
  	
  puts	
  "put	
  #{key}	
  #{value}"
	
  	
  	
  	
  	
  	
  @data[	
  @ring.hash(key)	
  ]	
  =	
  value
	
  	
  	
  	
  end
	
  	
  end
	
  	
  def	
  get(key)
	
  	
  	
  	
  if	
  @name	
  ==	
  @ring.node(key)
	
  	
  	
  	
  	
  	
  puts	
  "get	
  #{key}"
	
  	
  	
  	
  	
  	
  @data[@ring.hash(key)]
	
  	
  	
  	
  end
	
  	
  end
end
Thursday, July 25, 13
nodeA	
  =	
  Node.new(	
  'A',	
  ['A',	
  'B',	
  'C']	
  )
nodeB	
  =	
  Node.new(	
  'B',	
  ['A',	
  'B',	
  'C']	
  )
nodeC	
  =	
  Node.new(	
  'C',	
  ['A',	
  'B',	
  'C']	
  )
nodeA.put(	
  "foo",	
  "bar"	
  )
p	
  nodeA.get(	
  "foo"	
  )	
  	
  	
  #	
  nil
nodeB.put(	
  "foo",	
  "bar"	
  )
p	
  nodeB.get(	
  "foo"	
  )	
  	
  	
  #	
  "bar"
nodeC.put(	
  "foo",	
  "bar"	
  )
p	
  nodeC.get(	
  "foo"	
  )	
  	
  	
  #	
  nil
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Client Service
Request
Reply
Thursday, July 25, 13
module	
  Services
	
  	
  def	
  connect(port=2200,	
  ip="127.0.0.1")
	
  	
  	
  	
  ctx	
  =	
  ZMQ::Context.new
	
  	
  	
  	
  sock	
  =	
  ctx.socket(	
  ZMQ::REQ	
  )
	
  	
  	
  	
  sock.connect(	
  "tcp://#{ip}:#{port}"	
  )
	
  	
  	
  	
  sock
	
  	
  end
	
  	
  def	
  service(port)
	
  	
  	
  	
  thread	
  do
	
  	
  	
  	
  	
  	
  ctx	
  =	
  ZMQ::Context.new
	
  	
  	
  	
  	
  	
  rep	
  =	
  ctx.socket(	
  ZMQ::REP	
  )
	
  	
  	
  	
  	
  	
  rep.bind(	
  "tcp://127.0.0.1:#{port}"	
  )
	
  	
  	
  	
  	
  	
  while	
  line	
  =	
  rep.recv
	
  	
  	
  	
  	
  	
  	
  	
  msg,	
  payload	
  =	
  line.split('	
  ',	
  2)
	
  	
  	
  	
  	
  	
  	
  	
  send(	
  msg.to_sym,	
  rep,	
  payload	
  )	
  	
  	
  	
  	
  #	
  EVVVIILLLL!!!
	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  end
	
  	
  end
	
  	
  def	
  method_missing(method,	
  *args,	
  &block)
	
  	
  	
  	
  socket,	
  payload	
  =	
  args
	
  	
  	
  	
  payload.send(	
  "bad	
  message"	
  )	
  if	
  payload
	
  	
  end
end
Thursday, July 25, 13
class	
  Node
	
  	
  include	
  Configuration
	
  	
  include	
  Threads
	
  	
  include	
  Services
	
  	
  def	
  start()
	
  	
  	
  	
  service(	
  config("port")	
  )
	
  	
  	
  	
  puts	
  "#{@name}	
  started"
	
  	
  	
  	
  join_threads()
	
  	
  end
	
  	
  def	
  remote_call(name,	
  message)
	
  	
  	
  	
  puts	
  "#{name}	
  <=	
  #{message}"
	
  	
  	
  	
  req	
  =	
  connect(config("port",	
  name),	
  config("ip",	
  name))
	
  	
  	
  	
  resp	
  =	
  req.send(message)	
  &&	
  req.recv
	
  	
  	
  	
  req.close
	
  	
  	
  	
  resp
	
  	
  end
	
  	
  #	
  ...
Thursday, July 25, 13
 	
  #	
  ...
	
  	
  def	
  put(socket,	
  payload)
	
  	
  	
  	
  key,	
  value	
  =	
  payload.split('	
  ',	
  2)
	
  	
  	
  	
  socket.send(	
  do_put(key,	
  value).to_s	
  )
	
  	
  end
	
  	
  def	
  do_put(key,	
  value)
	
  	
  	
  	
  node	
  =	
  @ring.node(key)
	
  	
  	
  	
  if	
  node	
  ==	
  @name
	
  	
  	
  	
  	
  	
  puts	
  "put	
  #{key}	
  #{value}"
	
  	
  	
  	
  	
  	
  @data[@ring.hash(key)]	
  =	
  value
	
  	
  	
  	
  else
	
  	
  	
  	
  	
  	
  remote_call(node,	
  "put	
  #{key}	
  #{value}"	
  )
	
  	
  	
  	
  end
	
  	
  end
Thursday, July 25, 13
#	
  start	
  a	
  Node	
  as	
  a	
  Server
name	
  =	
  ARGV.first
node	
  =	
  Node.new(name,	
  ['A','B','C'])
node.start()
$	
  ruby	
  node.rb	
  A
$	
  ruby	
  node.rb	
  B
$	
  ruby	
  node.rb	
  C
#	
  connect	
  with	
  a	
  client
require	
  'zmq'
ctx	
  =	
  ZMQ::Context.new
req	
  =	
  ctx.socket(ZMQ::REQ)
req.connect(	
  "tcp://127.0.0.1:2200"	
  )
puts	
  "Inserting	
  Values"
1000.times	
  do	
  |i|
	
  	
  req.send(	
  "put	
  key#{i}	
  value#{i}"	
  )	
  &&	
  req.recv
end
puts	
  "Getting	
  Values"
1000.times	
  do	
  |i|
	
  	
  puts	
  req.send(	
  "get	
  key#{i}"	
  )	
  &&	
  req.recv
end
req.close
Thursday, July 25, 13
Thursday, July 25, 13
Publisher
Subscriber
Subscriber
Subscriber
Thursday, July 25, 13
class	
  Node
	
  	
  #	
  ...
	
  	
  def	
  coordinate_cluster(pub_port,	
  rep_port)
	
  	
  	
  	
  thread	
  do
	
  	
  	
  	
  	
  	
  ctx	
  =	
  ZMQ::Context.new
	
  	
  	
  	
  	
  	
  pub	
  =	
  ctx.socket(	
  ZMQ::PUB	
  )
	
  	
  	
  	
  	
  	
  pub.bind(	
  "tcp://*:#{pub_port}"	
  )
	
  	
  	
  	
  	
  	
  rep	
  =	
  ctx.socket(	
  ZMQ::REP	
  )
	
  	
  	
  	
  	
  	
  rep.bind(	
  "tcp://*:#{rep_port}"	
  )
	
  	
  	
  	
  	
  	
  while	
  line	
  =	
  rep.recv
	
  	
  	
  	
  	
  	
  	
  	
  msg,	
  node	
  =	
  line.split('	
  ',	
  2)
	
  	
  	
  	
  	
  	
  	
  	
  nodes	
  =	
  @ring.nodes
	
  	
  	
  	
  	
  	
  	
  	
  case	
  msg
	
  	
  	
  	
  	
  	
  	
  	
  when	
  'join'
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  nodes	
  =	
  (nodes	
  <<	
  node).uniq.sort
	
  	
  	
  	
  	
  	
  	
  	
  when	
  'down'
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  nodes	
  -­‐=	
  [node]
	
  	
  	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  	
  	
  	
  	
  @ring.cluster(nodes)
	
  	
  	
  	
  	
  	
  	
  	
  pub.send(	
  "ring	
  "	
  +	
  nodes.join(','))
	
  	
  	
  	
  	
  	
  	
  	
  rep.send(	
  "true"	
  )
	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  end
	
  	
  end
Thursday, July 25, 13
class	
  Node
	
  	
  #	
  ...
	
  	
  def	
  track_cluster(sub_port)
	
  	
  	
  	
  thread	
  do
	
  	
  	
  	
  	
  	
  ctx	
  =	
  ZMQ::Context.new
	
  	
  	
  	
  	
  	
  sub	
  =	
  ctx.socket(	
  ZMQ::SUB	
  )
	
  	
  	
  	
  	
  	
  sub.connect(	
  "tcp://127.0.0.1:#{sub_port}"	
  )
	
  	
  	
  	
  	
  	
  sub.setsockopt(	
  ZMQ::SUBSCRIBE,	
  "ring"	
  )
	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  while	
  line	
  =	
  sub.recv
	
  	
  	
  	
  	
  	
  	
  	
  _,	
  nodes	
  =	
  line.split('	
  ',	
  2)
	
  	
  	
  	
  	
  	
  	
  	
  nodes	
  =	
  nodes.split(',').map{|x|	
  x.strip}
	
  	
  	
  	
  	
  	
  	
  	
  @ring.cluster(	
  nodes	
  )
	
  	
  	
  	
  	
  	
  	
  	
  puts	
  "ring	
  changed:	
  #{nodes.inspect}"
	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  end
	
  	
  end
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
 	
  def	
  replicate(message,	
  n)
	
  	
  	
  	
  list	
  =	
  @ring.pref_list(n)
	
  	
  	
  	
  results	
  =	
  []
	
  	
  	
  	
  while	
  replicate_node	
  =	
  list.shift
	
  	
  	
  	
  	
  	
  results	
  <<	
  remote_call(replicate_node,	
  message)
	
  	
  	
  	
  end
	
  	
  	
  	
  results
	
  	
  end
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
WHATTO EAT FOR DINNER?
• Adam wants Pizza
{value:"pizza", vclock:{adam:1}}
• Barb wantsTacos
{value:"tacos", vclock:{barb:1}}
• Adam gets the value, the system can’t resolve, so he gets bolth
[{value:"pizza", vclock:{adam:1}},
{value:"tacos", vclock:{barb:1}}]
• Adam resolves the value however he wants
{value:"taco pizza", vclock:{adam:2, barb:1}}
Thursday, July 25, 13
#	
  artificially	
  create	
  a	
  conflict	
  with	
  vclocks
req.send('put	
  1	
  foo	
  {"B":1}	
  hello1')	
  &&	
  req.recv
req.send('put	
  1	
  foo	
  {"C":1}	
  hello2')	
  &&	
  req.recv
puts	
  req.send("get	
  2	
  foo")	
  &&	
  req.recv
sleep	
  5
#	
  resolve	
  the	
  conflict	
  by	
  decending	
  from	
  one	
  of	
  the	
  vclocks
req.send('put	
  2	
  foo	
  {"B":3}	
  hello1')	
  &&	
  req.recv
puts	
  req.send("get	
  2	
  foo")	
  &&	
  req.recv
Thursday, July 25, 13
• choose a value at random
• siblings (user resolution)
• defined resolution (eg. CRDT)
CONFLICT RESOLUTION
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
1.
2.
3.
4.
Thursday, July 25, 13
Thursday, July 25, 13
MERKEL TREEMERKEL TREE
Thursday, July 25, 13
* Thanks Joe Blomstedt
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
Thursday, July 25, 13
array	
  	
  =	
  [{value:1},{value:3},{value:5}]
mapped	
  =	
  array.map{|obj|	
  obj[:value]}
#	
  [1,	
  3,	
  5]
mapped.reduce(0){|sum,value|	
  sum	
  +	
  value}
#	
  9
Thursday, July 25, 13
Thursday, July 25, 13
module	
  Mapreduce
	
  	
  def	
  mr(socket,	
  payload)
	
  	
  	
  	
  map_func,	
  reduce_func	
  =	
  payload.split(/;s+reduce/,	
  2)
	
  	
  	
  	
  reduce_func	
  =	
  "reduce#{reduce_func}"
	
  	
  	
  	
  socket.send(	
  Reduce.new(reduce_func,	
  call_maps(map_func)).call.to_s	
  )
	
  	
  end
	
  	
  def	
  map(socket,	
  payload)
	
  	
  	
  	
  socket.send(	
  Map.new(payload,	
  @data).call.to_s	
  )
	
  	
  end
	
  	
  #	
  run	
  in	
  parallel,	
  then	
  join	
  results
	
  	
  def	
  call_maps(map_func)
	
  	
  	
  	
  results	
  =	
  []
	
  	
  	
  	
  nodes	
  =	
  @ring.nodes	
  -­‐	
  [@name]
	
  	
  	
  	
  nodes.map	
  {|node|
	
  	
  	
  	
  	
  	
  Thread.new	
  do
	
  	
  	
  	
  	
  	
  	
  	
  res	
  =	
  remote_call(node,	
  "map	
  #{map_func}")
	
  	
  	
  	
  	
  	
  	
  	
  results	
  +=	
  eval(res)
	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  }.each{|w|	
  w.join}
	
  	
  	
  	
  results	
  +=	
  Map.new(map_func,	
  @data).call
	
  	
  end
end
Thursday, July 25, 13
module	
  Mapreduce
	
  	
  def	
  mr(socket,	
  payload)
	
  	
  	
  	
  map_func,	
  reduce_func	
  =	
  payload.split(/;s+reduce/,	
  2)
	
  	
  	
  	
  reduce_func	
  =	
  "reduce#{reduce_func}"
	
  	
  	
  	
  socket.send(	
  Reduce.new(reduce_func,	
  call_maps(map_func)).call.to_s	
  )
	
  	
  end
	
  	
  def	
  map(socket,	
  payload)
	
  	
  	
  	
  socket.send(	
  Map.new(payload,	
  @data).call.to_s	
  )
	
  	
  end
	
  	
  #	
  run	
  in	
  parallel,	
  then	
  join	
  results
	
  	
  def	
  call_maps(map_func)
	
  	
  	
  	
  results	
  =	
  []
	
  	
  	
  	
  nodes	
  =	
  @ring.nodes	
  -­‐	
  [@name]
	
  	
  	
  	
  nodes.map	
  {|node|
	
  	
  	
  	
  	
  	
  Thread.new	
  do
	
  	
  	
  	
  	
  	
  	
  	
  res	
  =	
  remote_call(node,	
  "map	
  #{map_func}")
	
  	
  	
  	
  	
  	
  	
  	
  results	
  +=	
  eval(res)
	
  	
  	
  	
  	
  	
  end
	
  	
  	
  	
  }.each{|w|	
  w.join}
	
  	
  	
  	
  results	
  +=	
  Map.new(map_func,	
  @data).call
	
  	
  end
end
Thursday, July 25, 13
200.times	
  do	
  |i|
	
  	
  req.send(	
  "put	
  2	
  key#{i}	
  {}	
  #{i}"	
  )	
  &&	
  req.recv
end
req.send(	
  "mr	
  map{|k,v|	
  [1]};	
  reduce{|vs|	
  vs.length}"	
  )
puts	
  req.recv
Thursday, July 25, 13
200.times	
  do	
  |i|
	
  	
  req.send(	
  "put	
  2	
  key#{i}	
  {}	
  #{i}"	
  )	
  &&	
  req.recv
end
req.send(	
  "mr	
  map{|k,v|	
  [1]};	
  reduce{|vs|	
  vs.length}"	
  )
puts	
  req.recv
Thursday, July 25, 13
ONE FINAL IMPROVEMENT
• C!
• A!
• P!
Thursday, July 25, 13
N/R/W
• N! # of Nodes to replicate a value to (in total)
• R! # of nodes to Read a value from (before success)
• W! # of nodes to Write a value to (before success)
Thursday, July 25, 13
Node A Node B Node C Node D Node E
N = 3 Write an Object
Node A Node B Node C Node D Node E
W = 2 Write an Object
replicate
replicate to
C & D
respond first
Node A Node B Node C Node D Node E
R = 2 Read an Object
C & E
respond first
eventually
replicate to
request from
Thursday, July 25, 13
EVENTUALLY CONSISTENT
• How Eventual?
• How Consistent?
Le mieux est l'ennemi du bien
Thursday, July 25, 13
Probabilistically Bounded Staleness
N=3, R=1,W=2
* http://pbs.cs.berkeley.edu
Thursday, July 25, 13
N=3,R=2,W=2
Thursday, July 25, 13
http://git.io/MYrjpQ
* thanks JD
Thursday, July 25, 13
Distributed Hash Ring
Vector Clocks
Preference List
MerkelTree
Read Repair
Key/Value
CRDT (counters, more coming)
Node Gossip
Request/
Response
Thursday, July 25, 13
basho
http://littleriakbook.comhttp://pragprog.com/book/rwdata
@coderoshi
Thursday, July 25, 13

More Related Content

What's hot

D-Talk: What's awesome about Ruby 2.x and Rails 4
D-Talk: What's awesome about Ruby 2.x and Rails 4D-Talk: What's awesome about Ruby 2.x and Rails 4
D-Talk: What's awesome about Ruby 2.x and Rails 4
Jan Berdajs
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
Tsuyoshi Yamamoto
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful wedding
Stéphane Wirtel
 
The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181
Mahmoud Samir Fayed
 
Go for the paranoid network programmer
Go for the paranoid network programmerGo for the paranoid network programmer
Go for the paranoid network programmer
Eleanor McHugh
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.Mike Fogus
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Tsuyoshi Yamamoto
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureMike Fogus
 
Lập trình Python cơ bản
Lập trình Python cơ bảnLập trình Python cơ bản
Lập trình Python cơ bản
Nguyen Thi Lan Phuong
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Voce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu CodigoVoce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu Codigo
Victor Hugo Germano
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutines
Freddie Wang
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
André Faria Gomes
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1
Ke Wei Louis
 
Current State of Coroutines
Current State of CoroutinesCurrent State of Coroutines
Current State of Coroutines
Guido Pio Mariotti
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency
명신 김
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
Eleanor McHugh
 
Kotlin coroutines
Kotlin coroutines Kotlin coroutines
Kotlin coroutines
TSE-JU LIN(Louis)
 

What's hot (20)

D-Talk: What's awesome about Ruby 2.x and Rails 4
D-Talk: What's awesome about Ruby 2.x and Rails 4D-Talk: What's awesome about Ruby 2.x and Rails 4
D-Talk: What's awesome about Ruby 2.x and Rails 4
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful wedding
 
The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181
 
Go for the paranoid network programmer
Go for the paranoid network programmerGo for the paranoid network programmer
Go for the paranoid network programmer
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
 
Lập trình Python cơ bản
Lập trình Python cơ bảnLập trình Python cơ bản
Lập trình Python cơ bản
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Voce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu CodigoVoce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu Codigo
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutines
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1
 
Current State of Coroutines
Current State of CoroutinesCurrent State of Coroutines
Current State of Coroutines
 
C++ Lambda and concurrency
C++ Lambda and concurrencyC++ Lambda and concurrency
C++ Lambda and concurrency
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
Kotlin coroutines
Kotlin coroutines Kotlin coroutines
Kotlin coroutines
 

Viewers also liked

Riak Search 2: Yokozuna
Riak Search 2: YokozunaRiak Search 2: Yokozuna
Riak Search 2: Yokozuna
PDX Web & Design
 

Viewers also liked (6)

HTTP is Hard
HTTP is HardHTTP is Hard
HTTP is Hard
 
Hardcore HTML
Hardcore HTMLHardcore HTML
Hardcore HTML
 
Hardcore CSS
Hardcore CSSHardcore CSS
Hardcore CSS
 
Riak Search 2: Yokozuna
Riak Search 2: YokozunaRiak Search 2: Yokozuna
Riak Search 2: Yokozuna
 
Yokozuna
YokozunaYokozuna
Yokozuna
 
DDS-20m
DDS-20mDDS-20m
DDS-20m
 

Similar to Distributed Data Structures

Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
JavaOne 2013 - Clojure for Java Developers
JavaOne 2013 - Clojure for Java DevelopersJavaOne 2013 - Clojure for Java Developers
JavaOne 2013 - Clojure for Java Developers
Jan Kronquist
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
Domenic Denicola
 
Groovy
GroovyGroovy
Groovy
Zen Urban
 
Java VS Python
Java VS PythonJava VS Python
Java VS Python
Simone Federici
 
メタプログラミングPerl nagoya rubykaigi02
メタプログラミングPerl nagoya rubykaigi02メタプログラミングPerl nagoya rubykaigi02
メタプログラミングPerl nagoya rubykaigi02
なんとか くら
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
What they don't tell you about JavaScript
What they don't tell you about JavaScriptWhat they don't tell you about JavaScript
What they don't tell you about JavaScriptRaphael Cruzeiro
 
Concurrency: Rubies, plural
Concurrency: Rubies, pluralConcurrency: Rubies, plural
Concurrency: Rubies, plural
ehuard
 
Concurrency: Rubies, Plural
Concurrency: Rubies, PluralConcurrency: Rubies, Plural
Concurrency: Rubies, Plural
Eleanor McHugh
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
Sunghyouk Bae
 
Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)
tarcieri
 
Elasticsearch's aggregations &amp; esctl in action or how i built a cli tool...
Elasticsearch's aggregations &amp; esctl in action  or how i built a cli tool...Elasticsearch's aggregations &amp; esctl in action  or how i built a cli tool...
Elasticsearch's aggregations &amp; esctl in action or how i built a cli tool...
FaithWestdorp
 
Slides changes symfony23
Slides changes symfony23Slides changes symfony23
Slides changes symfony23Javier López
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
Ian Barber
 

Similar to Distributed Data Structures (20)

Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
JavaOne 2013 - Clojure for Java Developers
JavaOne 2013 - Clojure for Java DevelopersJavaOne 2013 - Clojure for Java Developers
JavaOne 2013 - Clojure for Java Developers
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 
Groovy
GroovyGroovy
Groovy
 
Java VS Python
Java VS PythonJava VS Python
Java VS Python
 
メタプログラミングPerl nagoya rubykaigi02
メタプログラミングPerl nagoya rubykaigi02メタプログラミングPerl nagoya rubykaigi02
メタプログラミングPerl nagoya rubykaigi02
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
What they don't tell you about JavaScript
What they don't tell you about JavaScriptWhat they don't tell you about JavaScript
What they don't tell you about JavaScript
 
Concurrency: Rubies, plural
Concurrency: Rubies, pluralConcurrency: Rubies, plural
Concurrency: Rubies, plural
 
Concurrency: Rubies, Plural
Concurrency: Rubies, PluralConcurrency: Rubies, Plural
Concurrency: Rubies, Plural
 
Having Fun Programming!
Having Fun Programming!Having Fun Programming!
Having Fun Programming!
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
 
Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)
 
Elasticsearch's aggregations &amp; esctl in action or how i built a cli tool...
Elasticsearch's aggregations &amp; esctl in action  or how i built a cli tool...Elasticsearch's aggregations &amp; esctl in action  or how i built a cli tool...
Elasticsearch's aggregations &amp; esctl in action or how i built a cli tool...
 
Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9
 
Slides changes symfony23
Slides changes symfony23Slides changes symfony23
Slides changes symfony23
 
ZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made SimpleZeroMQ: Messaging Made Simple
ZeroMQ: Messaging Made Simple
 
Hw09 Hadoop + Clojure
Hw09   Hadoop + ClojureHw09   Hadoop + Clojure
Hw09 Hadoop + Clojure
 

Recently uploaded

Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 

Recently uploaded (20)

Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 

Distributed Data Structures

  • 7. REPLICATION ISTHE ROOT OF ALL EVIL Thursday, July 25, 13
  • 8. THE CAUSE OF MOST NETWORK PARTITIONS Thursday, July 25, 13
  • 9. THE CAPTHEOREM SUCKS • Consistent • Available • Partition-Tolerant* * http://codahale.com/you-cant-sacrifice-partition-tolerance Thursday, July 25, 13
  • 10. DON’T DISTRIBUTE DATASTORES, STORE DISTRIBUTED DATA Thursday, July 25, 13
  • 11. IF IT CAN HAPPEN, AT SCALE IT WILL HAPPEN Thursday, July 25, 13
  • 14. h  =  NaiveHash.new(("A".."J").to_a) tracknodes  =  Array.new(100000) 100000.times  do  |i|    tracknodes[i]  =  h.node(i) end h.add("K") misses  =  0 100000.times  do  |i|    misses  +=  1  if  tracknodes[i]  !=  h.node(i) end puts  "misses:  #{(misses.to_f/100000)  *  100}%" misses:  90.922% Thursday, July 25, 13
  • 15. 0 2160/2 2160 a single partition SHA1(Key) ring with 32 partitions Node 0 Node 1 Node 2 Thursday, July 25, 13
  • 16. 0 2160/2 2160 a single partition ring with 32 partitions Node 0 Node 1 Node 2 Node 3 SHA1(Key) Thursday, July 25, 13
  • 17. SHA1BITS  =  160 class  PartitionedConsistentHash    def  initialize(nodes=[],  partitions=32)        @partitions  =  partitions        @nodes,  @ring  =  nodes.clone.sort,  {}        @power  =  SHA1BITS  -­‐  Math.log2(partitions).to_i        @partitions.times  do  |i|            @ring[range(i)]  =  @nodes[0]            @nodes  <<  @nodes.shift        end        @nodes.sort!    end    def  range(partition)        (partition*(2**@power)..(partition+1)*(2**@power)-­‐1)    end    def  hash(key)        Digest::SHA1.hexdigest(key.to_s).hex    end    def  add(node)        @nodes  <<  node        partition_pow  =  Math.log2(@partitions)        pow  =  SHA1BITS  -­‐  partition_pow.to_i        (0..@partitions).step(@nodes.length)  do  |i|            @ring[range(i,  pow)]  =  node        end    end    def  node(keystr)        return  nil  if  @ring.empty?        key  =  hash(keystr)        @ring.each  do  |range,  node|            return  node  if  range.cover?(key)        end    end end h  =  PartitionedConsistentHash.new(("A".."J").to_a) nodes  =  Array.new(100000) 100000.times  do  |i|    nodes[i]  =  h.node(i) end puts  "add  K" h.add("K") misses  =  0 100000.times  do  |i|    misses  +=  1  if  nodes[i]  !=  h.node(i) end puts  "misses:  #{(misses.to_f/100000)  *  100}%n" misses:  9.473% Thursday, July 25, 13
  • 18. class  Node    def  initialize(name,  nodes=[],  partitions=32)        @name  =  name        @data  =  {}        @ring  =  ConsistentHash.new(nodes,  partitions)    end    def  put(key,  value)        if  @name  ==  @ring.node(key)            puts  "put  #{key}  #{value}"            @data[  @ring.hash(key)  ]  =  value        end    end    def  get(key)        if  @name  ==  @ring.node(key)            puts  "get  #{key}"            @data[@ring.hash(key)]        end    end end Thursday, July 25, 13
  • 19. nodeA  =  Node.new(  'A',  ['A',  'B',  'C']  ) nodeB  =  Node.new(  'B',  ['A',  'B',  'C']  ) nodeC  =  Node.new(  'C',  ['A',  'B',  'C']  ) nodeA.put(  "foo",  "bar"  ) p  nodeA.get(  "foo"  )      #  nil nodeB.put(  "foo",  "bar"  ) p  nodeB.get(  "foo"  )      #  "bar" nodeC.put(  "foo",  "bar"  ) p  nodeC.get(  "foo"  )      #  nil Thursday, July 25, 13
  • 23. module  Services    def  connect(port=2200,  ip="127.0.0.1")        ctx  =  ZMQ::Context.new        sock  =  ctx.socket(  ZMQ::REQ  )        sock.connect(  "tcp://#{ip}:#{port}"  )        sock    end    def  service(port)        thread  do            ctx  =  ZMQ::Context.new            rep  =  ctx.socket(  ZMQ::REP  )            rep.bind(  "tcp://127.0.0.1:#{port}"  )            while  line  =  rep.recv                msg,  payload  =  line.split('  ',  2)                send(  msg.to_sym,  rep,  payload  )          #  EVVVIILLLL!!!            end        end    end    def  method_missing(method,  *args,  &block)        socket,  payload  =  args        payload.send(  "bad  message"  )  if  payload    end end Thursday, July 25, 13
  • 24. class  Node    include  Configuration    include  Threads    include  Services    def  start()        service(  config("port")  )        puts  "#{@name}  started"        join_threads()    end    def  remote_call(name,  message)        puts  "#{name}  <=  #{message}"        req  =  connect(config("port",  name),  config("ip",  name))        resp  =  req.send(message)  &&  req.recv        req.close        resp    end    #  ... Thursday, July 25, 13
  • 25.    #  ...    def  put(socket,  payload)        key,  value  =  payload.split('  ',  2)        socket.send(  do_put(key,  value).to_s  )    end    def  do_put(key,  value)        node  =  @ring.node(key)        if  node  ==  @name            puts  "put  #{key}  #{value}"            @data[@ring.hash(key)]  =  value        else            remote_call(node,  "put  #{key}  #{value}"  )        end    end Thursday, July 25, 13
  • 26. #  start  a  Node  as  a  Server name  =  ARGV.first node  =  Node.new(name,  ['A','B','C']) node.start() $  ruby  node.rb  A $  ruby  node.rb  B $  ruby  node.rb  C #  connect  with  a  client require  'zmq' ctx  =  ZMQ::Context.new req  =  ctx.socket(ZMQ::REQ) req.connect(  "tcp://127.0.0.1:2200"  ) puts  "Inserting  Values" 1000.times  do  |i|    req.send(  "put  key#{i}  value#{i}"  )  &&  req.recv end puts  "Getting  Values" 1000.times  do  |i|    puts  req.send(  "get  key#{i}"  )  &&  req.recv end req.close Thursday, July 25, 13
  • 29. class  Node    #  ...    def  coordinate_cluster(pub_port,  rep_port)        thread  do            ctx  =  ZMQ::Context.new            pub  =  ctx.socket(  ZMQ::PUB  )            pub.bind(  "tcp://*:#{pub_port}"  )            rep  =  ctx.socket(  ZMQ::REP  )            rep.bind(  "tcp://*:#{rep_port}"  )            while  line  =  rep.recv                msg,  node  =  line.split('  ',  2)                nodes  =  @ring.nodes                case  msg                when  'join'                    nodes  =  (nodes  <<  node).uniq.sort                when  'down'                    nodes  -­‐=  [node]                end                @ring.cluster(nodes)                pub.send(  "ring  "  +  nodes.join(','))                rep.send(  "true"  )            end        end    end Thursday, July 25, 13
  • 30. class  Node    #  ...    def  track_cluster(sub_port)        thread  do            ctx  =  ZMQ::Context.new            sub  =  ctx.socket(  ZMQ::SUB  )            sub.connect(  "tcp://127.0.0.1:#{sub_port}"  )            sub.setsockopt(  ZMQ::SUBSCRIBE,  "ring"  )                        while  line  =  sub.recv                _,  nodes  =  line.split('  ',  2)                nodes  =  nodes.split(',').map{|x|  x.strip}                @ring.cluster(  nodes  )                puts  "ring  changed:  #{nodes.inspect}"            end        end    end Thursday, July 25, 13
  • 33.    def  replicate(message,  n)        list  =  @ring.pref_list(n)        results  =  []        while  replicate_node  =  list.shift            results  <<  remote_call(replicate_node,  message)        end        results    end Thursday, July 25, 13
  • 36. WHATTO EAT FOR DINNER? • Adam wants Pizza {value:"pizza", vclock:{adam:1}} • Barb wantsTacos {value:"tacos", vclock:{barb:1}} • Adam gets the value, the system can’t resolve, so he gets bolth [{value:"pizza", vclock:{adam:1}}, {value:"tacos", vclock:{barb:1}}] • Adam resolves the value however he wants {value:"taco pizza", vclock:{adam:2, barb:1}} Thursday, July 25, 13
  • 37. #  artificially  create  a  conflict  with  vclocks req.send('put  1  foo  {"B":1}  hello1')  &&  req.recv req.send('put  1  foo  {"C":1}  hello2')  &&  req.recv puts  req.send("get  2  foo")  &&  req.recv sleep  5 #  resolve  the  conflict  by  decending  from  one  of  the  vclocks req.send('put  2  foo  {"B":3}  hello1')  &&  req.recv puts  req.send("get  2  foo")  &&  req.recv Thursday, July 25, 13
  • 38. • choose a value at random • siblings (user resolution) • defined resolution (eg. CRDT) CONFLICT RESOLUTION Thursday, July 25, 13
  • 44. * Thanks Joe Blomstedt Thursday, July 25, 13
  • 55. array    =  [{value:1},{value:3},{value:5}] mapped  =  array.map{|obj|  obj[:value]} #  [1,  3,  5] mapped.reduce(0){|sum,value|  sum  +  value} #  9 Thursday, July 25, 13
  • 57. module  Mapreduce    def  mr(socket,  payload)        map_func,  reduce_func  =  payload.split(/;s+reduce/,  2)        reduce_func  =  "reduce#{reduce_func}"        socket.send(  Reduce.new(reduce_func,  call_maps(map_func)).call.to_s  )    end    def  map(socket,  payload)        socket.send(  Map.new(payload,  @data).call.to_s  )    end    #  run  in  parallel,  then  join  results    def  call_maps(map_func)        results  =  []        nodes  =  @ring.nodes  -­‐  [@name]        nodes.map  {|node|            Thread.new  do                res  =  remote_call(node,  "map  #{map_func}")                results  +=  eval(res)            end        }.each{|w|  w.join}        results  +=  Map.new(map_func,  @data).call    end end Thursday, July 25, 13
  • 58. module  Mapreduce    def  mr(socket,  payload)        map_func,  reduce_func  =  payload.split(/;s+reduce/,  2)        reduce_func  =  "reduce#{reduce_func}"        socket.send(  Reduce.new(reduce_func,  call_maps(map_func)).call.to_s  )    end    def  map(socket,  payload)        socket.send(  Map.new(payload,  @data).call.to_s  )    end    #  run  in  parallel,  then  join  results    def  call_maps(map_func)        results  =  []        nodes  =  @ring.nodes  -­‐  [@name]        nodes.map  {|node|            Thread.new  do                res  =  remote_call(node,  "map  #{map_func}")                results  +=  eval(res)            end        }.each{|w|  w.join}        results  +=  Map.new(map_func,  @data).call    end end Thursday, July 25, 13
  • 59. 200.times  do  |i|    req.send(  "put  2  key#{i}  {}  #{i}"  )  &&  req.recv end req.send(  "mr  map{|k,v|  [1]};  reduce{|vs|  vs.length}"  ) puts  req.recv Thursday, July 25, 13
  • 60. 200.times  do  |i|    req.send(  "put  2  key#{i}  {}  #{i}"  )  &&  req.recv end req.send(  "mr  map{|k,v|  [1]};  reduce{|vs|  vs.length}"  ) puts  req.recv Thursday, July 25, 13
  • 61. ONE FINAL IMPROVEMENT • C! • A! • P! Thursday, July 25, 13
  • 62. N/R/W • N! # of Nodes to replicate a value to (in total) • R! # of nodes to Read a value from (before success) • W! # of nodes to Write a value to (before success) Thursday, July 25, 13
  • 63. Node A Node B Node C Node D Node E N = 3 Write an Object Node A Node B Node C Node D Node E W = 2 Write an Object replicate replicate to C & D respond first Node A Node B Node C Node D Node E R = 2 Read an Object C & E respond first eventually replicate to request from Thursday, July 25, 13
  • 64. EVENTUALLY CONSISTENT • How Eventual? • How Consistent? Le mieux est l'ennemi du bien Thursday, July 25, 13
  • 65. Probabilistically Bounded Staleness N=3, R=1,W=2 * http://pbs.cs.berkeley.edu Thursday, July 25, 13
  • 68. Distributed Hash Ring Vector Clocks Preference List MerkelTree Read Repair Key/Value CRDT (counters, more coming) Node Gossip Request/ Response Thursday, July 25, 13