<html style="direction: ltr;">
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
<style type="text/css">body p { margin-bottom: 0cm; margin-top: 0pt; } </style>
</head>
<body style="direction: ltr;"
bidimailui-detected-decoding-type="latin-charset" bgcolor="#FFFFFF"
text="#000000">
If you use either NginX or Apache's WSGi modules, you get the
following crucial features: management of the CPython processes,
support for threading (provides limited concurrency benefits but
does reduce RAM use), and multiplexing of the port. If you want to
do anything similar with Tornado, you're on your own: you have to
run several Tornado processes yourself, manage them somehow (what do
you do when they get stuck? how do you find out?), each on its port,
and introduce a load balancer in front for all ports. This doesn't
seem very scalable or easy to maintain to me: just adding a "worker"
process involves allocating a port, reconfiguring your load balancer
(and deploying it), etc. In terms of programming, sure, Tornado is
easy, but in terms of operations I think it's a nightmare. One man's
bloat is another man's necessary feature.<br>
<br>
I didn't mean to sound so negative about Tornado! I appreciate its
approach a lot. I just think it's overused in the web world, often
chosen for the wrong reasons. If I have any criticism about Tornado
is that it has virtually no support for threading -- which is really
why the codebase is so small, coherent and easy to debug. That ends
up being a great fit for the Python world, which generally abhors
threads (for the right reasons, in context).<br>
<br>
The real comparison, in my view, is not Tornado vs. Django (Django
over what server?), but Tornado vs. other lightweight async servers,
such as Node.js.<br>
<br>
If I were to write an async Internet application right now from
scratch, and was not limited to the Python world, I would definitely
look towards something like Erlang. You get the advantages of
threading while still maintaining code coherence and debuggability.<br>
<br>
<br>
<div class="moz-cite-prefix">On 10/11/2012 04:08 PM, Japhy Bartlett
wrote:<br>
</div>
<blockquote
cite="mid:CANTsVHKR+7Q6=MDBJurqphe3q5q1nv6-P8n7nLjYtz+HC_tg9A@mail.gmail.com"
type="cite">As far as tornado being.. "quite bad ... for REST"...
I guess I'll just say that I've been paid to write REST services
using both tornado and django, and the tornado systems were not
only easier to write, maintain and scale.
<div>
<br>
</div>
<div>It also happens to win a lot of benchmarks,
and "over-simplification" is another man's lack of bloat. The
underlying code is quite nice, and a human being can read it.</div>
<div><br>
</div>
<div>
No.. it is not meant to serve static files, but it's certainly
capable ("absolutely miserably"?), and that is a *really* weird
criticism to make of a python web server.</div>
<div><br>
</div>
<div>"fast" in the context of tornado actually means.. fast. Like
requests, natively asynchronous *or* synchronous through WSGI,
tend to get served in fewer milliseconds than most other python
frameworks.</div>
<div><br>
</div>
<div><br>
</div>
<div>I think it's very underrated, and I hate to see people saying
bad things about it. Maybe it's worth a talk in the next month
or two?</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
<div class="gmail_quote">On Thu, Oct 11, 2012 at 3:00 PM, Tal
Liron <span dir="ltr"><<a moz-do-not-send="true"
href="mailto:tal.liron@threecrickets.com" target="_blank">tal.liron@threecrickets.com</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="direction:ltr" bgcolor="#FFFFFF" text="#000000">
<div class="im"> On 10/11/2012 01:59 PM, Jordan Bettis
wrote:<br>
<br>
<blockquote style="direction:rtl" type="cite">
<pre style="direction:ltr">Of course you can have a dynamic worker pool. That's the way apache
works. Given that python has a fairly "big boned" runtime, there's a
substantial cost there, as well as doing other things like making DB
connections for the new workers. And anyway it still only partially
solves the problem. You're still going to run out of memory or file
descriptors or something eventually. Compare Apache's behavior in the
face of a Slow DOS attack compared to that of an asynchronous server
like nginx.
</pre>
</blockquote>
</div>
My life mission is to dispel this myth (especially because
I used to believe it myself).<br>
<br>
Let's get rid of one myth first: a long time ago, it was
the case that Linux's single-threaded epoll service was
somehow more scalable than more simply using threads to
read the socket, because thread switching was painful.
This stopped being true a long time ago: the "fastest" web
servers (lighttpd) do not use epoll. And, in any case,
whether you have a single thread <i>accepting</i> the
connections or not, you'll want a pool of thread (or
"workers" of some kind) generating content for these
connections. I'm saying this to point out that there's
some confusion as in what counts as "async": so let's just
get the idea that it has to do with <i>accepting</i> the
connections out of the way.<br>
<br>
In a true "async" server, the server calls you to tells
you, look, there's this new client connection here (the
server maintains a pool of <i>information</i> -- not
threads -- about each client). You can then call the
server at your convenience when you have data to send to
the client, or ask it to close the connection. (Again,
let's forget how the server actually implements this
internally; it has nothing to do with asynchronicity in
the sense we are talking about here.) The quality of an
async server has a lot to do with what kind of information
it keeps.<br>
<br>
Think of it for not only in terms of the server but also
in terms of your application. At some point the server
turns things over to your code. So, what is your
application doing?<br>
<br>
For a typical "web" application (REST), each client
connection returns an entity of some kind. So, you really
need to process each client quickly in turn. While it's
true that NginX or Tornado or Node.js can accept a great
many connections (it's just a small record of information
they keep for each, not a thread), if there's no thread
(or "worker") ready at your application's end to generate
an entity, then these connections will queue up and your
clients will consider your site "down." Async or sync
server makes no difference: your app is sync because it
needs to handle one request at a time.<br>
<br>
So, when does the asynchronous approach make a real
difference? Say your application is not typical REST, but
instead you are streaming video. There's no single entity
that the clients are waiting for. So, what you can do
instead is have each of your threads divide their time
between the open connections. The more load you have, the
less data you want to send per client when their turn
comes (or you can give paying clients more time per
turn...) A good async server will provide you with
statistics about load to help you do the right thing and
degrade gracefully. The API approach Garret mentioned for
WSGi is typical: your app can just return a null or
otherwise tell the server: "Don't return anything to the
client right now; in fact, don't you worry about it all,
I'll handle the data my own way and close the connection."
Yes, such an approach enables async, but I wouldn't call
it a good approach. The architectural burden becomes
yours. If you're working with Tornado, for example, you're
much better off working with its native API than using
WSGi. Your app won't be portable, but then async rarely
is.<br>
<br>
There's also a kinda middle ground between these extremes:
serving files. Text files are usually too small to make a
difference, but what if you are serving a lot of images?
They're big, and sending them to slow clients can hold
things up if you are using the typical "web" approach of
sending them everything then need immediately. So, instead
you can kinda stream the file to them, chunk by chunk, and
if you do this well you can degrade gracefully. It's
async, but with more determinability (because you know the
size of the files), so it's a use case that has been
heavily optimized. For example, individual chunks can be
cached (mmap files ftw). But this has nothing to do with
whether the server presents your app with a sync or async
interface. As I stated, some of the best file servers are
synchronous servers. They provide only a traditional REST
API for your apps, but internally they do semi-streaming
for files very well.<br>
<br>
(And actually there's another myth here: that somehow file
servers that degrade more gracefully will help you scale.
Well, do you ever really want any individual server of
yours to get to the point where it starts to degrade
performance in any way, let alone degrade gracefully?
These days, Google and other search indexes will penalize
you for degradation. The trick is to scale horizontally
with cheap VMs, so you <i>never</i> hit that point in the
graph where things start heading south. You don't care if
you're heading south fast or slowly. So, at the high scale
it makes almost no difference if you choose Apache or
NginX or lighttpd for your REST apps. It will matter only
if you're limited to one or two servers in your cluster.)<br>
<br>
As an opposite example, let's consider Tornado. Yes, it
can serve files, but it does so absolutely miserably. Its
devs make it clear that it was never their priority to
compete with mature web file servers. Instead, the goal
was to create a good, straightforward and (to be honest)
overly simple async server. Tornado is great if you want
to write a streaming server without bells and whistles.
But it's quite bad, partly due to its over-simplification,
for traditional REST. If you're picking Tornado for your
web application because it's "async" and "fast" you might
not be understanding what these terms mean in this
context. Find a mature sync server and make sure <i>your</i>
app, on your end, never holds up a thread for too long.<br>
<br>
Over and out.<span class="HOEnZb"><font color="#888888"><br>
<br>
-Tl<br>
</font></span></div>
<br>
_______________________________________________<br>
Chicago mailing list<br>
<a moz-do-not-send="true" href="mailto:Chicago@python.org">Chicago@python.org</a><br>
<a moz-do-not-send="true"
href="http://mail.python.org/mailman/listinfo/chicago"
target="_blank">http://mail.python.org/mailman/listinfo/chicago</a><br>
<br>
</blockquote>
</div>
<br>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
Chicago mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Chicago@python.org">Chicago@python.org</a>
<a class="moz-txt-link-freetext" href="http://mail.python.org/mailman/listinfo/chicago">http://mail.python.org/mailman/listinfo/chicago</a>
</pre>
</blockquote>
<br>
</body>
</html>