uWSGI 1.9.12
Changelog [20130605]
Bugfixes
- offloading cache writes will return the correct status code and not 202
- you can now control the path of temporary files setting the TMPDIR environment variable (this fixes an old issue for users without control over /tmp)
- fixed a compilation error on amqp imperial monitor
- cron commands are correctly escaped when reported in the stats server
- fixed fastcgi parser corner-case bug with big uploads
- fixed support for newest cygwin
New Features
Offloading responses
Take the following WSGI app:
- def application(environ, start_response):
- start_response('200 OK', [('Content-Type', 'text/plain')])
- return ['u' * 100000000]
it will generate about 100megs of data. 98% of the time the worker spent on the request was on the data transfer. As the whole responseis followed by the end of the request we can offload the data write to a thread and free the worker suddenly (so it will be able to handle a new request).
100megs are a huge value, but even 1MB can cause a dozen of poll()/write() syscalls that blocks your worker for a bunch of milliseconds
Thanks to the ‘memory offload’ facility added in 1.9.11 implementing it has been very easy.
The offloading happens via the uWSGI Transformations
- [uwsgi]
- socket = :3031
- wsgi-file = myapp.py
- ; offload all of the application writes
- route-run = offload:
By default the response is buffered to memory until it reaches 1MB size. After that it will be buffered to disk and the offload enginewill use sendfile().
You can set the limit (in bytes) after disk buffering passing an argument to the offload:
- [uwsgi]
- socket = :3031
- wsgi-file = myapp.py
- ; offload all of the application writes (buffer to disk after 1k)
- route-run = offload:1024
“offload” MUST BE the last transformation in the chain
- [uwsgi]
- socket = :3031
- wsgi-file = myapp.py
- ; gzip the response
- route-run = gzip:
- ; offload all of the application writes (buffer to disk after 1k)
- route-run = offload:1024
JWSGI and JVM improvements
The JVM plugin has been extended to support more objects helper (like ArrayList), while JWSGI can now be used asa low-level layer to add support for more JVM-based languages.
JRuby integration is the first attempt of such a usage. We have just releases a JWSGI to Rack adapter allowing you tun runRuby/Rack apps on top of JRUBY:
https://github.com/unbit/jwsgi-rack
A similar approach for Jython is on work
–touch-signal
A new touch option has been added allowing the rise of a uwsgi signal when a file is touched:
- [uwsgi]
- ...
- ; raise signal 17 on /tmp/foobar modifications
- touch-signal = /tmp/foobar 17
- ...
The “pipe” offload engine
A new offload engine allowing transfer from a socket to the client has been added.
it will be automatically used in the new router_memacached and router_redis plugins
memcached router improvements
You can now store responses in memcached (as you can already do with uWSGI caching)
- [uwsgi]
- ...
- route = ^/cacheme memcachedstore:addr=127.0.0.1:11211,key=${REQUEST_URI}
- route = ^/cacheme2 memcachedstore:addr=192.168.0.1:11211,key=${REQUEST_URI}foobar
- ...
obviously you can get them too
- [uwsgi]
- ...
- route-run = memcached:addr=127.0.0.1:11211,key=${REQUEST_URI}
- ...
The memcached router is now builtin in the default profiles
The new redis router
Based on the memcached router, a redis router has been added. It works in the same way:
- [uwsgi]
- ...
- route = ^/cacheme redisstore:addr=127.0.0.1:6379,key=${REQUEST_URI}
- route = ^/cacheme2 redisstore:addr=192.168.0.1:6379,key=${REQUEST_URI}foobar
- ...
… and get the values
- [uwsgi]
- ...
- route-run = redis:addr=127.0.0.1:6379,key=${REQUEST_URI}
- ...
The redis router is builtin by default
The “hash” router
this special routing action allows you to hash a string and return a value from a list (indexed with the hashed key).
Take the following list:
127.0.0.1:11211
192.168.0.1:11222
192.168.0.2:22122
192.168.0.4:11321
and a string:
/foobar
we hash the string /foobar using djb33x algorithm and we apply the modulo 4 (the size of the items list) to the result.
We get “1”, so we will get the second items in the list (we are obviously zero-indexed).
Do you recognize the pattern ?
Yes, it is the standard way to distribute items on multiple servers (memcached clients for example uses it from ages).
The hash router exposes this system allowing you to distribute items in you redis/memcached servers or to make other funny things.
This an example usage for redis:
- [uwsgi]
- ...
- ; hash the list of servers and return the value in the MYNODE var
- route = ^/cacheme_as/(.*) hash:items=127.0.0.1:11211;192.168.0.1:11222;192.168.0.2:22122;192.168.0.4:11321,key=$1,var=MYNODE
- ; log the result
- route = ^/cacheme_as/(.*) log:${MYNODE} is the choosen memcached server !!!
- ; use MYNODE as the server address
- route = ^/cacheme_as/(.*) memcached:addr=${MYNODE},key=$1
- ...
you can even choose the hashing algo from those supported in uWSGI
- [uwsgi]
- ...
- ; hash the list of servers with murmur2 and return the value in the MYNODE var
- route = ^/cacheme_as/(.*) hash:algo=murmur2,items=127.0.0.1:11211;192.168.0.1:11222;192.168.0.2:22122;192.168.0.4:11321,key=$1,var=MYNODE
- ; log the result
- route = ^/cacheme_as/(.*) log:${MYNODE} is the choosen memcached server !!!
- ; use MYNODE as the server address
- route = ^/cacheme_as/(.*) memcached:addr=${MYNODE},key=$1
- ...
the router_hash plugin is compiled-in by default
Availability
uWSGI 1.9.12 will be available starting from 20130605 at the following url