Tornado advertises itself as “a relatively simple, non-blocking web server framework” and was designed to solve the C10k problem. However, looking at their database wrapper, which wraps MySQLdb, I came across the following piece of code:
def _execute(self, cursor, query, parameters): try: return cursor.execute(query, parameters) except OperationalError: logging.error("Error connecting to MySQL on %s", self.host) self.close() raise
As far as I know calls to the MySQLdb, which is built on top of
libmysqlclient, are blocking.
Am I right in thinking that a long-running query would render the entire Tornado server unresponsive until it finishes or is there magic on the code?
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Bret Taylor, one of the original authors, writes:
We experimented with different async DB approaches, but settled on
synchronous at FriendFeed because generally if our DB queries were
backlogging our requests, our backends couldn’t scale to the load
anyway. Things that were slow enough were abstracted to separate
backend services which we fetched asynchronously via the async HTTP
It’s true that Tornado doesn’t include a non-blocking database layer; in fact the database layer is not integral part of the Tornado framework at all, as opposed to e.g. Django’s ORM. Yes, Tornado ships with blocking MySQL wrapper because that’s what FriendFeed happened to use, but it’s more an external library than core functionality. I’m pretty sure most people are using something else for database access.
Yes, absent other measures, the server will wait for the query to finish executing. That does not mean Tornado is not a non-blocking web server.
A “non-blocking web server” doesn’t block on network I/O (and may have some provision for disk I/O if it does static file serving). That does not mean you get instant, causality-violating instruction execution in your application.
Doing a database call takes time, just like reading files, formatting strings, processing templates, etc. takes time. Doing any of these things in the same thread as the server’s main event loop will prevent the loop from moving on until you’re done.
Tornado is nonblocking,but just limited to some IO operation like read or write to a socket file.
if you want everything in your code nonblocking,you have to design by yourself.but if your code is computation intensively, then nonblocking is meaningless for you. this situation you might use multi-process.
remember one thing nonblocking just mean the server send/receive date won’t blocking. If you can’t make your code nonblocking,then your whole application is someway blocking.
Yes; this is not a fully non-blocking web server at all.
A non-blocking webserver doesn’t block, using non-blocking APIs for file I/O, database access, and so on, to ensure that one request that has to wait for something to finish doesn’t prevent other requests from being processed. This applies to everything that might block the server, including database access.
There’s nothing as silly as “causality violation” in having non-blocking database access; it makes perfect sense to run a non-blocking query related to one request, and to process other requests while that’s still running. In practice, this will usually mean making multiple connections to the database backend.
Note that if you’re trying to run ten thousand concurrent requests, be careful: most database backends can’t cope with this. If you have more than a few dozen database requests to run in parallel, you probably want something like a connection pooler, to allow the web server to make lots of database connections without swamping the backend. This will cause requests to block, waiting in a queue to get database access, but doing it this way means it’s not blocking the whole server–just the requests that need the database.