17
COMBINING THE STRENGTHS OF ERLANG AND RUBY erlounge Berlin February 2012 – Mar4n Rehfeld

Combining the strength of erlang and Ruby

Embed Size (px)

DESCRIPTION

Use erlang for state and concurrency control while implementing business logic rapidly with Ruby's unique ability to have DSL like syntax.

Citation preview

Page 2: Combining the strength of erlang and Ruby

Game  Server  for  Upcoming  Wooga  Game

What  is  a  game  server?

• provide  HTTP  API  to  actual  game  („client“)

• validate  API  calls  against  current  state  &  game  logic

• API  calls  will  modify  the  game  state

• make  game  state  persistent

Page 3: Combining the strength of erlang and Ruby

Game  Server  for  Upcoming  Wooga  Game

It  will  be  a  stateful  game  server

• one  process  per  ac4ve  user  gaming  session

• the  process  holds  the  current  state  and  is  the  only  one  that  can  modify  it  (strong  encapsula:on)

• the  process  handles  all  API  calls  for  the  given  user  one  a=er  the  other  (concurrency  control  through  actor  model)

• the  process  loads  the  game  state  from  storage  and  writes  it  back  periodically  and  on  process  termina:on  (:meout  =  user  stopped  playing)

Page 4: Combining the strength of erlang and Ruby

Game  Server  for  Upcoming  Wooga  Game

Details  on  the  basic  idea:

Awesome  presenta4on  on  the

Magic  Land  game  server  by

@knu4n  &  @hungryblankhZp://www.slideshare.net/wooga/from-­‐0-­‐to-­‐1000000-­‐daily-­‐users-­‐with-­‐erlang

Page 5: Combining the strength of erlang and Ruby

Our  Goals

• Get  most  of  the  benefits  from  wooga’s  pure-­‐erlang  game  server  (Magic  Land)

• especially  func:onal  approach  for  game  state  encapsula:on  and  transforma:on  +  concurrency  control

• But:  Keep  Object-­‐Oriented  approach  for  modelling  the  game  logic

Page 6: Combining the strength of erlang and Ruby

Expected  OO-­‐Benefits

• Rapid  development

• concise  &  expressive  syntax

• leverage  exis4ng  know  how

• but:  keep  the  OO  part  stateless  and  side-­‐effect  freeto  avoid  the  usual  traps  &  pidalls

Page 7: Combining the strength of erlang and Ruby

Target  Architecture

App Server Node

Erlang VM

Ruby Worker

Ruby Worker

Ruby Worker...

App Server Node

Erlang VM

Ruby Worker

Ruby Worker

Ruby Worker...

App Server Node

Erlang VM

Ruby Worker

Ruby Worker

Ruby Worker...

...

Shared Storage

for game state snapshots and for storing cold game sessions

Load BalancerAuthority for:

"What app server is responsible for current session?"

Page 8: Combining the strength of erlang and Ruby

Example  Game  Ac4on  in  Ruby

game_action '/:actor/fruit_tree/self/shake', :affects => [:fruit_trees, :user] do |response|

x, y = params[:x], params[:y] fruit_trees[x, y].shakeend

URL

affected  parts  ofthe  game  state

• DSL-­‐like  defini4on  of  game  ac4on

• skinny  as  controllers  should  be  8-­‐)

Page 9: Combining the strength of erlang and Ruby

Example  Model  in  Ruby

class FruitTree < Tree property :last_shake_time, :type => Integer, :default => 0 property :collectable_fruit_count, :type => Integer, :default => 0

def shake raise Error::Validation, "FruitTree at (#{x}, #{y}) has no fruit" unless carries_fruit?

session.user.xp += 1 session.user.energy -= 1 self.last_shake_time = game_time self.collectable_fruit_count = config.fruit_count end # ...end

Inheritance

DSL-­‐like  defini4onof  persistent  state

• easily  unit  testable

• minimal  amount  of  code

Page 10: Combining the strength of erlang and Ruby

erlang  talking  to  Ruby

Some  op4ons

• erlectricity  hZps://github.com/mojombo/erlectricity:Can  talk  erlang  binary  protocol  to  Ruby  processes  through  erlang  ports

• ernie  hZps://github.com/mojombo/ernie:Remote  func4on  call  using  the  BERT-­‐RPC  protocol  to  either  Ruby  or  na4ve  erlang  processes

• ZeroMQ  <hZp://www.zeromq.org/>:awesome  brokerless  queue  transport  layer,  connects  30+  languages

Page 11: Combining the strength of erlang and Ruby

ZeroMQ

Pro

• loose  coupling  of  erlang  and  Ruby  through  queues

• easily  deploy  new  Ruby  code  without  touching  erlang

• allows  flexible  transports,  even  accross  machines

Con

• yet  another  layer

Page 12: Combining the strength of erlang and Ruby

Connec4ng  the  Dots

• use  Mongrel2  hZp://mongrel2.org/  protocol  &  ZeroMQ  setup

• erlang:  emongrel2  hZps://github.com/hungryblank/emongrel2

• Ruby

• rack-­‐mongrel2  fork  hEps://github.com/khiltd/khi-­‐rack-­‐mongrel2

• rack  protocol  hEp://rack.rubyforge.org

• Sinatra  hEp://www.sinatrarb.com/

➡ essen4ally  we  are  speaking  HTTP  over  ZeroMQand  can  hook  up  any  Rack-­‐based  Ruby  web  framework

Page 13: Combining the strength of erlang and Ruby

Setup  Overview

server

Push/Pull  Queue

Pub/Sub  Queue

worker

worker

worker

worker

worker

session

session

session...

...

sender

receiver

1:n

m:n

Page 14: Combining the strength of erlang and Ruby

How  does  the  game  state  look  like?

• Has  many  parts,  each  part  has  a  name  (e.g.  fruit_trees)  and  some  content

• this  is  a  performance  op:miza:on,  so  that  we  don't  need  to  send  the  complete  state  back  and  forth  for  every  call

• erlang  does  not  care  about  the  content  (binary  data)

• actually  the  content  contains  serialized  objects  (e.g.  a  MapObjectCollection  containing  FruitTree  members)

• erlang  does  need  to  know,  what  game  ac4on  needs  what  state  parts

Page 15: Combining the strength of erlang and Ruby

Looking  back  at  the  Game  Ac4on

game_action '/:actor/fruit_tree/self/shake', :affects => [:fruit_trees, :user] do |response|

x, y = params[:x], params[:y] fruit_trees[x, y].shakeend

affected  parts  ofthe  game  state

• Ruby  knows  the  mapping  of  game  ac4ons  to  affected  state  parts

• pushes  the  mapping  on  startup  &  makes  it  available  on  request

Page 16: Combining the strength of erlang and Ruby

Aside:  Efficient  Game  State  Access

• considered  different  serializa4on  formats  (e.g.  JSON,  MessagePack)

• especially  for  large  collec4ons  of  objects  we  wanted  to  avoid  parsing  everything  to  extract  a  single  object

• chose  TNetstrings  hZp://tnetstrings.org/  as  a  serializa4on  format  (length  prefix  helps  searching/lazy  parsing)

• built  a  lazy  parser/encoder  for  it    in  C  for  speed  :-­‐)hZps://github.com/wooga/lazy_tnetstring

Page 17: Combining the strength of erlang and Ruby

Q  &  A

Mar4n  Rehfeld@klickmich