Top Banner
DragonCraft Architectural Overview Freeverse Inc.
28

Dragoncraft Architectural Overview

May 27, 2015

Download

Technology

jessesanford

Presentation given to NYC Tech Talks Meetup group on June 26 2012. More info here: http://www.meetup.com/NYC-Tech-Talks/events/69478562/
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Dragoncraft Architectural Overview

DragonCraft Architectural Overview

Freeverse Inc.

Page 2: Dragoncraft Architectural Overview
Page 3: Dragoncraft Architectural Overview

Jesse Sanford, Joshua Kehn Freeverse / ngmoco:) / DeNA

● Web guys brought in to design RESTful HTTP based games for handheld clients.

● Platform concurrently being built by Ngmoco team out in San Francisco.

● First games in company's history built entirely on○ EC2○ Node.js○ MongoDB

● There is a lot of firsts here!

Page 4: Dragoncraft Architectural Overview

Why Node.js?

● Already using javascript. Knowledge share!● Fast growing ecosystem.● Reasonable to bring libraries from client to

server and vice versa.● Lots of javascript patterns and best practices

to follow.● Growing talent pool.

Page 5: Dragoncraft Architectural Overview

Why MongoDB?

● Ever changing schemas make document stores attractive.

● Easy path to horizontal scalability.● 10gen is very easy to work with.● Lots of best practice patterns for running on

ec2 infrastructure.● Javascript is a friendly interface.

Page 6: Dragoncraft Architectural Overview

Handling the change.

● Lots of patience.● Many proof of concepts.● Dedicated poc's for different puzzle pieces.

(Platform services, Game Libraries)● Developer training and evangelists.● Performance testing and open source library

vetting.● Lots of patience. Seriously.

Page 7: Dragoncraft Architectural Overview

Building from scratch.

● Lots of testing.● Pre-flight environment for content.● Duplicate of production for release staging.● Full stack developer sandboxes on every

workstation.○ Individual MongoDB and Node.js instances running.○ Full client stack available as a browser based

handheld simulator for client interface.

Page 8: Dragoncraft Architectural Overview

"Physical" Infrastructure

● EC2 fabric managed by Rightscale● Extensive library of "Rightscripts" and

"Server templates".● Different deployments for each environment.● Deployments a mix of single service

machines and arrays of machines.● Arrays load balanced by HA proxy not ELB's● Mongo clusters are largest expense.

Page 9: Dragoncraft Architectural Overview

Logical Diagram

Page 10: Dragoncraft Architectural Overview

Physical/Logical Diagram

Page 11: Dragoncraft Architectural Overview

Mongo Infrastructure

● Mongo cluster per environment.● 3 config nodes split between 2 availability

zones.● Currently only 1 shard.● 3 db nodes split between 2 availability● mongos processes running directly on app

servers.

Page 12: Dragoncraft Architectural Overview

Mongo Infrastructure cont.

● Config nodes on t1-micros.● DB nodes on m1-xlarges.● DB nodes running raid 10 on ebs.● XFS with LVM.● Snapshots taken after forcing fsync and lock

on db and then XFS freeze. ● Backups always done on secondary.

Page 13: Dragoncraft Architectural Overview

Shrinking Mongo

● Staging and testing environments too costly.● Logically the application knows no

MongoD/S differences.● Still single shard.● Spinning instances is quick.● Only used for smoke testing at the end of

every dev cycle.● Moving to single master -> slave replication.● Cost savings of 60% in these environments.

Page 14: Dragoncraft Architectural Overview

Other Services

● HA-proxy 2 m1-small● Memcached - 1 m1-large● PHP+Apache (cms), Flume/Syslog - 1 m1-

large● Ejabberd - 1 m1-large● Beanstalkd - 1 m1-large● Nodejs - (currently 3) c1-xlarge

Page 15: Dragoncraft Architectural Overview

Log4js-syslog, Flume

● Centralized logging from all application servers in the cluster.

● Configurable log levels at both the application layer and filters on the stream after that.

● Flume speaks syslog fluently● Flume allows us to point the firehose

wherever we want.● It's trivial to ingest the Flume ouput from s3

into Hadoop/Elastic Map Reduce

Page 16: Dragoncraft Architectural Overview

Daida, Beanstalkd

● Needed fast worker queue for push messaging and out-of-band computation.

● Considered Redis and Resque● Considered RabbitMQ/AMPQ● Beanstalkd was built for work queues.● Beanstalkd is very simple.● No real support for HA● Workers needed to be written in javascript.● No upfront knowledge about the runtime

activities of workers.

Page 17: Dragoncraft Architectural Overview

Daida, Beanstalkd cont.

● Developers define jobs (payload contains variables needed for job to execute)

● Developers schedule jobs.● Developers create "strategies" which know

how to execute the jobs.● At runtime using some functional magic

Daida closes the developer defined strategy around the payload variables that came with the job.

● This is somewhat similar to the job being run by a worker inside a container with a context.

Page 18: Dragoncraft Architectural Overview

var handlers = { bar: function(data, cb) { var callback = cb || function() { /* noOp */ }; //if callback wasn't passed console.log('test job passed data: ' + JSON.stringify(data)); callback(); //always make sure to callback!!!! },

foo: function(data, cb) { var callback = cb || function() { /* noOp */ }; console.log('foo job passed name'+ data.name); callback(); //again never forget to callback!!! }, }; exports.handlers = handlers;

exports.bar = handlers.bar; exports.foo = handlers.foo;

//taken from https://github.com/ngmoco/daida.js

Daida handler example.

Page 19: Dragoncraft Architectural Overview

Ejabberd

● Best multi-user-chat solution for the money.● Considered IRC and other more custom

solutions.● Javascript handhelds can use javascript chat

client libraries!● Capable of being run over plain HTTP.

(Comet/long-poll/BOSH)● Widely used.● Fine grained control over users and rooms.● A little complex for our needs.● Erlang/OTP is solid.

Page 20: Dragoncraft Architectural Overview

Other Nodejs libraries

● Connect● Express ● mongoose● oauth● connect-auth ● connect-cookie-session

Page 21: Dragoncraft Architectural Overview

Megaphone load tester

● Written in erlang/otp to make use of it's lightweight processes and distributed nature.

● SSL Capable HTTP Reverse proxy.● Records sessions from handhelds.● Proxy is transparent and handhelds are

stupid.● Choose which sessions to replay.● Write small scripts to manipulate req/resp

during replay. OAuth handshakes?● Interact with replay in console.● Record results of replay.

Page 22: Dragoncraft Architectural Overview

Megaphone load tester cont.

● Replay in bulk! (Load test).● Centralized console can spawn http replay

processes on many headless machines. Similar to headless Jmeter.

● A single session (some number of individual requests) is sent to the client process when spawned

● Responses are sent back to the centralized databases as clients receive them.

● The same session can be sent to multiple clients and played back concurrently.

Page 23: Dragoncraft Architectural Overview

%% This module contains the functions to manipulate req/resp for the dcraft_session1 playback-module(dcraft_session1).-include("blt_otp.hrl").-export([ create_request/1, create_request/2, create_request/3]).-record(request, { url, verb, body_vars}).-record(response, {request_number, response_obj}).create_request(Request) -> create_request(Request, []).create_request(Request, Responses) -> create_request(Request, Responses, 0).create_request(#request{url="http://127.0.0.1:8080/1.2.1/dragoncraft/player/sanford/mission/"++OldMissionId} = Request, Responses, RequestNumber) ->

?DEBUG_MSG("~p Request for wall Found!~n", [?MODULE]),[LastResponseRecord|RestResponses] = Responses,{{_HttpVer, _ResponseCode, _ResponseDesc}, _Headers, ResponseBodyRaw} = LastResponseRecord#response.response_obj,{ok, ResponseBodyObj} = json:decode(ResponseBodyRaw),ResponseKVs = element(1, ResponseBodyObj),[Response_KV1 | [Response_KV2 | Response_KV_Rest ]] = ResponseKVs,Response_KV2_Key = element(1, Response_KV2),Response_KV2_Val = element(2, Response_KV2),ResponseDataObj = element(1, Response_KV2_Val),[ResponseDataKV | ResponseDataKVRest ] = ResponseDataObj,ResponseData_KV_Key = element(1, ResponseDataKV), %<<"identifier">>ResponseData_KV_Val = element(2, ResponseDataKV),MissionId = binary_to_list(ResponseData_KV_Val),Replaced = re:replace(Request#request.url, OldMissionId, MissionId++"/wall"),[ReHead|ReRest] = Replaced,[ReTail] = ReRest,?DEBUG_MSG("~p replaced head is ~p and tail ~p ~n", [?MODULE, ReHead, ReTail]),NewUrl = binary_to_list(ReHead)++binary_to_list(ReTail),NewRequest = Request#request{url=NewUrl};

create_request(Request, Responses, RequestNumber) -> Request.

EX. Session handler script for manipulating requests at runtime

Page 24: Dragoncraft Architectural Overview

Other notables

● Recently started using python's fabric library for rolling releases.

● Node cluster for multiprocess node. ● Node ipc with linux signals to raise and lower

logging levels and content updates.

Page 25: Dragoncraft Architectural Overview

Screenshots

Page 26: Dragoncraft Architectural Overview

Demo

Page 27: Dragoncraft Architectural Overview

Links

● http://dragoncraftthegame.com/● http://freeverse.com/● http://blog.ngmoco.com/● https://developer.mobage.com/● http://dena.jp/intl/

Page 28: Dragoncraft Architectural Overview

Repos

● https://github.com/ngmoco/daida.js.git● https://github.com/ngmoco/daida-beanstalk.

git● https://github.com/ngmoco/daida-local.git● https://github.com/ngmoco/Megaphone

(coming very soon)