Sanic – Python 3.5+ web server that's written to go fast
github.com
github.com
In the end, my implementation was nowhere near nginx. I even ran it under PyPy and it fared no better. Then I realized the oxymoronic nature of writing an optimized web server in Python.
I don't see how writing an optimzed web server in Python becomes oxymoronic -- it can still be the fastest performing python server, and have a valid use case for those that want to work in Python.
I did extensive benchmarking until there were no more hot spots, didn't help. Dropping into C or Cython was a non-goal. For dev an embedded Python web server is convenient but it doesn't have to be fast. When it comes to performance, it always makes more sense to use a native-code web server in production.
Why not Cython?
I still think that a Python server can have it's use, and there's nothing wrong in trying to make it as fast as posible.
I'm curious, why were C/Cython non-goals?
It's great to see an order of magnitude leap on the python side - but on the face of it I'm not sure the leap really is enough to enable a different class of services in python? Perhaps I'm being too pessimistic - I know I'd be happy to be able to "ignore" node, and only consider eg: Python for most things and go for some things. Just to limit my tech stack.
But where does nginx with lua fit - is it another order of magnitude above go for dynamic content?
Performance is not a magical inherent property of a language-and-webserver combination, and will vary wildly with the application. In my experience practical performance has much more to do with architecture, algorithms and "the other bunch that makes things efficient" -- not so much with a language.
It's also only one facet. And usually not a very important one, either.
well it is. however most performance characteristics of a language are well understood. mostly python/ruby is slower than a lot of other languages.
> practical performance has much more to do with architecture
well sort of not every case does well with these kinds of languages.
however in most cases it's just fine to use them.
my company changed one product from python to scala. everything was slower in python, however in 90% of our use case that didn't even matter. however we were thread and calculation (i.e. shuffling/changing large lists/maps in memory) where python was just slow. I guess we could've written a library for these kind of transformations in C. however another problem was also PDF generation, which was really really slow in python (for bigger pdf's, slower one's we just fine). we are happy to use scala, but I didn't found python bad or weak. you are pretty fast and the tooling is just amazing. also the ORM's in python are superior to everything i've seen on the JVM world. (Django ORM and SQLAlchemy) I guess they are even the best ORM's out there. if I would be developing more towards a cloud architecture I would probably use python again. you could just do more if you have room for a "infinite" amount of servers
still python is a really great and well designed language. I would everybody encourage to look into it.
This was tweaking Nagle, using edge triggered epoll, using sendfile(). Not just Python-optimizations.
How could it be?
(Eg, nearly static configuration, very few flow or looping constructs, unless you explicitly use something optional like Lua)
I've actually at one point considered writing some light web apps as nginx modules, in Lua. In the end though, it's usually enough to pluck the lowest hanging fruit, which (as a rule is) caching... Cache as much as possible (including when you have a python web app behind nginx).
If you wanted to create a static files server, Python is just a bad choice.
Python is a good choice if you need custom, complex logic or access to non-file data stores. And if you need that, Nginx isn't a choice (yes you can use modules -- eventually you recreate the same problem).
So yes, don't try to replace Ngnix or HAProxy or PostgreSQL or such with Python. But the gaps not covered are good to be written in Python. And it's nice if they're fast.
How does your benchmark compare against GO, Elixir and Node?
137% as many req/sec as Node
83% as many req/sec as Go
I'm it sure where this goes when you factor in async IO, but my guess is that Node gains a little and Go loses a lot.When you add asyncpg to the mix my money is on Sanic winning by a long shot, in a benchmark that includes e.g., 3 queries and returning the results as JSON.
nginx (openresty, really) has beat both of them them in all "normal" (ie. not limited by DB access, etc) usage conditions that I have tested.
I wonder if this is a convergence on a local maximum for writing web apps, or if it's just a situation where the most popular ones did it this way, so everyone does it this way. Not that it matters too much, in the general case. The route and app setup plumbing is a small part of most applications, so it's rarely going to be ruinous if you spend an extra hour or two getting it working right. But, since I've been evaluating a bunch of different ways to build web app backends lately, I've just noticed how similar they all are, no matter what language you choose. Most of the ones I've been looking at are asynchronous, so this also has that similarity to most of the others.
While one could argue that it's obvious that they would look the same...but, web development didn't always look this way. The first 10-15 years of web application development I did looked very different, in fact (CGI or mod_perl or PHP, which has some quite different conventions).
It came to me after playing with Rails for several years and then taking a look at Laravel, which is clearly Rails inspired in many ways but made some different decisions in the naming of a few things that are present in both frameworks.
It's more like a global minimum.
With many of these micro-frameworks, you're observing what is near the minimum API required for mapping a web request to a single function.
> you're observing what is near the minimum API required for mapping a web request to a single function.
I mean, sure, it is functionality needs to be there across the board...but, it could be named differently or used differently. An "app" object is seemingly universal everywhere, a run method is super common; router configuration is very similar across several frameworks, though in this and Flask it is a decorator while it's a method in Express or Mojolicious, but still look a lot alike.
Anyway, I just think it's nice. It means that when I poke around in projects I've never seen before in frameworks I'm not familiar with, it isn't terribly difficult to get up to speed on at least the basics of what it's doing and how to change minor things about it. Building a big project from scratch still requires some time to get up to speed, but I think it's likely to provide developers more mobility across projects and companies, which is a good thing. Standards are nice, even when they're de facto and just came about because "everybody's doing it".
I haven't had a chance to tinker with the async elements of this, but I'm betting it's similarly transferable knowledge across all of the frameworks that are async.
Anyway, none of this is really an amazing revelation, I guess for people who've been working on modern web apps for a while. But, I'm catching up from doing it in a variety of old ways (for examples of doing it very different ways, just take a look at some Drupal or WordPress or Mediawiki or old school Perl web application code...these projects are still very heavily used and have thousands of developers working on them, and they look literally nothing like the model we're talking about, and often don't really even look that much like each other). My point is that there's been convergence, and it really hasn't always been obvious how it should be done. Knowledge of Drupal, WordPress, or Mediawiki, does not readily translate to anything else. I have to get back up to speed every time I dive into any of them (and I still do have to do so now and then). There are tons of projects that are like that.
Also, interop is getting a lot better. I don't feel like it would be crazy to stick a Mojolicious app alongside an Express app, working with the same data sources and even talking to the same web/mobile frontends, for example. Making those old projects interact nicely with others is often an exercise in frustration.
One question: Why default to ujson? I understand that if you're always dealing with small, simple json objects it's quite fast and safe. But with larger json payloads, its performance and compatibility start to break down. I haven't touched it in the last 8 months, but I had to switch to Python's built-in json module (which is quite fast in 3.5) for compatibility when serializing and deserializing large json objects.
But the main advantage - that you're still using uwsgi as a "unified application server" of sorts - persists, which was the main point for us (Django, Flask, Tornado on uWSGI). This simplified deployment and administration quite a bit.
Re. topic: It would be really interesting to see it compared to Tornado.
I know there are people who are stuck on old versions, but the community has recognised how much damage this dispute was doing to Python's image. They know they'll have official Cpython support to 2020, so it's a non-issue until then.
Oh and Ubuntu 16.04 defaulting to 3.5 helped too.
PHP is such a bad language hue hue
Java. AbstractCommentPostingRequestSerializerInterface hue hue
Python. You know Python 3 right? hue hue hue
command.exe windows suxxx hue hue
... countless others with varying stupidityDisclaimer: I have nothing to do with this project.
[0] https://github.com/channelcat/sanic/blob/master/docs/getting...
The hard dependency on uvloop looks weird. It's just a pluggable loop for asyncio, anyone can switch to it in two lines of code, no reason to depend on something that's a native extension.
Also why not just improve aiohttp's performance…
Have you read aiohttp's code? there have been some discussions about improving its performance, there is basically no immediate bottleneck, the whole thing just performs poorly. I hate to say it but sometimes it's just better to start from scratch.
But maybe in near future Python will grow significantly, who knows.
I want to trace this profound moment in WebDev history. Amazing.
See also, Gil Tene https://www.youtube.com/watch?v=lJ8ydIuPFeU
A nice overview, http://bravenewgeek.com/everything-you-know-about-latency-is...
See also, http://highscalability.com/blog/2015/10/5/your-load-generato...