> On 20 Sep 2017, at 9:24 AM, Samuel Bancal <sam.ban...@gmail.com> wrote:
> 
> Hi,
> 
> We've experienced some high latency with a Django project using mod-wsgi in 
> daemon mode. That web service does folder management ... and has a /refresh 
> POST url that will keep the request hang until a) a change is made in the 
> folder or b) 60 seconds have passed.
> 
> With this, having a few clients ... already used the 15 threads available. 
> And any new request were waiting for a /refresh to timeout before being 
> processed.
> 
> I guess such /refresh method is not today's best practice ... and the dev 
> (me) would better look into XHR calls (which I don't know yet).
> 
> With this, I have 3 questions :
> 
> + Would XHR calls be non-consuming threads as POST do?
> + How to best size today's solution? Since all /refresh are spending their 
> time doing some DB requests followed by `time.sleep(1)` ... Can I grow the 
> number of threads to 256? Or shall I split it to something like 8 processes 
> of 32 threads? (or even above?)
> + Before that, we used mod-wsgi in embedded mode ... which never gave any 
> latency we could measure. Would it be, for such situation, better to switch 
> back to embedded mode?

The reason you wouldn't have seen an issue in embedded mode is that the limit 
on maximum number of clients supported by Apache child worker processes would 
be much higher and Apache would spawn new worker processes if need be if the 
number of concurrent requests needing to be handled did grow, up to the limit.

The risk in using embedded mode is the amount of memory used by Apache and some 
performance issues around how Apache dynamically adjusts the number of 
processes. The overhead of always starting up new processes with a full Python 
interpreter in it and reloading your code is expensive. Unfortunately the 
Apache algorithm suffers when doing this with heavyweight Python applications.

Switching to XHR calls will not help unless you are also re-designing things to 
periodically poll instead of wait, something which could be done without using 
XHR anyway. Depending on number of requests, polling can cause other issues as 
number of overall requests increases.

As to growing the number of threads, what you need to be careful of here is 
that doing so in a process which also can handle CPU intensive requests, is 
that you start to bog things down due to the Python global interpreter lock 
(GIL).

If these requests are always waiting for the database and then sleeping, and 
not doing CPU intensive tasks, best way to handle it would be to create two 
separate daemon process groups. In the new daemon process group you could set 
the number of threads a lot higher in order to handle the number of concurrent 
requests. Then in the Apache configuration, you would delegate only URLs 
related to these requests which need to wait a long time to that daemon process 
group.

I call this vertically partitioning the URL namespace, the separation allowing 
you to custom daemon process groups to the specific type of work being down for 
the requests delegated to that daemon process group.

I have blogged about this concept in:

* http://blog.dscpl.com.au/2014/02/vertically-partitioning-python-web.html 
<http://blog.dscpl.com.au/2014/02/vertically-partitioning-python-web.html>

There are some examples in the post about it.

Still be careful about bumping the number of threads per process too high, 
better to also use processes as well so spreading threads. There are some 
metrics you can get out of mod_wsgi if need be to help size the thread pool so 
you aren't allocating way more than you need.

The other way is to delegate the long wrong requests to run back in embedded 
mode and so for those at least, allow them to make use of dynamic 
process/thread management of Apache.

If you were doing that, you would need to look closely at the Apache MPM 
settings and adjust them to avoid the problems with process churn Apache 
experiences. I have talked about that problem in:

* https://www.youtube.com/watch?v=k6Erh7oHvns 
<https://www.youtube.com/watch?v=k6Erh7oHvns>

To combat memory overhead, you might perhaps want to use a more lightweight 
WSGI application for handling those specific requests. Pulling in a large 
Django application wouldn't necessarily be a good idea depending on how well it 
lazily loads code, or whether is pre-pulling request handlers on startup.

I'll let you digest that and if you have questions let me know.

Graham

-- 
You received this message because you are subscribed to the Google Groups 
"modwsgi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to modwsgi+unsubscr...@googlegroups.com.
To post to this group, send email to modwsgi@googlegroups.com.
Visit this group at https://groups.google.com/group/modwsgi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to