utopia kindgoms scaling case: from 4 to 50k users

44
scaling case. From 4 users to 90k+ Jaime Buelta Soft. Developer at

Upload: jaime-buelta

Post on 29-Nov-2014

2.500 views

Category:

Documents


1 download

DESCRIPTION

PyCon Ireland Talk 2011

TRANSCRIPT

Page 1: Utopia Kindgoms scaling case: From 4 to 50K users

● scaling case. From 4 users to 90k+●

● Jaime Buelta● Soft. Developer at

Page 2: Utopia Kindgoms scaling case: From 4 to 50K users

The Game

Page 3: Utopia Kindgoms scaling case: From 4 to 50K users

Get image from game

Page 4: Utopia Kindgoms scaling case: From 4 to 50K users

Utopia Kingdoms

● Fantasy strategy game● Build your own Kingdom● Create armies and attack other Kingdoms● Join other Kingdoms in an Alliance● Manage resources● Available in Facebook and Kongregate

http://www.facebook.com/UtopiaKigdomsGamehttp://www.kongregate.com/games/JoltOnline/utopia-kingdoms

Page 5: Utopia Kindgoms scaling case: From 4 to 50K users

Technology stack

Page 6: Utopia Kindgoms scaling case: From 4 to 50K users

Technology Stack - Backend

PythonCherrypy framework

Amazon SimpleDBLinux in Amazon EC2

Page 7: Utopia Kindgoms scaling case: From 4 to 50K users

Stack of technologies - Frontend

HTML( generated by Genshi templates)

jQuery

Page 8: Utopia Kindgoms scaling case: From 4 to 50K users

Stack of technologies - Frontend

HTML( generated by Genshi templates)

jQuery

Page 9: Utopia Kindgoms scaling case: From 4 to 50K users

Some points of interest(will discuss them later)

● Your resources (population, gold, food, etc) grows with time

● You actions (build something, attack a player) typically takes some time

● Players are ranked against the rest● You can add friends and enemies

Page 10: Utopia Kindgoms scaling case: From 4 to 50K users

Do not guess

Measure

Page 11: Utopia Kindgoms scaling case: From 4 to 50K users

Measurement tools

● OS tools● Task manager (top)● IO Monitor (iostat)

● Monitoring tools (Munin, Nagios)

● Logs● Needs to find a good compromise detailed/relevance

● Profiling

Page 12: Utopia Kindgoms scaling case: From 4 to 50K users

You've got to love profiling

● Generate profiles with cProfile module

Profile whole application with

python -m cProfile -o file.prof my_app.py

(not very useful in a web app)

● If you're using a framework, profile only your functions to reduce noise

Page 13: Utopia Kindgoms scaling case: From 4 to 50K users

Profile decorator (example)

def profile_this(func):

import cProfile

prof = cProfile.Profile()

retval = prof.runcall(func)

filename = 'profile-{ts}.prof'.format(time.time())

prof.dumpstats(filename)

return retval

Page 14: Utopia Kindgoms scaling case: From 4 to 50K users

Analyzing profile

● gprof2dot● Using dot, convert to graph

gprof2dot -f pstats file.prof | dot -Tpng -o file.png

● Good for workflows

● RunSnakeRun● Good for cumulative times

Page 15: Utopia Kindgoms scaling case: From 4 to 50K users

Example of RunSnakeRunRAZR

Page 16: Utopia Kindgoms scaling case: From 4 to 50K users

Example of gprof2dot

Page 17: Utopia Kindgoms scaling case: From 4 to 50K users

The power of cache

Page 18: Utopia Kindgoms scaling case: From 4 to 50K users

All static should be out of python

● Use a good web server to serve all static content (Static HTML, CSS, JavaScript code)

● Some options● Apache● Nginx● Cherokee● Amazon S3

Page 19: Utopia Kindgoms scaling case: From 4 to 50K users

Use memcached(and share the cache between your servers)

Page 20: Utopia Kindgoms scaling case: From 4 to 50K users

Example

● Asking for friends/enemies to DB● Costly request in SimpleDB (using SQL statement)

● On each request● Cache the friends on memcache for 1 hour● Invalidate the cache if adding/removing

friends or enemies

Page 21: Utopia Kindgoms scaling case: From 4 to 50K users

Caching caveats

● Cache only after knowing there is a problem● Do not trust in cache for storage● Take a look on size of cached data● Choosing a good cache time can be difcult /

Invalidate cache can be complex● Some data is too dynamic to be cached

Page 22: Utopia Kindgoms scaling case: From 4 to 50K users

Caching is not just memcached

● More options available:● Get on memory on start● File cache● Cache client side

Page 23: Utopia Kindgoms scaling case: From 4 to 50K users

Parse templates just once

● The template rendering modules have options to parse the templates just once

● Be sure to activate it in production● In development, you'll most likely want to

parse them each time

● Same apply to regex, specially complex ones

Page 24: Utopia Kindgoms scaling case: From 4 to 50K users

More problems

Page 25: Utopia Kindgoms scaling case: From 4 to 50K users

Rankings

● Sort players on the DB is slow when you grow the number of players

● Solution:● Independent ranking server (operates just in

memory)● Works using binary trees● Small Django project, communicates using xmlrpc

● Inconvenient:● Data is not persistent, if the rankings server goes

down, needs time to reconstruct the rankings

Page 26: Utopia Kindgoms scaling case: From 4 to 50K users

Database pulling - Resources

● There was a process just taking care of the growth of resources.● It goes element by element, and increasing the

values● It pulls the DB constantly, even when the user has

their values to maximum● Increment the resources of a user just the next

time is accessed (by himself or by others)● No usage of DB when the user is not in use● The request already reads from DB the user

Page 27: Utopia Kindgoms scaling case: From 4 to 50K users

Database pulling - Actions

● Lots of actions are delayed. Recruit a unit, buildings, raids...

● A process check each user if an action has to be done NOW.● Tons of reads just to check “not now”● Great delay in some actions, as they are not

executed in time

Page 28: Utopia Kindgoms scaling case: From 4 to 50K users

Database pulling - Actions

● Implement a queue to execute the actions at the proper time:● Beanstalk (allows deferred extraction)● A process listen to this queue and performs the

action, independently from request servers.● The process can be launched in a diferent

machine.● Multiple process can extract actions faster.

Page 29: Utopia Kindgoms scaling case: From 4 to 50K users

DataBase Issues

Page 30: Utopia Kindgoms scaling case: From 4 to 50K users

Amazon SimpleDB

● Key – Value storage● Capable of SQL queries● Store a dictionary (schemaless, multiple

columns)● All the values are strings● Access through boto module● Pay per use

Page 31: Utopia Kindgoms scaling case: From 4 to 50K users

Problems with SimpleDB

● Lack of control● Can't use local copy

– In development, you must access Amazon servers (slow and costly)

● Can't backup except manually● Can't analyze or change DB (e.g. can't define

indexes)● Can't monitor DB

Page 32: Utopia Kindgoms scaling case: From 4 to 50K users

Problems with SimpleDB

● Bad tool support● Slow and high variability (especially on SQL

queries)● Sometime, the queries just timeout and had to be

repeated.

Page 33: Utopia Kindgoms scaling case: From 4 to 50K users

Migrate to MongoDB

Page 34: Utopia Kindgoms scaling case: From 4 to 50K users

MongoDB

● NoSQL● Schemaless● Fast● Allow complex queries● Retain control (backups, measure queries, etc)● Previous experience using it from ChampMan

Page 35: Utopia Kindgoms scaling case: From 4 to 50K users

Requisites of the migration

● Low-level approach● Objects are basically dictionaries● Be able to save dirty fields (avoid saving

unchanged values)● Log queries to measure performance

Page 36: Utopia Kindgoms scaling case: From 4 to 50K users

MongoSpell● Thin wrap over pymongo● Objects are just dictionary-like elements● Minimal schema● Fast!● Able to log queries● It will probably be released soon as Open

Source

Page 37: Utopia Kindgoms scaling case: From 4 to 50K users

Definition of collections

class Spell(Document):

collection_name = 'spells'

needed_fields = ['name',

'cost',

'duration']

optional_fields = [

'elemental',

]

activate_dirty_fields = True

indexes = ['name__unique', 'cost']

Page 38: Utopia Kindgoms scaling case: From 4 to 50K users

Querying from DB

Spell.get_from_db(name='fireball')

Spell.filter()

Spell.filter(sort='name')

Spell.filter(name__in=['fireball', 'magic missile'])

Spell.filter(elemental__fire__gt=2)

Spell.filter(duration__gt=2,

cost=3, hint='cost')

Spell.filter(name='fireball', only='cost')

Page 39: Utopia Kindgoms scaling case: From 4 to 50K users

Some features

● Dirty fields● No type checks● Query logs● 10x faster than SimpleDB!!!

Page 40: Utopia Kindgoms scaling case: From 4 to 50K users

Query logs

[07:46:06]- 2.6 ms – get_from_db - Reinforcement - Reinforcements.py(31)[07:46:06]- 4.3 ms - get_from_db - Player - Player.py(876)[07:46:10]- 0.1 ms - filter - Membership- AllianceMembership.py(110) [07:46:10]- 1.3 ms - get_from_db - Reinforcement -Reinforcements.py(31)[07:46:10]- 1.4 ms - get_from_db - Notifications - Notifications.py (56)

Page 41: Utopia Kindgoms scaling case: From 4 to 50K users

Scalability vs Efciency

Page 42: Utopia Kindgoms scaling case: From 4 to 50K users

Scalable vs Efcient

Scalable● Can support more

users adding more elements

Efficient● Can support more

users with the same elements

Work on both to achieve your goals

Page 43: Utopia Kindgoms scaling case: From 4 to 50K users

Keep measuring and improving!(and monitor production to be proactive)

Page 44: Utopia Kindgoms scaling case: From 4 to 50K users

Thank you for your interest!

Questions?

[email protected]://WrongSideOfMemphis.wordpress.com

http://www.joltonline.com