SlideShare a Scribd company logo
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate, a reasonably fast, non-blocking,
multithreaded WSGI server
Thomas Schorr
Plone Conference 2020
WSGI Why Rust? Project Status Performance Demo Next steps
PEP-3333: Python Web Server Gateway Interface
def application(environ, start_response):
"""Simplest possible WSGI application"""
status = '200 OK'
response_headers = [
('Content-type', 'text/plain')]
start_response(status, response_headers)
return [b'Hello World!n']
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
• 1:1 threading, 1:n threading
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
• 1:1 threading, 1:n threading
• maintain a pool of worker threads
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
• 1:1 threading, 1:n threading
• maintain a pool of worker threads
• multiprocessing
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
• 1:1 threading, 1:n threading
• maintain a pool of worker threads
• multiprocessing
• ...
WSGI Why Rust? Project Status Performance Demo Next steps
The Server Side
• The server invokes the application callable once for each HTTP request it
receives
• Many possibilities for handling requests
• Single threaded server
• Spawn a thread for each incoming request
• 1:1 threading, 1:n threading
• maintain a pool of worker threads
• multiprocessing
• ...
• The WSGI server can give hints through environ dictionary
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
• databases, caches
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
• databases, caches
• connection might not be thread safe
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
• databases, caches
• connection might not be thread safe
• connection/setup might be expensive
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
• databases, caches
• connection might not be thread safe
• connection/setup might be expensive
• all of the above is true for Zope
WSGI Why Rust? Project Status Performance Demo Next steps
The Application Side
• often needs to connect to components that outlive the single request
• databases, caches
• connection might not be thread safe
• connection/setup might be expensive
• all of the above is true for Zope
• recipe for disaster: choose a WSGI server with an inappropriate worker
model
WSGI Why Rust? Project Status Performance Demo Next steps
Consequence: Limited Choice
of WSGI servers suitable for Zope/Plone.
• waitress (the default) with very good overall performance
• bjoern: fast, non-blocking, single threaded
• ...
WSGI Why Rust? Project Status Performance Demo Next steps
More options please
Wishlist:
• multithreaded, 1:1 threading, workerpool
• PasteDeploy entry point
• handle the Zope/Plone use case
• non-blocking
• File wrapper supporting sendfile
• competitive performance
Non Goals
• Python 2
• ASGI (not yet at least)
• Windows
WSGI Why Rust? Project Status Performance Demo Next steps
Why Rust?
Naive expectations:
• Faster than Python
• Easier to use than C
WSGI Why Rust? Project Status Performance Demo Next steps
Performance
Performance
Emmerich, P. et al (2019): The Case for Writing Network Drivers in High-Level Programming Languages. -
https://www.net.in.tum.de/fileadmin/bibtex/publications/papers/the-case-for-writing-network-drivers-in-high-level-languages.pdf
.
WSGI Why Rust? Project Status Performance Demo Next steps
Memory Management through Ownership
• feature unique to Rust
• a set of rules that the compiler checks at compile time
(https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
• Each value in Rust has a variable that’s called it’s owner.
• There can be only one owner at a time.
• When the owner goes out of scope, the value will be dropped.
• Drop is a trait; there’s a default implementation that you can override
• You can still control where (stack or heap) your data is stored.
WSGI Why Rust? Project Status Performance Demo Next steps
How is that relevant?
Example: interfacing with Python
• Python memory management: reference counting + garbage collection
• association: increasing an objects’ refcount using Py_INCREF
• should match with corresponding Py_DECREF invocations
• garbage collection when object refcount goes to 0
• Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
WSGI Why Rust? Project Status Performance Demo Next steps
How is that relevant?
Example: interfacing with Python
• Python memory management: reference counting + garbage collection
• association: increasing an objects’ refcount using Py_INCREF
• should match with corresponding Py_DECREF invocations
• garbage collection when object refcount goes to 0
• Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
• 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in
zope.interface (50 Py_DECREF)
WSGI Why Rust? Project Status Performance Demo Next steps
How is that relevant?
Example: interfacing with Python
• Python memory management: reference counting + garbage collection
• association: increasing an objects’ refcount using Py_INCREF
• should match with corresponding Py_DECREF invocations
• garbage collection when object refcount goes to 0
• Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
• 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in
zope.interface (50 Py_DECREF)
• 1 Py_INCREF in rust-cpython (4 Py_DECREF)
WSGI Why Rust? Project Status Performance Demo Next steps
How is that relevant?
Example: interfacing with Python
• Python memory management: reference counting + garbage collection
• association: increasing an objects’ refcount using Py_INCREF
• should match with corresponding Py_DECREF invocations
• garbage collection when object refcount goes to 0
• Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
• 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in
zope.interface (50 Py_DECREF)
• 1 Py_INCREF in rust-cpython (4 Py_DECREF)
• very hard to create a mismatch of Py_INCREF/Py_DECREF
invocations, making it harder to create memory leaks or core dumps
WSGI Why Rust? Project Status Performance Demo Next steps
How is that relevant?
Example: interfacing with Python
• Python memory management: reference counting + garbage collection
• association: increasing an objects’ refcount using Py_INCREF
• should match with corresponding Py_DECREF invocations
• garbage collection when object refcount goes to 0
• Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
• 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in
zope.interface (50 Py_DECREF)
• 1 Py_INCREF in rust-cpython (4 Py_DECREF)
• very hard to create a mismatch of Py_INCREF/Py_DECREF
invocations, making it harder to create memory leaks or core dumps
• still possible to create more references than needed
WSGI Why Rust? Project Status Performance Demo Next steps
Other Rust features
• strict typing will find many problems at compile time
• Pattern matching
• very good documentation, helpful compiler messages
WSGI Why Rust? Project Status Performance Demo Next steps
What is Pyruvate from a user perspective
• a package available from PyPI:
WSGI Why Rust? Project Status Performance Demo Next steps
What is Pyruvate from a user perspective
• a package available from PyPI:
pip install pyruvate
WSGI Why Rust? Project Status Performance Demo Next steps
What is Pyruvate from a user perspective
• a package available from PyPI:
pip install pyruvate
• an importable Python module:
WSGI Why Rust? Project Status Performance Demo Next steps
What is Pyruvate from a user perspective
• a package available from PyPI:
pip install pyruvate
• an importable Python module:
import pyruvate
def application(environ, start_response):
"""WSGI application"""
...
pyruvate.serve(application, '0.0.0.0:7878', 3)
WSGI Why Rust? Project Status Performance Demo Next steps
Using Pyruvate with Zope/Plone
with plone.recipe.zope2instance:
• buildout.cfg
[instance]
recipe = plone.recipe.zope2instance
http-address = 127.0.0.1:8080
eggs =
Plone
pyruvate
wsgi-ini-template = ${buildout:directory}/
templates/pyruvate.ini.in
• pyruvate.ini.in Template
[server:main]
use = egg:pyruvate#main
socket = %(http_address)s
workers = 2
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
• Cargo.toml pulls Rust dependencies
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
• Cargo.toml pulls Rust dependencies
• setup.py
• uses setuptools_rust to build a
RustExtension
• defines PasteDeploy entry point
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
• Cargo.toml pulls Rust dependencies
• setup.py
• uses setuptools_rust to build a
RustExtension
• defines PasteDeploy entry point
• pyproject.toml to specify build system
requirements (PEP 518)
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
• Cargo.toml pulls Rust dependencies
• setup.py
• uses setuptools_rust to build a
RustExtension
• defines PasteDeploy entry point
• pyproject.toml to specify build system
requirements (PEP 518)
• tests folder containing (currently only) Python
tests (unit tests in Rust modules)
WSGI Why Rust? Project Status Performance Demo Next steps
Pyruvate project structure
• initially created with cargo new --lib
• Rust sources in src folder
• Cargo.toml pulls Rust dependencies
• setup.py
• uses setuptools_rust to build a
RustExtension
• defines PasteDeploy entry point
• pyproject.toml to specify build system
requirements (PEP 518)
• tests folder containing (currently only) Python
tests (unit tests in Rust modules)
• __init__.py in pyruvate folder
• Paste Deploy entry point
• FileWrapper import
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
• Linting: rustfmt, clippy
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
• Linting: rustfmt, clippy
• cargo test
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
• Linting: rustfmt, clippy
• cargo test
• coverage report using kcov, uploaded to
https://codecov.io
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
• Linting: rustfmt, clippy
• cargo test
• coverage report using kcov, uploaded to
https://codecov.io
• Python integration tests with tox
WSGI Why Rust? Project Status Performance Demo Next steps
Gitlab Pipeline
• Two stages: test + build
• Linting: rustfmt, clippy
• cargo test
• coverage report using kcov, uploaded to
https://codecov.io
• Python integration tests with tox
• build wheels
WSGI Why Rust? Project Status Performance Demo Next steps
Binary packages
• manylinux2010 wheels for Python 3.6-3.9
• switched from manylinux1 after stable Rust stopped supporting the old
ABI (ELF file OS ABI invalid error when loading rust shared libraries)
1.47.0
• manylinux2010 needs recent pip and setuptools versions
WSGI Why Rust? Project Status Performance Demo Next steps
Binary packages
• manylinux2010 wheels for Python 3.6-3.9
• switched from manylinux1 after stable Rust stopped supporting the old
ABI (ELF file OS ABI invalid error when loading rust shared libraries)
1.47.0
• manylinux2010 needs recent pip and setuptools versions
• pip >= 19.0 if pip prefers sdist over wheel (and there’s no Rust)
• setuptools >= 42.0.0 (when using zc.buildout)
WSGI Why Rust? Project Status Performance Demo Next steps
Binary packages
• manylinux2010 wheels for Python 3.6-3.9
• switched from manylinux1 after stable Rust stopped supporting the old
ABI (ELF file OS ABI invalid error when loading rust shared libraries)
1.47.0
• manylinux2010 needs recent pip and setuptools versions
• pip >= 19.0 if pip prefers sdist over wheel (and there’s no Rust)
• setuptools >= 42.0.0 (when using zc.buildout)
• wanted: MacOS
WSGI Why Rust? Project Status Performance Demo Next steps
Features
• rust-cpython based Python interface
(https://github.com/dgrunwald/rust-cpython)
• Nonblocking IO using mio (https://github.com/tokio-rs/mio)
• Nonblocking read
• blocking or nonblocking write
• Worker pool based on threadpool (https://docs.rs/threadpool); 1:1
threading
• PasteDeploy entry point
• integrates with Python logging
• asynchronous logging -> no need to hold the GIL when creating the log
message
• logging configuration in wsgi.ini
• TCP or Unix Domain sockets
• supports systemd socket activation
WSGI Why Rust? Project Status Performance Demo Next steps
Performance
Pierre Terre / Rabbit Hole, Monarch’s Way / CC BY-SA 2.0
• number of requests/amount of
data transferred per unit of time
• Testing and eventually
improving it
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
• limiting socket buffer sizes of a Vagrant box
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
• limiting socket buffer sizes of a Vagrant box
• Docker?
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
• limiting socket buffer sizes of a Vagrant box
• Docker?
• Flame graphs from perf data
(http://www.brendangregg.com/flamegraphs.html)
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
• limiting socket buffer sizes of a Vagrant box
• Docker?
• Flame graphs from perf data
(http://www.brendangregg.com/flamegraphs.html)
• .to_lower() is much more expensive than
.to_ascii_uppercase()
WSGI Why Rust? Project Status Performance Demo Next steps
Approach
• Static code analyis + refactoring
• reminder: pyruvate started as a Hello Rust project
• memory allocations are expensive
• How to induce socket blocking?
• limiting socket buffer sizes of a Vagrant box
• Docker?
• Flame graphs from perf data
(http://www.brendangregg.com/flamegraphs.html)
• .to_lower() is much more expensive than
.to_ascii_uppercase()
• load testing with siege and ab
WSGI Why Rust? Project Status Performance Demo Next steps
Performance: Design considerations
• Python Global Interpreter Lock: Python code can only run when holding
the GIL
• Multiple worker threads need to acquire the GIL in turn
• acquire GIL only for application execution
• drop GIL when doing IO
• more than one possible way to do this
• IO event polling
• abstraction: mio Poll instance
• accepted connections are registered for read events with a Poll instance
in the main thread
• completely read requests + connection are passed to the worker pool
• iterate over WSGI response chunks (needs GIL)
• blocking write: loop until response is completely written
• non-blocking write:
• write until EAGAIN
• register connection for write events with per worker Poll instance
• drop GIL, stash response
WSGI Why Rust? Project Status Performance Demo Next steps
Performance: current status
• Lenovo X390 and Vagrant (2 CPU, 2 G RAM, 8K write buffer size limit)
• faster than waitress on a Hello world WSGI application
• faster that waitress on / (looking at
https://zope.readthedocs.io/en/4.x/wsgi.html#test-criteria-for-
recommendations)
• but slower on /Plone
• more performance testing needed
WSGI Why Rust? Project Status Performance Demo Next steps
Live Demo
WSGI Why Rust? Project Status Performance Demo Next steps
Release 1.0
• Planned for end of this year
• Reuse connections (keep-alive + chunked transport)
• Branch on Gitlab, needs some work
• MacOS support wanted
• optimize pipeline
• use a kcov binary package
• async logging: thread ID
• More testing + bugfixing
WSGI Why Rust? Project Status Performance Demo Next steps
Thanks for your attention
• Thomas Schorr
• info@thomasschorr.de
• https://gitlab.com/tschorr/pyruvate
• https://pypi.org/project/pyruvate

More Related Content

What's hot

API Design first with Swagger
API Design first with SwaggerAPI Design first with Swagger
API Design first with Swagger
Tony Tam
 
Rest API with Swagger and NodeJS
Rest API with Swagger and NodeJSRest API with Swagger and NodeJS
Rest API with Swagger and NodeJS
Luigi Saetta
 
Building APIs with Node.js and Swagger
Building APIs with Node.js and SwaggerBuilding APIs with Node.js and Swagger
Building APIs with Node.js and Swagger
Jeremy Whitlock
 
Designing APIs with OpenAPI Spec
Designing APIs with OpenAPI SpecDesigning APIs with OpenAPI Spec
Designing APIs with OpenAPI Spec
Adam Paxton
 
Consuming Restful APIs using Swagger v2.0
Consuming Restful APIs using Swagger v2.0Consuming Restful APIs using Swagger v2.0
Consuming Restful APIs using Swagger v2.0
Pece Nikolovski
 
Swagger - make your API accessible
Swagger - make your API accessibleSwagger - make your API accessible
Swagger - make your API accessible
Victor Trakhtenberg
 
Swagger 2.0: Latest and Greatest
Swagger 2.0: Latest and GreatestSwagger 2.0: Latest and Greatest
Swagger 2.0: Latest and Greatest
LaunchAny
 
Swagger for-your-api
Swagger for-your-apiSwagger for-your-api
Swagger for-your-api
Tony Tam
 
API documentation with Swagger UI(LT)
API documentation with Swagger UI(LT)API documentation with Swagger UI(LT)
API documentation with Swagger UI(LT)
Jiang Wu
 
Crystal clear service interfaces w/ Swagger/OpenAPI
Crystal clear service interfaces w/ Swagger/OpenAPICrystal clear service interfaces w/ Swagger/OpenAPI
Crystal clear service interfaces w/ Swagger/OpenAPI
Scott Triglia
 
Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing Swagger
Tony Tam
 
Understanding how to use Swagger and its tools
Understanding how to use Swagger and its toolsUnderstanding how to use Swagger and its tools
Understanding how to use Swagger and its tools
Swagger API
 
Swagger APIs for Humans and Robots (Gluecon)
Swagger APIs for Humans and Robots (Gluecon)Swagger APIs for Humans and Robots (Gluecon)
Swagger APIs for Humans and Robots (Gluecon)
Tony Tam
 
Exposing Salesforce REST Services Using Swagger
Exposing Salesforce REST Services Using SwaggerExposing Salesforce REST Services Using Swagger
Exposing Salesforce REST Services Using Swagger
Salesforce Developers
 
Developing Faster with Swagger
Developing Faster with SwaggerDeveloping Faster with Swagger
Developing Faster with Swagger
Tony Tam
 
Design Driven API Development
Design Driven API DevelopmentDesign Driven API Development
Design Driven API Development
Sokichi Fujita
 
Streamlining API with Swagger.io
Streamlining API with Swagger.ioStreamlining API with Swagger.io
Streamlining API with Swagger.io
Victor Augusteo
 
Why your APIs should fly first class
Why your APIs should fly first classWhy your APIs should fly first class
Why your APIs should fly first class
LibbySchulze
 
Quick run in with Swagger
Quick run in with SwaggerQuick run in with Swagger
Quick run in with Swagger
Mesh Korea
 
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
Alvaro Sanchez-Mariscal
 

What's hot (20)

API Design first with Swagger
API Design first with SwaggerAPI Design first with Swagger
API Design first with Swagger
 
Rest API with Swagger and NodeJS
Rest API with Swagger and NodeJSRest API with Swagger and NodeJS
Rest API with Swagger and NodeJS
 
Building APIs with Node.js and Swagger
Building APIs with Node.js and SwaggerBuilding APIs with Node.js and Swagger
Building APIs with Node.js and Swagger
 
Designing APIs with OpenAPI Spec
Designing APIs with OpenAPI SpecDesigning APIs with OpenAPI Spec
Designing APIs with OpenAPI Spec
 
Consuming Restful APIs using Swagger v2.0
Consuming Restful APIs using Swagger v2.0Consuming Restful APIs using Swagger v2.0
Consuming Restful APIs using Swagger v2.0
 
Swagger - make your API accessible
Swagger - make your API accessibleSwagger - make your API accessible
Swagger - make your API accessible
 
Swagger 2.0: Latest and Greatest
Swagger 2.0: Latest and GreatestSwagger 2.0: Latest and Greatest
Swagger 2.0: Latest and Greatest
 
Swagger for-your-api
Swagger for-your-apiSwagger for-your-api
Swagger for-your-api
 
API documentation with Swagger UI(LT)
API documentation with Swagger UI(LT)API documentation with Swagger UI(LT)
API documentation with Swagger UI(LT)
 
Crystal clear service interfaces w/ Swagger/OpenAPI
Crystal clear service interfaces w/ Swagger/OpenAPICrystal clear service interfaces w/ Swagger/OpenAPI
Crystal clear service interfaces w/ Swagger/OpenAPI
 
Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing Swagger
 
Understanding how to use Swagger and its tools
Understanding how to use Swagger and its toolsUnderstanding how to use Swagger and its tools
Understanding how to use Swagger and its tools
 
Swagger APIs for Humans and Robots (Gluecon)
Swagger APIs for Humans and Robots (Gluecon)Swagger APIs for Humans and Robots (Gluecon)
Swagger APIs for Humans and Robots (Gluecon)
 
Exposing Salesforce REST Services Using Swagger
Exposing Salesforce REST Services Using SwaggerExposing Salesforce REST Services Using Swagger
Exposing Salesforce REST Services Using Swagger
 
Developing Faster with Swagger
Developing Faster with SwaggerDeveloping Faster with Swagger
Developing Faster with Swagger
 
Design Driven API Development
Design Driven API DevelopmentDesign Driven API Development
Design Driven API Development
 
Streamlining API with Swagger.io
Streamlining API with Swagger.ioStreamlining API with Swagger.io
Streamlining API with Swagger.io
 
Why your APIs should fly first class
Why your APIs should fly first classWhy your APIs should fly first class
Why your APIs should fly first class
 
Quick run in with Swagger
Quick run in with SwaggerQuick run in with Swagger
Quick run in with Swagger
 
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
 

Similar to Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server

The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
Viktor Todorov
 
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::SynchronyFast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::SynchronyKyle Drake
 
Enterprise PHP Development - ZendCon 2008
Enterprise PHP Development - ZendCon 2008Enterprise PHP Development - ZendCon 2008
Enterprise PHP Development - ZendCon 2008
Ivo Jansch
 
Northeast PHP - High Performance PHP
Northeast PHP - High Performance PHPNortheast PHP - High Performance PHP
Northeast PHP - High Performance PHP
Jonathan Klein
 
Enterprise PHP (php|works 2008)
Enterprise PHP (php|works 2008)Enterprise PHP (php|works 2008)
Enterprise PHP (php|works 2008)
Ivo Jansch
 
2019 StartIT - Boosting your performance with Blackfire
2019 StartIT - Boosting your performance with Blackfire2019 StartIT - Boosting your performance with Blackfire
2019 StartIT - Boosting your performance with Blackfire
Marko Mitranić
 
Concourse Workshop
Concourse WorkshopConcourse Workshop
Concourse Workshop
VMware Tanzu
 
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
OpenNebula Project
 
Use Xdebug to profile PHP
Use Xdebug to profile PHPUse Xdebug to profile PHP
Use Xdebug to profile PHP
Seravo
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
Workhorse Computing
 
Jun Heider - Flex Application Profiling By Example
Jun Heider - Flex Application Profiling By ExampleJun Heider - Flex Application Profiling By Example
Jun Heider - Flex Application Profiling By Example
360|Conferences
 
web2py:Web development like a boss
web2py:Web development like a bossweb2py:Web development like a boss
web2py:Web development like a boss
Francisco Ribeiro
 
Socket applications
Socket applicationsSocket applications
Socket applicationsJoão Moura
 
Site Performance - From Pinto to Ferrari
Site Performance - From Pinto to FerrariSite Performance - From Pinto to Ferrari
Site Performance - From Pinto to FerrariJoseph Scott
 
GDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
GDD Japan 2009 - Designing OpenSocial Apps For Speed and ScaleGDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
GDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
Patrick Chanezon
 
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
Tech in Asia ID
 
Resin Outperforms NginX
Resin Outperforms NginXResin Outperforms NginX
Resin Outperforms NginX
billdigman
 
Test
TestTest
Test
Eddie Kao
 
JavaOne 2014: Java vs JavaScript
JavaOne 2014:   Java vs JavaScriptJavaOne 2014:   Java vs JavaScript
JavaOne 2014: Java vs JavaScript
Chris Bailey
 
Nodejs
NodejsNodejs

Similar to Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server (20)

The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
The Recording HTTP Proxy: Not Yet Another Messiah - Bulgaria PHP 2019
 
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::SynchronyFast, concurrent ruby web applications with EventMachine and EM::Synchrony
Fast, concurrent ruby web applications with EventMachine and EM::Synchrony
 
Enterprise PHP Development - ZendCon 2008
Enterprise PHP Development - ZendCon 2008Enterprise PHP Development - ZendCon 2008
Enterprise PHP Development - ZendCon 2008
 
Northeast PHP - High Performance PHP
Northeast PHP - High Performance PHPNortheast PHP - High Performance PHP
Northeast PHP - High Performance PHP
 
Enterprise PHP (php|works 2008)
Enterprise PHP (php|works 2008)Enterprise PHP (php|works 2008)
Enterprise PHP (php|works 2008)
 
2019 StartIT - Boosting your performance with Blackfire
2019 StartIT - Boosting your performance with Blackfire2019 StartIT - Boosting your performance with Blackfire
2019 StartIT - Boosting your performance with Blackfire
 
Concourse Workshop
Concourse WorkshopConcourse Workshop
Concourse Workshop
 
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
OpenNebulaConf 2016 - Measuring and tuning VM performance by Boyan Krosnov, S...
 
Use Xdebug to profile PHP
Use Xdebug to profile PHPUse Xdebug to profile PHP
Use Xdebug to profile PHP
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
Jun Heider - Flex Application Profiling By Example
Jun Heider - Flex Application Profiling By ExampleJun Heider - Flex Application Profiling By Example
Jun Heider - Flex Application Profiling By Example
 
web2py:Web development like a boss
web2py:Web development like a bossweb2py:Web development like a boss
web2py:Web development like a boss
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
Site Performance - From Pinto to Ferrari
Site Performance - From Pinto to FerrariSite Performance - From Pinto to Ferrari
Site Performance - From Pinto to Ferrari
 
GDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
GDD Japan 2009 - Designing OpenSocial Apps For Speed and ScaleGDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
GDD Japan 2009 - Designing OpenSocial Apps For Speed and Scale
 
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
 
Resin Outperforms NginX
Resin Outperforms NginXResin Outperforms NginX
Resin Outperforms NginX
 
Test
TestTest
Test
 
JavaOne 2014: Java vs JavaScript
JavaOne 2014:   Java vs JavaScriptJavaOne 2014:   Java vs JavaScript
JavaOne 2014: Java vs JavaScript
 
Nodejs
NodejsNodejs
Nodejs
 

More from PloneFoundation

Form Block / Formbuilder
Form Block / FormbuilderForm Block / Formbuilder
Form Block / Formbuilder
PloneFoundation
 
Améliorer la gouvernance et la gestion interne de la ville avec Plone
Améliorer la gouvernance et la gestion interne de la ville avec PloneAméliorer la gouvernance et la gestion interne de la ville avec Plone
Améliorer la gouvernance et la gestion interne de la ville avec Plone
PloneFoundation
 
Running Plone on AWS
Running Plone on AWSRunning Plone on AWS
Running Plone on AWS
PloneFoundation
 
State of Plone 4 and 5
State of Plone 4 and 5State of Plone 4 and 5
State of Plone 4 and 5
PloneFoundation
 
State of Plone 2020
State of Plone 2020State of Plone 2020
State of Plone 2020
PloneFoundation
 
Plone 6 Theming based on Barceloneta LTS
Plone 6 Theming based on Barceloneta LTSPlone 6 Theming based on Barceloneta LTS
Plone 6 Theming based on Barceloneta LTS
PloneFoundation
 
Modernize Plone's Classic UI
Modernize Plone's Classic UIModernize Plone's Classic UI
Modernize Plone's Classic UI
PloneFoundation
 
Green Party Maps
Green Party MapsGreen Party Maps
Green Party Maps
PloneFoundation
 
Volto: A Journey towards Personalization
Volto: A Journey towards PersonalizationVolto: A Journey towards Personalization
Volto: A Journey towards Personalization
PloneFoundation
 
Bundle Splitting in Volto
Bundle Splitting in VoltoBundle Splitting in Volto
Bundle Splitting in Volto
PloneFoundation
 
Asking questions for the benefit of your future self - Growing with the Plone...
Asking questions for the benefit of your future self - Growing with the Plone...Asking questions for the benefit of your future self - Growing with the Plone...
Asking questions for the benefit of your future self - Growing with the Plone...
PloneFoundation
 
The State of Pillow
The State of PillowThe State of Pillow
The State of Pillow
PloneFoundation
 
Pyramid and the Pylons Project in the wild
Pyramid and the Pylons Project in the wildPyramid and the Pylons Project in the wild
Pyramid and the Pylons Project in the wild
PloneFoundation
 
Questions
QuestionsQuestions
Questions
PloneFoundation
 

More from PloneFoundation (14)

Form Block / Formbuilder
Form Block / FormbuilderForm Block / Formbuilder
Form Block / Formbuilder
 
Améliorer la gouvernance et la gestion interne de la ville avec Plone
Améliorer la gouvernance et la gestion interne de la ville avec PloneAméliorer la gouvernance et la gestion interne de la ville avec Plone
Améliorer la gouvernance et la gestion interne de la ville avec Plone
 
Running Plone on AWS
Running Plone on AWSRunning Plone on AWS
Running Plone on AWS
 
State of Plone 4 and 5
State of Plone 4 and 5State of Plone 4 and 5
State of Plone 4 and 5
 
State of Plone 2020
State of Plone 2020State of Plone 2020
State of Plone 2020
 
Plone 6 Theming based on Barceloneta LTS
Plone 6 Theming based on Barceloneta LTSPlone 6 Theming based on Barceloneta LTS
Plone 6 Theming based on Barceloneta LTS
 
Modernize Plone's Classic UI
Modernize Plone's Classic UIModernize Plone's Classic UI
Modernize Plone's Classic UI
 
Green Party Maps
Green Party MapsGreen Party Maps
Green Party Maps
 
Volto: A Journey towards Personalization
Volto: A Journey towards PersonalizationVolto: A Journey towards Personalization
Volto: A Journey towards Personalization
 
Bundle Splitting in Volto
Bundle Splitting in VoltoBundle Splitting in Volto
Bundle Splitting in Volto
 
Asking questions for the benefit of your future self - Growing with the Plone...
Asking questions for the benefit of your future self - Growing with the Plone...Asking questions for the benefit of your future self - Growing with the Plone...
Asking questions for the benefit of your future self - Growing with the Plone...
 
The State of Pillow
The State of PillowThe State of Pillow
The State of Pillow
 
Pyramid and the Pylons Project in the wild
Pyramid and the Pylons Project in the wildPyramid and the Pylons Project in the wild
Pyramid and the Pylons Project in the wild
 
Questions
QuestionsQuestions
Questions
 

Recently uploaded

Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
informapgpstrackings
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
e20449
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
WSO2
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 

Recently uploaded (20)

Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Graphic Design Crash Course for beginners
Graphic Design Crash Course for beginnersGraphic Design Crash Course for beginners
Graphic Design Crash Course for beginners
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 

Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server

  • 1. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server Thomas Schorr Plone Conference 2020
  • 2. WSGI Why Rust? Project Status Performance Demo Next steps PEP-3333: Python Web Server Gateway Interface def application(environ, start_response): """Simplest possible WSGI application""" status = '200 OK' response_headers = [ ('Content-type', 'text/plain')] start_response(status, response_headers) return [b'Hello World!n']
  • 3. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives
  • 4. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests
  • 5. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server
  • 6. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request
  • 7. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request • 1:1 threading, 1:n threading
  • 8. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request • 1:1 threading, 1:n threading • maintain a pool of worker threads
  • 9. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request • 1:1 threading, 1:n threading • maintain a pool of worker threads • multiprocessing
  • 10. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request • 1:1 threading, 1:n threading • maintain a pool of worker threads • multiprocessing • ...
  • 11. WSGI Why Rust? Project Status Performance Demo Next steps The Server Side • The server invokes the application callable once for each HTTP request it receives • Many possibilities for handling requests • Single threaded server • Spawn a thread for each incoming request • 1:1 threading, 1:n threading • maintain a pool of worker threads • multiprocessing • ... • The WSGI server can give hints through environ dictionary
  • 12. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request
  • 13. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request • databases, caches
  • 14. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request • databases, caches • connection might not be thread safe
  • 15. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request • databases, caches • connection might not be thread safe • connection/setup might be expensive
  • 16. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request • databases, caches • connection might not be thread safe • connection/setup might be expensive • all of the above is true for Zope
  • 17. WSGI Why Rust? Project Status Performance Demo Next steps The Application Side • often needs to connect to components that outlive the single request • databases, caches • connection might not be thread safe • connection/setup might be expensive • all of the above is true for Zope • recipe for disaster: choose a WSGI server with an inappropriate worker model
  • 18. WSGI Why Rust? Project Status Performance Demo Next steps Consequence: Limited Choice of WSGI servers suitable for Zope/Plone. • waitress (the default) with very good overall performance • bjoern: fast, non-blocking, single threaded • ...
  • 19. WSGI Why Rust? Project Status Performance Demo Next steps More options please Wishlist: • multithreaded, 1:1 threading, workerpool • PasteDeploy entry point • handle the Zope/Plone use case • non-blocking • File wrapper supporting sendfile • competitive performance Non Goals • Python 2 • ASGI (not yet at least) • Windows
  • 20. WSGI Why Rust? Project Status Performance Demo Next steps Why Rust? Naive expectations: • Faster than Python • Easier to use than C
  • 21. WSGI Why Rust? Project Status Performance Demo Next steps Performance Performance Emmerich, P. et al (2019): The Case for Writing Network Drivers in High-Level Programming Languages. - https://www.net.in.tum.de/fileadmin/bibtex/publications/papers/the-case-for-writing-network-drivers-in-high-level-languages.pdf .
  • 22. WSGI Why Rust? Project Status Performance Demo Next steps Memory Management through Ownership • feature unique to Rust • a set of rules that the compiler checks at compile time (https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) • Each value in Rust has a variable that’s called it’s owner. • There can be only one owner at a time. • When the owner goes out of scope, the value will be dropped. • Drop is a trait; there’s a default implementation that you can override • You can still control where (stack or heap) your data is stored.
  • 23. WSGI Why Rust? Project Status Performance Demo Next steps How is that relevant? Example: interfacing with Python • Python memory management: reference counting + garbage collection • association: increasing an objects’ refcount using Py_INCREF • should match with corresponding Py_DECREF invocations • garbage collection when object refcount goes to 0 • Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps
  • 24. WSGI Why Rust? Project Status Performance Demo Next steps How is that relevant? Example: interfacing with Python • Python memory management: reference counting + garbage collection • association: increasing an objects’ refcount using Py_INCREF • should match with corresponding Py_DECREF invocations • garbage collection when object refcount goes to 0 • Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps • 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in zope.interface (50 Py_DECREF)
  • 25. WSGI Why Rust? Project Status Performance Demo Next steps How is that relevant? Example: interfacing with Python • Python memory management: reference counting + garbage collection • association: increasing an objects’ refcount using Py_INCREF • should match with corresponding Py_DECREF invocations • garbage collection when object refcount goes to 0 • Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps • 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in zope.interface (50 Py_DECREF) • 1 Py_INCREF in rust-cpython (4 Py_DECREF)
  • 26. WSGI Why Rust? Project Status Performance Demo Next steps How is that relevant? Example: interfacing with Python • Python memory management: reference counting + garbage collection • association: increasing an objects’ refcount using Py_INCREF • should match with corresponding Py_DECREF invocations • garbage collection when object refcount goes to 0 • Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps • 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in zope.interface (50 Py_DECREF) • 1 Py_INCREF in rust-cpython (4 Py_DECREF) • very hard to create a mismatch of Py_INCREF/Py_DECREF invocations, making it harder to create memory leaks or core dumps
  • 27. WSGI Why Rust? Project Status Performance Demo Next steps How is that relevant? Example: interfacing with Python • Python memory management: reference counting + garbage collection • association: increasing an objects’ refcount using Py_INCREF • should match with corresponding Py_DECREF invocations • garbage collection when object refcount goes to 0 • Py_INCREF/Py_DECREF mismatch: memory leaks, core dumps • 63 occurences of Py_INCREF in BTrees (79 Py_DECREF), 19 in zope.interface (50 Py_DECREF) • 1 Py_INCREF in rust-cpython (4 Py_DECREF) • very hard to create a mismatch of Py_INCREF/Py_DECREF invocations, making it harder to create memory leaks or core dumps • still possible to create more references than needed
  • 28. WSGI Why Rust? Project Status Performance Demo Next steps Other Rust features • strict typing will find many problems at compile time • Pattern matching • very good documentation, helpful compiler messages
  • 29. WSGI Why Rust? Project Status Performance Demo Next steps What is Pyruvate from a user perspective • a package available from PyPI:
  • 30. WSGI Why Rust? Project Status Performance Demo Next steps What is Pyruvate from a user perspective • a package available from PyPI: pip install pyruvate
  • 31. WSGI Why Rust? Project Status Performance Demo Next steps What is Pyruvate from a user perspective • a package available from PyPI: pip install pyruvate • an importable Python module:
  • 32. WSGI Why Rust? Project Status Performance Demo Next steps What is Pyruvate from a user perspective • a package available from PyPI: pip install pyruvate • an importable Python module: import pyruvate def application(environ, start_response): """WSGI application""" ... pyruvate.serve(application, '0.0.0.0:7878', 3)
  • 33. WSGI Why Rust? Project Status Performance Demo Next steps Using Pyruvate with Zope/Plone with plone.recipe.zope2instance: • buildout.cfg [instance] recipe = plone.recipe.zope2instance http-address = 127.0.0.1:8080 eggs = Plone pyruvate wsgi-ini-template = ${buildout:directory}/ templates/pyruvate.ini.in • pyruvate.ini.in Template [server:main] use = egg:pyruvate#main socket = %(http_address)s workers = 2
  • 34. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib
  • 35. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder
  • 36. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder • Cargo.toml pulls Rust dependencies
  • 37. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder • Cargo.toml pulls Rust dependencies • setup.py • uses setuptools_rust to build a RustExtension • defines PasteDeploy entry point
  • 38. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder • Cargo.toml pulls Rust dependencies • setup.py • uses setuptools_rust to build a RustExtension • defines PasteDeploy entry point • pyproject.toml to specify build system requirements (PEP 518)
  • 39. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder • Cargo.toml pulls Rust dependencies • setup.py • uses setuptools_rust to build a RustExtension • defines PasteDeploy entry point • pyproject.toml to specify build system requirements (PEP 518) • tests folder containing (currently only) Python tests (unit tests in Rust modules)
  • 40. WSGI Why Rust? Project Status Performance Demo Next steps Pyruvate project structure • initially created with cargo new --lib • Rust sources in src folder • Cargo.toml pulls Rust dependencies • setup.py • uses setuptools_rust to build a RustExtension • defines PasteDeploy entry point • pyproject.toml to specify build system requirements (PEP 518) • tests folder containing (currently only) Python tests (unit tests in Rust modules) • __init__.py in pyruvate folder • Paste Deploy entry point • FileWrapper import
  • 41. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build
  • 42. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build • Linting: rustfmt, clippy
  • 43. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build • Linting: rustfmt, clippy • cargo test
  • 44. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build • Linting: rustfmt, clippy • cargo test • coverage report using kcov, uploaded to https://codecov.io
  • 45. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build • Linting: rustfmt, clippy • cargo test • coverage report using kcov, uploaded to https://codecov.io • Python integration tests with tox
  • 46. WSGI Why Rust? Project Status Performance Demo Next steps Gitlab Pipeline • Two stages: test + build • Linting: rustfmt, clippy • cargo test • coverage report using kcov, uploaded to https://codecov.io • Python integration tests with tox • build wheels
  • 47. WSGI Why Rust? Project Status Performance Demo Next steps Binary packages • manylinux2010 wheels for Python 3.6-3.9 • switched from manylinux1 after stable Rust stopped supporting the old ABI (ELF file OS ABI invalid error when loading rust shared libraries) 1.47.0 • manylinux2010 needs recent pip and setuptools versions
  • 48. WSGI Why Rust? Project Status Performance Demo Next steps Binary packages • manylinux2010 wheels for Python 3.6-3.9 • switched from manylinux1 after stable Rust stopped supporting the old ABI (ELF file OS ABI invalid error when loading rust shared libraries) 1.47.0 • manylinux2010 needs recent pip and setuptools versions • pip >= 19.0 if pip prefers sdist over wheel (and there’s no Rust) • setuptools >= 42.0.0 (when using zc.buildout)
  • 49. WSGI Why Rust? Project Status Performance Demo Next steps Binary packages • manylinux2010 wheels for Python 3.6-3.9 • switched from manylinux1 after stable Rust stopped supporting the old ABI (ELF file OS ABI invalid error when loading rust shared libraries) 1.47.0 • manylinux2010 needs recent pip and setuptools versions • pip >= 19.0 if pip prefers sdist over wheel (and there’s no Rust) • setuptools >= 42.0.0 (when using zc.buildout) • wanted: MacOS
  • 50. WSGI Why Rust? Project Status Performance Demo Next steps Features • rust-cpython based Python interface (https://github.com/dgrunwald/rust-cpython) • Nonblocking IO using mio (https://github.com/tokio-rs/mio) • Nonblocking read • blocking or nonblocking write • Worker pool based on threadpool (https://docs.rs/threadpool); 1:1 threading • PasteDeploy entry point • integrates with Python logging • asynchronous logging -> no need to hold the GIL when creating the log message • logging configuration in wsgi.ini • TCP or Unix Domain sockets • supports systemd socket activation
  • 51. WSGI Why Rust? Project Status Performance Demo Next steps Performance Pierre Terre / Rabbit Hole, Monarch’s Way / CC BY-SA 2.0 • number of requests/amount of data transferred per unit of time • Testing and eventually improving it
  • 52. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring
  • 53. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive
  • 54. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking?
  • 55. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking? • limiting socket buffer sizes of a Vagrant box
  • 56. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking? • limiting socket buffer sizes of a Vagrant box • Docker?
  • 57. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking? • limiting socket buffer sizes of a Vagrant box • Docker? • Flame graphs from perf data (http://www.brendangregg.com/flamegraphs.html)
  • 58. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking? • limiting socket buffer sizes of a Vagrant box • Docker? • Flame graphs from perf data (http://www.brendangregg.com/flamegraphs.html) • .to_lower() is much more expensive than .to_ascii_uppercase()
  • 59. WSGI Why Rust? Project Status Performance Demo Next steps Approach • Static code analyis + refactoring • reminder: pyruvate started as a Hello Rust project • memory allocations are expensive • How to induce socket blocking? • limiting socket buffer sizes of a Vagrant box • Docker? • Flame graphs from perf data (http://www.brendangregg.com/flamegraphs.html) • .to_lower() is much more expensive than .to_ascii_uppercase() • load testing with siege and ab
  • 60. WSGI Why Rust? Project Status Performance Demo Next steps Performance: Design considerations • Python Global Interpreter Lock: Python code can only run when holding the GIL • Multiple worker threads need to acquire the GIL in turn • acquire GIL only for application execution • drop GIL when doing IO • more than one possible way to do this • IO event polling • abstraction: mio Poll instance • accepted connections are registered for read events with a Poll instance in the main thread • completely read requests + connection are passed to the worker pool • iterate over WSGI response chunks (needs GIL) • blocking write: loop until response is completely written • non-blocking write: • write until EAGAIN • register connection for write events with per worker Poll instance • drop GIL, stash response
  • 61. WSGI Why Rust? Project Status Performance Demo Next steps Performance: current status • Lenovo X390 and Vagrant (2 CPU, 2 G RAM, 8K write buffer size limit) • faster than waitress on a Hello world WSGI application • faster that waitress on / (looking at https://zope.readthedocs.io/en/4.x/wsgi.html#test-criteria-for- recommendations) • but slower on /Plone • more performance testing needed
  • 62. WSGI Why Rust? Project Status Performance Demo Next steps Live Demo
  • 63. WSGI Why Rust? Project Status Performance Demo Next steps Release 1.0 • Planned for end of this year • Reuse connections (keep-alive + chunked transport) • Branch on Gitlab, needs some work • MacOS support wanted • optimize pipeline • use a kcov binary package • async logging: thread ID • More testing + bugfixing
  • 64. WSGI Why Rust? Project Status Performance Demo Next steps Thanks for your attention • Thomas Schorr • info@thomasschorr.de • https://gitlab.com/tschorr/pyruvate • https://pypi.org/project/pyruvate