SlideShare uma empresa Scribd logo
1 de 64
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

API Design first with Swagger
API Design first with SwaggerAPI Design first with Swagger
API Design first with SwaggerTony Tam
 
Rest API with Swagger and NodeJS
Rest API with Swagger and NodeJSRest API with Swagger and NodeJS
Rest API with Swagger and NodeJSLuigi 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 SwaggerJeremy Whitlock
 
Designing APIs with OpenAPI Spec
Designing APIs with OpenAPI SpecDesigning APIs with OpenAPI Spec
Designing APIs with OpenAPI SpecAdam 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.0Pece Nikolovski
 
Swagger - make your API accessible
Swagger - make your API accessibleSwagger - make your API accessible
Swagger - make your API accessibleVictor Trakhtenberg
 
Swagger 2.0: Latest and Greatest
Swagger 2.0: Latest and GreatestSwagger 2.0: Latest and Greatest
Swagger 2.0: Latest and GreatestLaunchAny
 
Swagger for-your-api
Swagger for-your-apiSwagger for-your-api
Swagger for-your-apiTony 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/OpenAPIScott Triglia
 
Introducing Swagger
Introducing SwaggerIntroducing Swagger
Introducing SwaggerTony 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 toolsSwagger 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 SwaggerSalesforce Developers
 
Developing Faster with Swagger
Developing Faster with SwaggerDeveloping Faster with Swagger
Developing Faster with SwaggerTony Tam
 
Design Driven API Development
Design Driven API DevelopmentDesign Driven API Development
Design Driven API DevelopmentSokichi Fujita
 
Streamlining API with Swagger.io
Streamlining API with Swagger.ioStreamlining API with Swagger.io
Streamlining API with Swagger.ioVictor 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 classLibbySchulze
 
Quick run in with Swagger
Quick run in with SwaggerQuick run in with Swagger
Quick run in with SwaggerMesh 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
 

Mais procurados (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)
 

Semelhante a 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 2019Viktor 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 2008Ivo Jansch
 
Northeast PHP - High Performance PHP
Northeast PHP - High Performance PHPNortheast PHP - High Performance PHP
Northeast PHP - High Performance PHPJonathan 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 BlackfireMarko Mitranić
 
Concourse Workshop
Concourse WorkshopConcourse Workshop
Concourse WorkshopVMware 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 PHPSeravo
 
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 Example360|Conferences
 
web2py:Web development like a boss
web2py:Web development like a bossweb2py:Web development like a boss
web2py:Web development like a bossFrancisco 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 ScalePatrick 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 NginXbilldigman
 
JavaOne 2014: Java vs JavaScript
JavaOne 2014:   Java vs JavaScriptJavaOne 2014:   Java vs JavaScript
JavaOne 2014: Java vs JavaScriptChris Bailey
 

Semelhante a 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
 

Mais de PloneFoundation

Form Block / Formbuilder
Form Block / FormbuilderForm Block / Formbuilder
Form Block / FormbuilderPloneFoundation
 
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 PlonePloneFoundation
 
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 LTSPloneFoundation
 
Modernize Plone's Classic UI
Modernize Plone's Classic UIModernize Plone's Classic UI
Modernize Plone's Classic UIPloneFoundation
 
Volto: A Journey towards Personalization
Volto: A Journey towards PersonalizationVolto: A Journey towards Personalization
Volto: A Journey towards PersonalizationPloneFoundation
 
Bundle Splitting in Volto
Bundle Splitting in VoltoBundle Splitting in Volto
Bundle Splitting in VoltoPloneFoundation
 
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
 
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 wildPloneFoundation
 

Mais de 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
 

Último

Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 

Último (20)

Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 

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