combining the strengths or erlang and ruby
Post on 17-May-2015
5.314 Views
Preview:
DESCRIPTION
TRANSCRIPT
COMBINING THE STRENGTHS OF ERLANG AND RUBYerlounge Berlin February 2012 – Mar4n Rehfeld
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
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)
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
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
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
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?"
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-‐)
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
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
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
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
Setup Overview
server
Push/Pull Queue
Pub/Sub Queue
worker
worker
worker
worker
worker
session
session
session...
...
sender
receiver
1:n
m:n
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
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
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
Q & A
Mar4n Rehfeld@klickmich
top related