Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gunicorn, more than a WSGI server

Gunicorn, more than a WSGI server

Gunicorn is known as a Python WSGI HTTP Server for UNIX. But today the WSGI specification shows its limits and people wants more. This talk will introduce the new Gunicorn released in January with a new IPC library usable in others Python programs to handle the concurrency and support HTTP2.

Gunicorn handles the concurrency using a pre-fork worker model: workers are spawned processes managed by a main process. Until now there is no dialog between workers and the master which can trigger some issues like the thundering herd. To solve it and prepare gunicorn to support new protocols like HTTP2, a new IPC library has been specifically written in pure python. Mostly inspired from imsg in OpenBSD (but also Mojo), this new library is entirely written in Python and can be used outside of Gunicorn.

This talk will present the following:

1) The design of Gunicorn 1, its pros and cons 2) Description of the new IPC library how you can use it in your own projects 3) The design of Gunicorn 2 and its usage of the new IPC library, how it can do more than simply WSGI and HTTP 1.1.

Benoit Chesneau

January 30, 2016
Tweet

More Decks by Benoit Chesneau

Other Decks in Technology

Transcript

  1. MORE THAN A WSGI SERVER
    Python FOSDEM 2016

    View Slide

  2. WHAT
    IS GUNICORN

    View Slide

  3. A WSGI SERVER
    ▸ PEP 3333
    ▸ pre-fork worker model
    ▸ Python > 2.6x
    ▸ handle Django & Paste configuration
    ▸ support any concurrency framework

    View Slide

  4. ADDITIONS TO WSGI
    ▸ ALREADY_HANDLED: take control of the socket
    ▸ ‘gunicorn.socket’ environ
    ▸ ‘gunicorn.raw_uri’ environ
    ▸ `transfer-encoding: chunked`

    View Slide

  5. PREFORK WORKER MODEL
    ARBITER
    WORKER
    WORKER
    share socket
    WORKER
    listen
    handle signals
    supervise
    accept
    WSGI server
    handle signals

    View Slide

  6. SHARE NOTHING
    ▸ share only file descriptors
    ▸ Privilege separation
    ▸ Worker: simple process with a run function

    View Slide

  7. WORKER
    accept loop
    setup signals
    sockets
    configuration
    log
    parent pid
    tempfile
    class MyWorker(WorkerBase):
    def __init__(..):

    def init_process(self):

    def run(self):

    View Slide

  8. LET IT CRASH
    ▸ run the application
    ▸ need to notify the arbiter
    ▸ tempfile updates
    ▸ handle application errors
    ▸ but should crash on errors most of the time

    View Slide

  9. set application
    set Config
    EMBED
    class MyApp(BaseApplication):
    def load_config(self):

    def load(self):
    …

    return self.application

    View Slide

  10. DO MORE
    >

    View Slide

  11. DO MORE. BE SAFER.
    ▸ improve listening in the sync worker
    ▸ remove the tempfile
    ▸ prepare for the new protocols
    ▸ improve logging
    ▸ going further

    View Slide

  12. ACCEPT WHEN NEEDED
    ▸ place the listening sockets in an event loop
    ▸ on read, start to accept
    ▸ also have a timer

    View Slide

  13. IMPORT
    GUNICORN.IMSG

    View Slide

  14. GUNICORN.IMSG
    ▸ communicate between processes
    ▸ use UNIX socket
    ▸ sendmsg/recvmsg + buffer
    ▸ 2 methods: send, receive
    ▸ zero copy memory

    View Slide

  15. child
    parent
    IMSG EXAMPLE
    fds =socket.socketpair()
    pid = os.fork()
    if pid != 0:
    # parent
    socket.close(fds[1])
    imsg = IMSG(fds[0]
    return main(imsg)
    # child
    socket.close(fds[0])
    var imsg = IMSG(fds[1])
    return main(imsg)

    View Slide

  16. wait for a message
    send a message
    IMSG EXAMPLE
    main(imsg):
    imsg.send(“sometype”, “somemsg”),
    dispatch_msg(imsg)
    dispatch_msg(imsg):
    while True:
    msg = imsg.recv()
    if msg is None:
    sleep(1)
    continue
    print(msg.data)

    View Slide

  17. REMOVING TEMPFILE
    ▸ a socket pair is opened for each workers
    ▸ an imsg object is created for each
    ▸ imsg object are placed in an eventloop to read
    asynchronously
    ▸ maybe extracted from the code as a simple lib

    View Slide

  18. DETACHED MODE
    ▸ rework ALREADY_HANDLED
    ▸ socket control is given to app
    ▸ but still supervised
    ▸ simple API

    View Slide

  19. simple proc abstraction
    return a proc instance
    EXAMPLE
    def app(environ, start_response):
    ..

    start_response(status, headers)
    proc = MyProc(environ)
    return proc
    class MyProc(gunicorn.Proc):
    def status(self):
    return STATUS_ALIVE
    def terminate(self, Reason):
    ….

    View Slide

  20. IMPROVE LOGGING
    ▸ logging will now be handled in its own process
    ▸ log infos passed via imsg and dispatched by the arbiter
    ▸ fix privilege separation issues

    View Slide

  21. GOING FURTHER
    ▸ HTTP 2
    ▸ static file server?
    ▸ fastcgi?

    View Slide

  22. View Slide

  23. HTTP://GUNICORN.ORG
    Gunicorn
    HTTP://ENKIM.EU
    Enki Multimedia

    View Slide