A talk I gave at DjangoCon Europe 2011, about Epio's internal architecture at that point.
Deploying, At An Unusual ScaleAndrew Godwinhttp://www.flickr.com/photos/whiskeytango/1431343034/@andrewgodwin
View Slide
Hi, I'm Andrew.Serial Python developerDjango core committerCo-founder of ep.io
Hi, I'm Andrew.Serial Python developerDjango core committerCo-founder of ep.ioOccasional fast talker
""Andrew speaks Englishlike a machine gunspeaks bullets.""Reinout van Rees
We're ep.ioPython Platform-as-a-ServiceEasy deployment, easy upgradesPostgreSQL, Redis, Celery, and more
Why am I here?Our ArchitectureHow we deploy DjangoHow varied Django deployments are
Our Architecture
BalancerRunner Runner RunnerApp 1App 2App 3App 2App 4App 1Databases File StorageBalancer
Oh My God, It's Full of PairsEverything is redundantDistributed programming is Hard
HardwareReal colo'd machinesLinodeEC2 (pretty unreliable)(pretty reliable)(pretty reliable)IPv6 (as much as we can)
ØMQWe used to use RedisEverything now on ZeroMQEliminates SPOF** Single Point Of Failure. What a pointless acronym.
ØMQ UsageRedundant location-resolvers (Nexus)REQ/XREP for control messagesPUSH/PULL for stats, logsPUB/SUB for heartbeats, locking
RunnersUnsurprisingly, these run the codeSquashFS filesystem imagesVirtualenvs per appUID & permission isolation, more coming
Logging/StatsAll done asynchronously using ØMQLogs to filesystem (chunked files)Stats to PostgreSQL database, for now
LoadbalancersIntercept all incoming HTTP requestsLook up hostname (or suffix)HTTP 1.1 compliant
DatabasesShared (only for PostgreSQL)Dedicated (uses Runner framework)PostgreSQL 9, damnit
Django in the backendWe use the ORM extensivelyAnnoying settings fiddling in __init__
www.ep.ioRuns on ep.io, just like any other app*Provides JSON API, web UI* Well not quite - App ID 0 is special - but we're working on it
WSGIIt's a standard, right?
WSGIIt's a standard, right?Well, yes, and it works fine, but it's notenough for serving a Python app
Static FilesCSS, images, JavaScript, etc.Needs a URL and a directory path
Python & DependenciesMostly filled by pip/buildout/etcpackaging apparently allows version spec
Deploying DjangoIt makes things consistent, right?
Settings LayoutsVanilla settings.pylocal_settings.pyconfigs/HOSTNAME.pyMany others...
Python PathsProject-level importsApp-level importsapps/ directories
DatabasesIf it's SQL, it's PostgreSQLRedis for key-value, MongoDB soonSome things assume a safe network
HA (High Availability)Not terribly easy with shared DBsPostgreSQL 9's sensible warm standbyRedis has SLAVEOFPossibly use DRBD for general solution
BackupsHigh Availability is NOT a backupbtrfs for consistent snapshottingArchived remote syncsNo access to backups from servers
MigrationsNo solution yet for migration/code syncWe're working on it...
Web servingIt's not like it's important or anything
gunicornSmall and lightweightSupports long-running requestsPretty stable
nginxEven more lightweightExtremely fastReally, really stable
The Load BalancerUsed to be HAProxyRewritten to custom Python daemoneventlet used for high throughputCan't use nginx, no HTTP 1.1 for backends
CelerySee: Yesterday's TalkSlightly tricky to run manyWe use Redis as the backend
Management CommandsFirst off, run as subprocessThen, a custom PTY moduleNow, run as pty-wrapping subprocesses
Some General AdviceIf you're crazy enough to do this
Messaging's Not EnoughHaving a state to check is handy
Why run one, when you canrun two for twice the price?Redundancy is good. Double redundancy is better.
Always expect the worstHope you never have to deal with it.
The more backups, the better.Make sure you have historical ones, too.
Django is very flexibleSometimes a little too flexible...
Your real problems will emerge laterDon't over-optimise up front for everything
Questions?Andrew Godwin[email protected]@andrewgodwin