Building a Hosting Platorm with Python Andrew Godwin @andrewgodwin - - PowerPoint PPT Presentation

building a hosting platorm with python
SMART_READER_LITE
LIVE PREVIEW

Building a Hosting Platorm with Python Andrew Godwin @andrewgodwin - - PowerPoint PPT Presentation

Building a Hosting Platorm with Python Andrew Godwin @andrewgodwin http://www.flickr.com/photos/whiskeytango/1431343034/ Hi, I'm Andrew. Serial Python developer Django core committer Co-founder of ep.io We're ep.io Python


slide-1
SLIDE 1

Building a Hosting Platorm with Python

Andrew Godwin

http://www.flickr.com/photos/whiskeytango/1431343034/

@andrewgodwin

slide-2
SLIDE 2

Hi, I'm Andrew.

Serial Python developer Django core committer Co-founder of ep.io

slide-3
SLIDE 3

We're ep.io

Python Platform-as-a-Service Easy deployment, easy upgrades PostgreSQL, Redis, Celery, and more

slide-4
SLIDE 4

Why am I here?

Architecture Overview What we use, and how What did we learn?

slide-5
SLIDE 5

Architectural Overview

In short: Ever so slightly mad.

slide-6
SLIDE 6

Hardware

Real colo'd machines Linode EC2 (pretty unreliable) (pretty reliable) (pretty reliable) IPv6 (as much as we can)

slide-7
SLIDE 7

Network

Internal networks are easy Cross-Atlantic latency is less fun Variety of different restrictions

slide-8
SLIDE 8

Daemons by the Dozen

We have lots of small components 17, as of June 2011 They all need to communicate

slide-9
SLIDE 9

Redundancy, Redundancy, ...

It's very important that no site dies. Everything can be run as a pair HA and backups both needed Cannot rely on a centralised state

slide-10
SLIDE 10

Security

User data is paramount Quite a bit of our code runs as root Permissions, chroot, other isolation VM per site is too much overhead

slide-11
SLIDE 11

Variety

Python sites are pretty varied We need other languages to work too Some things (PostgreSQL vs MySQL) we have to be less flexible on

slide-12
SLIDE 12

What do we use?

Lots of exciting things, that's what.

slide-13
SLIDE 13

Basic Technologies

Eventlet, ZeroMQ, PostgreSQL Historically, Redis Ubuntu/Debian packages & tools

slide-14
SLIDE 14

Moving Data

Message-passing (ZeroMQ, was Redis) Stored state (PostgreSQL, plain text)

slide-15
SLIDE 15

Storage

We're testing btrfs and GlusterFS One type needed for app disk images One type needed for app data store (mounted on every app instance)

slide-16
SLIDE 16

Eventlet

A shiny, coroutine-filled future

slide-17
SLIDE 17

What is eventlet?

Greenlet-based async/"threading" Multiple hubs (including libevent) Threads yield cooperatively on any async operations

slide-18
SLIDE 18

Brief Example

from eventlet.green import urllib results = {} def fetch(key, url): # The urlopen call will cooperatively yield results[key] = urllib.urlopen(url).read() for i in range(10): eventlet.spawn(fetch, i, "http://ep.io/%s" % i) # There's also a waitall() method on GreenPools while len(results) < 10: eventlet.sleep(1)

slide-19
SLIDE 19

Standard Classes

Eventlet-based daemons Multiple main loops, terminates if any die Catches any exceptions Logs to stderr and remote syslog

slide-20
SLIDE 20

Daemon Example

from ... import BaseDaemon, resilient_loop class Locker(BaseDaemon): main_loops = ["heartbeat_loop", "lock_loop"] def pre_run(self): # Initialise a dictionary of known locks. self.locks = {} @resilient_loop(1) def heartbeat_loop(self): self.send_heartbeat( self.lock_port, "locker-lock", )

slide-21
SLIDE 21

Greening The World

You must use greenlet-friendly libraries Others will work, but just block Eventlet supports most of stdlib Can monkeypatch to support other modules

slide-22
SLIDE 22

We're Not In Kansas Anymore

You can still have race conditions Ungreened modules block everything Some combiantions have odd bugs (unpatched Django & psycopg2)

slide-23
SLIDE 23

Still, it's really useful

We've had upwards of 10,000 threads multiprocessing falls over at that level eventlet is easier to use than threading (much less chance of race conditions)

slide-24
SLIDE 24

Redis

Small but perfectly formed.

slide-25
SLIDE 25

The Beginning

Everything in Redis No, really - app disk images too Disk images quickly moved to, uh, disk

slide-26
SLIDE 26

February - March

Doing lots of filtering "queries" Moved user info, permissions to Postgres App info, messaging still there

slide-27
SLIDE 27

Recently

App info moved to Postgres Messaging moved to ZeroMQ Not used by backend any more

slide-28
SLIDE 28

Why?

It's a great database/store, but not for us We may revisit once we get PGSQL issues Looking forward to Redis Cluster

slide-29
SLIDE 29

ØMQ

A møose taught me the symbol.

slide-30
SLIDE 30

What is ZeroMQ?

It's NOT a message queue Basically high-level sockets Comes in many delicious flavours: PUB/SUB REQ/REP PUSH/PULL XREQ/XREP PAIR

slide-31
SLIDE 31

ZeroMQ Example

from eventlet.green import zmq ctx = zmq.Context() # Request-response style socket sock = ctx.sock(zmq.REQ) # Can connect to multiple endpoints, will pick one sock.connect("tcp://1.2.3.4:567") sock.connect("tcp://1.1.1.1:643") # Send a message, get a message sock.send("Hello, world!") print sock.recv()

slide-32
SLIDE 32

How do we use it?

Mostly REQ/XREP Custom @zmq_loop decorator JSON + security measures

slide-33
SLIDE 33

zmq_loop example

from ... import BaseDaemon, zmq_loop class SomeDaemon(BaseDaemon): main_loops = ["query_loop", "stats_loop"] port = 1234 @zmq_loop(zmq.XREP, "port") def query_loop(data): return {"error": "Only a slide demo!"} @zmq_loop(zmq.PULL, "stats_port") def stats_loop(data): # PULL is one-way, so no return data print data

slide-34
SLIDE 34

Other Nice ZeroMQ things

Eventlet supports it, quite well Can use TCP, PGM, or in-process comms Can be faster than raw messages on TCP Doesn't care if your network isn't up yet

slide-35
SLIDE 35

PTYs

Or, How I Learned To Stop Worrying And Love Unix

slide-36
SLIDE 36

What is a PTY?

It's a process-controllable terminal Used for SSH, etc. We needed them for interactivity

slide-37
SLIDE 37

Attempt One

Just run processes in subprocess Great, until you want to be interactive Some programs insist on a terminal

slide-38
SLIDE 38

Attempt Two

Python has a pty module! Take the raw OS filehandles Try to make it greenlet-compatible Works! Most of the time...

slide-39
SLIDE 39

Greened pty example

def run(self): # First, fork to a new PTY. gc.disable() try: pid, fd = pty.fork() except: gc.enable() raise # If we're the child, run our program. if pid == 0: self.run_child() # Otherwise, do parent stuff else: gc.enable() ...

slide-40
SLIDE 40

Greened pty example

fcntl.fcntl(self.fd, fcntl.F_SETFL, os.O_NONBLOCK) # Call IO greenthreads in_thread = eventlet.spawn(self.in_thread)

  • ut_thread = eventlet.spawn(self.out_thread)
  • ut_thread.wait()
  • ut_thread.kill()

# Wait for process to terminate rpid = 0 while rpid == 0: rpid, status = os.waitpid(self.pid, 0) eventlet.sleep(0.01) in_thread.wait() in_thread.kill()

  • s.close(self.fd)
slide-41
SLIDE 41

Attempt Three

Use subprocess, but with a wrapper Wrapper exposes pty over stdin/stdout Significantly more reliable

slide-42
SLIDE 42

Lesser-Known Modules

They just want to be your friend.

slide-43
SLIDE 43

The resource module

Lets you set file handle, nproc, etc. limits Lets you discover limits, too

slide-44
SLIDE 44

The signal module

Want to catch Ctrl-C in a sane way? We use it to quit cleanly on SIGTERM Can set handlers for most signals

slide-45
SLIDE 45

The atexit module

Not terribly useful most of the time Used in our command-line admin client

slide-46
SLIDE 46

The shlex module

Implements a shell-like lexer shlex.split("command string") gives you arguments for os.exec

slide-47
SLIDE 47

The fcntl module

The portal to a dark world of Unix We use it for fiddling blocking modes Also contains leases, signals, dnotify, creation flags, and pipe fiddling

slide-48
SLIDE 48

Closing Remarks

Because stopping abruptly is bad.

slide-49
SLIDE 49

Adopting fresh technologies can be a pain.

Eventlet, ZeroMQ, new Redis are all young OS packaging and bugs not always fully worked out.

slide-50
SLIDE 50

Don't reinvent the wheel, or

  • ptimize prematurely.

Old advice, but still good. You really don't want to solve things the kernel solves already.

slide-51
SLIDE 51

Reinvent the wheel,

  • ccasionally

Don't necessarily use it Helps you to understand the problem Sometimes it's better (e.g. our balancer)

slide-52
SLIDE 52

Python is really very capable

It's easy to develop and maintain It's not too slow for most jobs There's always PyPy...

slide-53
SLIDE 53

Questions?

Andrew Godwin

andrew@ep.io @andrewgodwin