Posts Marcados wsgid
It’s always important to know how your web app is performing and there are many ways to do this. One such way is measuring memory consumption, for example. This blog post will explore how you can measure response time on your live application.
This feature works in a very simple way. Wsgid gives you the opportunity to run external code inside the regular request/response flow. Wsgid defines two distinct interfaces: IPreRequestFilter and IPostRequestFilter. By implementing any of these interfaces you will have your code called on every request.
Since we are injecting external code into the execution flow of our application, wsgid must ensure that a failing filter does not crash a successful request. So unless you call sys.exit(0) or crash the python interpreter (believe me, it happens!) all requests should complete as usual.
This interface has just one method (code here):
def IPreRequestFilter(plugnplay.Interface): def process(self, m2message, environ): pass
The m2message parameter is an instance of wsgid.core.Message. This is the parsed mongrel2 message. The environ is the WSGI Environ, as described by the PEP-333 specification.
Your code can modify the environ freely. This modified environ will be passed to the running WSGI app.
This interface has two methods (code here):
def IPostRequestFilter(plugnplay.Interface): def process(self, m2message, status, headers, body): pass def exception(self, m2message, e): pass
Since this filter is called after the WSGI app has ran, the filter receives all values returned by it. These values are are the raw values as defined by PEP-333. The exception method is called when the WSGI app call fails for any reason (usually an unhandled exception). From the wsgid perspective, even if the application returns an HTTP 500 it will be considered a successful run. If you want to detect error HTTP responses you should inspect the status parameter, received by the process method.
Important note: If the WSGI app call fails, just the exception method will be called. Does not make sense to call the process method since the WSGI app did not return any value.
The wsgid source-code includes two simple examples of request filters. The first is the WorkerPidFilter. This just adds an header to the response containing the PID of the Wsgid worker that ran the WSGI app. The code is very simple:
class WorkerPidFilter(Plugin): ''' Simple fillter that adds one more response header containing the pid of the Wsgid workers that was running the WSGI application ''' implements = [IPostRequestFilter, ] def process(self, message, status, headers, body): return (status, headers + [('X-Worker', os.getpid())], body) def exception(self, message, e): pass
Another example is a filter that calculates the total elapsed time of your request. You can take a look at the code here.
A more real world example
These example filters works very well for simple cases. When it comes to real world production application we may have to do it a little different. First of all, when writing a request filter we must consider the time the filter will take to run. The less it takes, the less it interferes in the request response time.
We could, for example, save the response times in a database. But we know that this wouldn’t be a great idea in the end! So the idea here is to save the information to later processing. We could save it into the logs. You can do this by just importing wsgid.core.log. This is a stantard Python Logger and it writes the information into your app main log file (the file is located inside your wsgidapp folder at logs/wsgid.log). But by doing this we would have to keep parsing the application log, not a very good idea either.
Another idea is to use a queue server, such as RabbitMQ. This way we can keep the filter execution time very low and we will have all messages saved to be processes later, without the need to parse any log file.
Attached to the RabbitMQ server we would have a separated process, reading all the messages and storing them anywhere, in a database, in a Graphite server or any other place.
The idea behind this implementation
The idea is very simples. Since your filter receives the parsed mongrel2 message, you have access to the connection ID of the client making the current request. This could be your primary key when measuring the values. In your PreRequestFilter you can send to the queue server, along with the connection ID, all the HTTP headers, the current time and any other information you want.
When the PostRequestFilter runs, you send the connection ID, the status returned by the WSGI app, the response headers and the current time again. With this information you can not only calculate the response time (per request URI, if you like) but you can calculate all sorts of information about your requests. User-Agent percentage, Content-Length average size, the most/less visited URI, HTTP status distribution (how many 200’s, 400’s, 500’s is your WSGI app returning) just to cite a few.
I will leave this implementation for a future post as I pretend to calculate all this information for the wsgid (http://wsgid.com) website and for my personal website (http://daltonmatos.com). This will be perfectly possible since they both run with wsgid.
Thanks for the reading and I hope you enjoyed!
Wsgid is a generic handler for the mongrel2 web server. It acts as a bridge between WSGI and mongrel2 and makes it possible to run any WSGI python application using mongrel2 as the front end. To know more about both projects visit their official websites at: http://wsgid.com and http://mongrel2.org
In this post we will see how to configure mongrel2 and wsgid so your application will be able to handle arbitrary sized requests very easily and with a low memory usage.
The problem of receiving big requests is that depending on how your front end server deals with it, you can easily become out of resources and in a worst case scenario your application can stop responding for a while. If your application exposes any POST endpoint, then you should be prepared to handle some big requests along the way.
The big picture
Mongrel2 has a very clever way to handle big requests without consuming all your server’s resources, in fact without consuming almost nothing, only bandwidth. Basically what it does is to dump the entire request to disk, using almost none additional memory. Here is how it works:
When the request comes in, mongrel2 sends a special message to the back-end handler containing only the original headers. This message notifies the start of this request. It’s up to the handler to accept or deny it. To accept the request, your handler just do nothing. If you want to deny the request, your handler must send a 0-length message back to mongrel2. Due to mongrel2 async model, you can send this deny message at any time, does not need to be imediatelly after receiving the request start message.
If you happen to be using wsgid (I hope you are!) this happens without your WSGI application ever knowing. All your application will see (if at all) is the wsgi.input attribute of the WSGI environ (if you happen to write a WSGI framework) or just request.POST (or something similar depending on what framework you’re using). It’s all transparent.
After the request is completely dumped, mongrel2 sends another message notifying the end of the upload and that’s when wsgid will actually call your application. During all the upload process, your application does not even know that a new request has come and was being handled.
All this happens while mongrel2 is already dumping the request content to disk. If your handler happen to deny the request, mongrel2 will close the connection and remove the temporary file. To know more about how mongrel2 notifies the handlers, you can read the on-line manual: http://mongrel2.org/static/mongrel2-manual.html.
Configuring mongrel2 to handle big requests
The configuration of the server is extremely simple. All you have to do is tell it where to dump any big request that may arrive. You may ask: How big a request must be to be dumped to disk? The truth is that you decide this and tell mongrel2 about it.
To tell it where to dump the request you must set the option upload.temp_store to the correct path. This path must include the filename template. An example could be: /uploads/m2.XXXXXX. This must be a mkstemp(3) compatible template. See the manpage for more details.
The size of the request is set with the limits.content_length. This sets the biggest request mongrel2 will handle without dumping to disk. This size is set in bytes.
Configuring wsgid to understand what mongrel2 is saying
Since mongrel is saving requests on disk wsgid must be able to open these files and pass its contents to the application being run. It’s important to note that the path chosen on the upload.temp_store is always relative to where your mongrel2 is chrooted, so somehow we must tell wsgid where this is.
Fortunately this new release of wsgid comes with a new command line option: --mongrel2-chroot. You just have to pass this to your wsgid instance to be able to handle big requests.
Alternatively you can add this options to your wsgid.json configuration file if you want. This can be complished with a simple command:
$ wsgid config --app-path=/path/to/your/wsgid-app --mongrel2-chroot=/path/to/mongrel2/chroot
This will save this new option on your config file. Just restart your wsgid instance and it will re-read the config file.
Working without knowing where mongrel2 is chrooted
There is another way to handle these big requests. In this approach your don’t need to pass --mongrel2-chroot to all your wsgid instances. The trick here is to mount the same device on many different places. The easiest way to do this is to have mongrel2’s temp_store in a separated partition (or logical volume if you are using LVM). Let’s see an example:
Suppose we have mongrel2 chrooted at /var/mongrel2/ and configured this way:
upload.temp_store = '/uploads/m2.XXXXXX'
Since mongrel2 assumes /uploads is relative to its chroot we must mount this device ate the right place.
# mount /dev/vg01/uploads /var/mongrel2/uploads
Now our logical volume is mounted at /var/mongrel2/uploads. There is one last setp so we can start serving big requests with wsgid. When mongrel2 sends the upload started message to wsgid, which contains the path of the temporary file, the path received by wsgid is the same we put on mongrel2’s config. So wsgid will try to read /uploads/m2.384Tdg (for example) and obviously will fail. So we need a way to make /uploas/ also available to wsgid (that normally is not chrooted anywhere) and the trick to do this is to re-mount the same device at a different place. And this is how we do it:
# mount /dev/vg01/uploads /uploads
So now we have the same device mongrel2 writes the temporary files available to all wsgid processes that need to read them. Remember that mongrel2 does not remove any of these file because obviously it does not know when your app is done. So it’s up to you to clean them.
If your /upload directory is part of a bigger volume or is not on a separated one, you still can accomplish this multi-mount approach. Just use the --bind. This way you can re-mount any directory at another place. Read the mount man page for more details.
This is another cool mongrel2 feature that the latest wsgid release (0.5.0) already supports. So now wsgid supports all major features mongrel2 provides and is starting to be more mature, trying to find its way into a production-ready tool.
Thanks for reading and enjoy!
Some time ago when people talked about webapp deployment they were probably talking about the LAMP stack. Since the appearance of the nginx webserver this has changed quite a bit. In this post you will know another stack, that does not use neither apache nor nginx but that is equally interesting and quite scalable too. We will be talking about mongrel2 for the frontend and wsgid for the backend worker processes.
Hoje é um dia muito importante. Finalmente depois de muito tempo consegui lançar meu próprio site. Já tinha comprado o domínio há bastante tempo mas não tinha ainda parado pra escrever os textos e o código do site.
O site é uma aplicação django e roda com o auxílio de um projeo meu já citado aqui no blog, o wsgid. Por enquanto o blog continua aqui no wordpress.com mas pretendo migrá-lo pra lá, pois assim terei tudo centralizado. Ainda tenho que encontrar uma blog engine para que possa migrar o blog.
Bem, é isso aí! Vai lá e dá uma olhada: http://daltonmatos.com