Handling 100 Requests per Second with Python and Django
ethicalads.io
ethicalads.io
There are frameworks that can handle over a million requests per second (simple json output) or at least several 10,000 requests per second if DB queries are performed (even though on different hardware, but just compare the scale).
https://www.techempower.com/benchmarks/#section=data-r20&hw=... https://www.techempower.com/benchmarks/#section=data-r20&hw=...
I think, if performance is a strong requirement, they were better off with another programming language.
They measured that the app spends about half its time waiting for the database.
There seems to be a whole lot of things to do before thinking of changing basic plumbing.
I would imagine that even with Python, a fully asynchronous framework would be far better at requests-per-second than Django, but would require sacrificing features, since nothing async is yet at feature parity.
My first instinct is that the number of requests seems really low, but I have no idea about the complexity of each request. To me that is kind of a crucial information to actually evaluate anything in the blog post.
I'd be curious to see if there is a meaningful gain from that approach, if anyone has done the transition before.
The number of requests still feels slow, and it isn't clear to me from the blog post whether that is DB limited or CPU limited on the application servers. Even with writes on each access Postgres should still be bored at that kind of load.
I think people seeing performance posts are used to people pushing huge numbers. Our intent here was to show that using standard off the shelf tools with a tiny bit of architecting, you can hit huge performance numbers at a reasonable cost. We have lots of various ways to shave performance, but we're pretty sure we could scale 2-3x with the same stack without a ton of work.
As our ad network grows though, everything has to grow pretty linearly (writes, reads, requests, etc.) and I hope our approach will continue to work well even with double or triple these numbers.
Connection setup/tear-down is cheap in MySQL but expensive in Postgres.
I think there must be some misconfiguration there. otherwise, the throughout should not be that low.
If possible, the author should setup a demo (contrived query, but similar to production scenario). From there, others can give valid suggestion or improve the code and configure.
(enjoyed the post, and I like your philosophy of using simple widely available tools; I'm hopeful that any changes you're able to provide back will have a kind of community-benefit flywheel effect)
But in this case the interpreter speed is largely irrelevant. This is a complex project and more than half the response time is spent waiting for the database (which is C++, not that it matters either)
[1]: https://www.techempower.com/benchmarks/#section=data-r20&hw=...
100/s is slow
I’d be curious to hear more about this. Was is just degraded performance or something else?
Generally we've found that having basic control over the hosting infrastructure is important. We still depend on Azure's LB's and other infra for keeping things available, but having the actual instances our code are running on accessible makes a lot of things easier.
less than $100/mo buys you an absolute beast of a VPS at some hosting provider that could alone handle way more than that.
We got some better performance for an internal service than Gunicorn after trying different gunicorn configurations to improve the performance of our workloads. We now mostly run (read depend) one instance of that service instead of 3 like we used to before.
[1] https://arunrocks.com/a-guide-to-asgi-in-django-30-and-its-p...
So hopefully I'm not that totally rude person, no-shade intended pointing out that if for some random reason you haven't seen ClickHouse you should check it out.
Solves problems that I parsed from your blog post and originally built for that use case.
100 recs/s for an ad network is super duper mega tiny so I hope you're successful and get bigger!
What we have considered is not doing any synchronous writes and just queuing it up and handling it async. There's definitely some questions about whether our current approach will scale 10x but it should be fine for the next 2-3x.
Just to shed a bit more light, we break things up into figuring out which ad to show and then handling when that ad is actually seen. The second part is mostly async already but the first part is the harder part. You want to choose the best ad for the content, the geographic targeting needs to match, and the ad campaign has to have budget left on the hour/day/total. If we only checked the budget every 5 minutes, that would be a problem. At some point, multiple servers need to know that there's still budget on a campaign and this requires some amount of synchronization.
This is a common pattern, however. The easiest thing to set up is to do a customer database query for every request, while the far more efficient option, in many, many cases, is to cache the 1000 most-likely queries and serve up static or pre-rendered data. Not cache like one update per day, but perhaps one update per minute. Only you and your team can decide whether it would cost more to serve up a few free ads (over a customer's budget) because the cache was a minute or two old, vs doubling/tripling your infrastructure costs in order to make the system more precise. Sounds like you've got a good roadmap for making that decision.
Just read the article...
I’ve been wanting to use Rust on the web.