SlideShare une entreprise Scribd logo
1  sur  69
Télécharger pour lire hors ligne
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

Contenu connexe

Tendances

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 4Jan Berdajs
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Python postgre sql a wonderful wedding
Python postgre sql   a wonderful weddingPython postgre sql   a wonderful wedding
Python postgre sql a wonderful weddingSté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 181Mahmoud Samir Fayed
 
Go for the paranoid network programmer
Go for the paranoid network programmerGo for the paranoid network programmer
Go for the paranoid network programmerEleanor 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
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Baruch Sadogursky
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutinesFreddie Wang
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1Ke Wei Louis
 
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 reduxEleanor 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 PerspectiveEleanor McHugh
 

Tendances (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
 

En vedette (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
 

Similaire à 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 DevelopersJan Kronquist
 
メタプログラミング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 2016Manoj 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, PluralEleanor McHugh
 
Concurrency: Rubies, plural
Concurrency: Rubies, pluralConcurrency: Rubies, plural
Concurrency: Rubies, pluralehuard
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Sunghyouk 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 SimpleIan Barber
 

Similaire à 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
 

Dernier

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 

Dernier (20)

How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 

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