In your recipe for a background monitoring thread watching memory consumption, after issuing the SIGUSR1, I'd probably just want the thread to exit instead of sleeping... do I just do "sys.exit()" to safely accomplish that?
Also, regarding my observations of paster returning garbage-collected memory to the OS, was I just getting lucky while monitoring (the memory was at the very top of the allocated memory)? This is a universal python issue? Again, thanks for all your help! On Sat, Mar 19, 2016 at 11:22 PM, Graham Dumpleton < [email protected]> wrote: > > On 20 Mar 2016, at 1:10 AM, Kent Bower <[email protected]> wrote: > > Thanks Graham, few more items inline... > > On Sat, Mar 19, 2016 at 1:24 AM, Graham Dumpleton < > [email protected]> wrote: > >> >> On 17 Mar 2016, at 11:28 PM, Kent Bower <[email protected]> wrote: >> >> My answers are below, but before you peek, Graham, note that you and I >> have been through this memory discussion before & I've read the vertical >> partitioning article and use inactivity-timeout, "WSGIRestrictEmbedded On", >> considered maximum-requests, etc. >> >> After years of this, I'm resigned to the fact that python is memory >> hungry, especially built on many of these web-stack and database libraries, >> etc. I'm Ok with that. I'm fine with a high-water RAM mark imposed by >> running under Apache, mostly. But, dang, it sure would be great if the 1 >> or 2% of requests that really (and legitimately) hog a ton of RAM, like, >> say 500MB extra, didn't keep it when done. I may revisit vertical >> partitioning again, but last time I did I think I found that the 1 or 2% in >> my case generally won't be divisible by url. In most cases I wouldn't know >> whether the particular request is going to need lots of RAM until >> *after *the database queries return (which is far too late for vertical >> partitioning to be useful). >> >> So I was mostly just curious about the status of nginx running wsgi, >> which doesn't solve python's memory piggishness, but would at least >> relinquish the extra RAM once python garbage collected. >> >> >> Where have you got the idea that using nginx would result in memory being >> released back to the OS once garbage collected? It isn’t able to do that. >> >> The situations are very narrow as to when a process is able to give back >> memory to the operating system. It can only be done when the now free >> memory was at top of allocated memory. This generally only happens for >> large block allocations and not in normal circumstances for a running >> Python application. >> > > > At this point I'm not sure where I got that idea, but I'm surprised at > this. For example, my previous observations of paster running wsgi were > that it is quite faithful at returning free memory to the OS. Was I just > getting lucky, or would paster be different for some reason? > > In any case, if nginx won't solve that, then I can't see any reason to > even consider it over apache/mod_wsgi. Thank you for answering that. > > >> >> (Have you considered a max-memory parameter to mod_wsgi that would >> gracefully stop taking requests and shutdown after the threshold is reached >> for platforms that would support it? I recall -- maybe incorrectly -- you >> saying on Windows or certain platforms you wouldn't be able to support >> that. What about the platforms that *could *support it? It seems to me >> to be the very best way mod_wsgi could approach this Apache RAM nuance, so >> seems like it would be tremendously useful for the platforms that could >> support it.) >> >> >> You can do this yourself rather easily with more recent mod_wsgi version. >> >> If you create a background thread from a WSGI script file, in similar way >> as monitor for code changes does in: >> >> >> http://modwsgi.readthedocs.org/en/develop/user-guides/debugging-techniques.html#extracting-python-stack-traces >> >> but instead of looking for code changes, inside the main loop of the >> background thread do: >> >> import os >> import mod_wsgi >> >> metrics = mod_wsgi.process_metrics() >> >> if metrics[‘memory_rss’] > MYMEMORYTHRESHOLD: >> os.kill(os.getpid(), signal.SIGUSR1) >> >> So mod_wsgi provides the way of determining the amount of memory without >> resorting to importing psutil, which is quite fat in itself, but how you >> use it is up to you. >> > > > Right, that's an idea; (could even be a shell script that takes this > approach, I suppose, but I like your recipe.) > > Unfortunately, I don't want to *automate *bits that can feasibly clobber > blocked sessions. SIGUSR1, after graceful-timeout & shutdown-timeout, can > result in ungraceful killing. Our application shares a database with an > old legacy application which was poorly written to hold transactions while > waiting on user input (this was apparently common two decades ago). So, > unfortunately, it isn't terribly uncommon that our application is blocked > at the database level waiting for someone using the legacy application who > has a record(s) locked and may not even be at their desk or may have gone > to lunch. Sometimes our client's IT staff has to hunt down these people or > decide to kill their database session. In any case, from a professional > point of view, our application should be the responsible one and wait > patiently, allowing our client's IT staff the choice of how to handle those > cases. So, while the likelihood is pretty low, even with graceful-timeout > & shutdown-timeout set at a very high value like 5 minutes,* I still run > the risk of killing legitimate sessions with SIGUSR1*. (I've brought > this up before and you didn't agree with my gripe and I do understand why, > but in my use case, I don't feel I can automate that route responsibly.... > we do use SIGUSR1 manually sometimes, when we can monitor and react to > cases where a session is blocked at the database level.) > > > If we have discussed it previously, then I may not have anything more to > add. > > Did I previously suggest offloading this memory consuming tasks behind a > job queue run under Celery or something else? That way they are out of the > web server processes at least. > > inactivity-timeout doesn't present this concern: it won't ever kill > anything, just silently restarts like a good boy when inactive. I've > recently reconsidered dropping that way down from 30 minutes. (When I > first implemented this, it was just to reclaim RAM at the end of the day, > so that's why it is 30 minutes. I didn't like the idea of churning new > processes during busy periods, but I've been thinking 1 or 2 minutes may be > quite reasonable.) > > If I could signal processes to shutdown at their next opportunity (meaning > the next time they are handling no requests, like inactivity-timeout), that > would solve many issues in this regard for me because I could signal these > processes when their RAM consumption is high and let them restart when > "convenient," being the ultimate in gracefulness. SIGUSR2 could mean "the > next time you get are completely idle," while SIGUSR1 continues to mean > "initiate shutdown now.” > > > That is what SIGUSR1 does it you set graceful-timeout large enough. It is > SIGINT or SIGTERM which is effectively initiate shutdown now. So shouldn’t > be a need to have a SIGUSR2 as SIGUSR1 should already do what you are > hoping for with a reasonable setting of graceful-timeout. > > >> Do note that if using SIGUSR1 to restart the current process (which >> should only be done for deamon mode), you should also set graceful-timeout >> option to WSGIDaemonProcess if you have long running requests. It is the >> maximum time process will wait to shutdown while still waiting for requests >> when doing a SIGUSR2 graceful shutdown of process, before going into forced >> shutdown mode where no requests will be accepted and requests can be >> interrupted. >> >> Here ( >> http://blog.dscpl.com.au/2009/05/blocking-requests-and-nginx-version-of.html) >> you discuss nginx's tendency to block requests that may otherwise be >> executing in a different process, depending on timing, etc. Is this issue >> still the same (I thought I read a hint somewhere that there may be a >> workaround for that), so I ask. >> >> >> That was related to someones attempt to embedded a Python interpreter >> inside of nginx processes themselves. That project died a long time ago. No >> one embeds Python interpreters inside of nginx processes. It was a flawed >> design. >> >> I don’t what you are reading to get all these strange ideas. :-) >> > > > Google, I suppose ;) That's why I finally asked you when I couldn't find > anything more about it via Google. > > > >> >> And so I wanted your opinion on nginx... >> >> ==== >> Here is what you asked for if it can still be useful. >> >> I'm on mod_wsgi-4.4.6 and the particular server that prompted me this >> time is running Apache 2.4 (prefork), though some of our clients use 2.2 >> (prefork). >> >> Our typical wsgi conf setting is something like this, though threads and >> processes varies depending on server size: >> >> LoadModule wsgi_module modules/mod_wsgi.so >> WSGIPythonHome /home/rarch/tg2env >> # see http://code.google.com/p/modwsgi/issues/detail?id=196#c10 concerning >> timeouts >> WSGIDaemonProcess rarch processes=20 threads=14 inactivity-timeout=1800 >> display-name=%{GROUP} graceful-timeout=5 >> python-eggs=/home/rarch/tg2env/lib/python-egg-cache >> >> >> Is your web server really going to be idle for 30 minutes? I can’t see >> how that would have been doing anything. >> >> Also, in mod_wsgi 4.x when inactivity-timeout kicks in has changed. >> >> It used to apply when there were active requests and they were blocked, >> as well as when no requests were running. >> >> Now it only applies to case where there are no requests. >> >> The case for running but blocked requests is now handled by >> request-timeout. >> >> You may be better of setting request-timeout now to be a more reasonable >> value for your expected longest request, but set inactivity-timeout to >> something much shorter. >> >> So suggest you play with that. >> >> Also, are you request handles I/O or CPU intensive and how many requests? >> >> Such a high number of processes and threads always screams to me that >> half the performance problems are due to setting these too [HIGH], invoking >> pathological OS process swapping issues and Python GIL issues. >> >> > > Yes, the requests are I/O intensive (that is, database intensive, which > adds a huge overhead to our typical request). Often requests finish in > under a second or two, but they also can take many seconds (not > *terrible *for the user, but sometimes they do a lot of processing with > many trips to the database). > We have several clients (companies), so the number of requests varies > widely, but can get pretty heavy on busy days (like black friday, since > they are in retail). We've played with those numbers quite a bit and > without high numbers like that, responsiveness suffers because we backlog > due to requests often taking several seconds. > > Thanks for all your input, you've been tremendously helpful! > Kent > > > > >> WSGIProcessGroup rarch >> WSGISocketPrefix run/wsgi >> WSGIRestrictStdout Off >> WSGIRestrictStdin On >> # Memory tweak. >> http://blog.dscpl.com.au/2009/11/save-on-memory-with-modwsgi-30.html >> WSGIRestrictEmbedded On >> WSGIPassAuthorization On >> >> # we'll make the /tg/ directory resolve as the wsgi script >> WSGIScriptAlias /tg >> /home/rarch/trunk/src/appserver/wsgi-config/wsgi-deployment.py >> process-group=rarch application-group=%{GLOBAL} >> WSGIScriptAlias /debug/tg >> /home/rarch/trunk/src/appserver/wsgi-config/wsgi-deployment.py >> process-group=rarch application-group=%{GLOBAL} >> >> MaxRequestsPerChild 0 >> <IfModule prefork.c> >> MaxClients 308 >> ServerLimit 308 >> </IfModule> >> <IfModule worker.c> >> ThreadsPerChild 25 >> MaxClients 400 >> ServerLimit 16 >> </IfModule> >> >> >> Thanks for all your help and for excellent software! >> Kent >> >> >> On Wed, Mar 16, 2016 at 7:27 PM, Graham Dumpleton < >> [email protected]> wrote: >> >>> On the question of whether nginx will solve this problem, I can’t see >>> how. >>> >>> When one talks about nginx and Python web applications, it is only as a >>> proxy for HTTP requests to some backend WSGI server. The Python web >>> application doesn’t run in nginx itself. So memory issues and how to deal >>> with them are the provence of the WSGI server used, whatever that is and >>> not nginx. >>> >>> Anyway, answer the questions below and can start with that. >>> >>> You really want to be using recent mod_wsgi version and not Apache 2.2. >>> >>> Apache 2.2 design has various issues and bad configuration defaults >>> which means it can gobble up more memory than you want. Recent mod_wsgi >>> versions have workarounds for Apache 2.2 issues and are much better at >>> eliminating those Apache 2.2 issues. Recent mod_wsgi versions also have >>> fixes for memory usage problems in some corner cases. As far as what I mean >>> by recent, I recommend 4.4.12 or later. The most recent version is 4.4.21. >>> If you are stuck with 3.4 or 3.5 from your Linux distro that is not good >>> and that may increase problems. >>> >>> So long as got recent mod_wsgi version then can look at using vertical >>> partitioning to farm out memory hungry request handlers to their own daemon >>> process group and better configure those to handle that and recycle >>> processes based on activity or, memory usage. A blog post related to that >>> is: >>> >>> * >>> http://blog.dscpl.com.au/2014/02/vertically-partitioning-python-web.html >>> >>> Graham >>> >>> On 17 Mar 2016, at 7:15 AM, Graham Dumpleton <[email protected]> >>> wrote: >>> >>> What version of mod_wsgi and Apache are you using? >>> >>> Are you stuck with old versions of both? >>> >>> For memory tracking there are API calls mod_wsgi provides in recent >>> versions for getting memory usage which can be used as part of scheme to >>> trigger a process restart. You can’t use sys.exit(), but can use signals to >>> trigger a clean shutdown of a process. Again better to have recent mod_wsgi >>> versions as can then also set up some graceful timeout options for signal >>> induced restart. >>> >>> Also, what is your mod_wsgi configuration so can make sure doing all the >>> typical things one would do to limit memory usage, or quarantine particular >>> handlers which are memory hungry? >>> >>> Graham >>> >>> On 17 Mar 2016, at 4:29 AM, Kent Bower <[email protected]> wrote: >>> >>> Interesting idea.. yes, we are using multiple threads and also other >>> stack frameworks, so that's not straightforward, but worth thinking >>> about... not sure how to approach that with the other threads. Thank you >>> Bill. >>> >>> On Wed, Mar 16, 2016 at 1:11 PM, Bill Freeman <[email protected]> wrote: >>> >>>> I don't know about nginx, but one possibility, if the large memory >>>> requests are infrequent, is to detect when you have completed one and >>>> trigger the exit/reload of the daemon process (calling sys.exit() is not >>>> the way, since there could be other threads in the middle of something, >>>> unless you run one thread per process). >>>> >>>> On Wed, Mar 16, 2016 at 7:50 AM, Kent <[email protected]> wrote: >>>> >>>>> I'm looking for a very brief high-level pros vs. cons of wsgi under >>>>> *apache *vs. under *nginx *and then to be pointed to more details I >>>>> can study myself (or at least the latter). >>>>> >>>>> Our application occasionally allows requests that consume a large >>>>> amount of RAM (no obvious way around that, they are valid requests) and >>>>> occasionally this causes problems since we can't reclaim the RAM readily >>>>> from apache. (We already have tweaked with and do use >>>>> "inactivity-timeout". This helps, but still now and then we hit problems >>>>> where we run into swapping to disk.) >>>>> >>>>> I'm wondering if nginx may solve this problem. I've read much of what >>>>> you (Graham) have had to say about the memory strategies with apache and >>>>> mod_wsgi, but wonder what your opinion of nginx is and where you've >>>>> already >>>>> discussed this. I've read articles I could find you've written on nginx, >>>>> such as "Blocking requests and nginx version of mod_wsgi," but wonder if >>>>> the same weaknesses are still applicable today, 7 years later? >>>>> >>>>> >>>>> Thank you very much in advance! >>>>> Kent >>>>> >>>>> -- >>>>> 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 [email protected]. >>>>> To post to this group, send email to [email protected]. >>>>> Visit this group at https://groups.google.com/group/modwsgi. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> >>>> -- >>>> You received this message because you are subscribed to a topic in the >>>> Google Groups "modwsgi" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/modwsgi/wyo2bJP0Cfc/unsubscribe. >>>> To unsubscribe from this group and all its topics, send an email to >>>> [email protected]. >>>> To post to this group, send email to [email protected]. >>>> Visit this group at https://groups.google.com/group/modwsgi. >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> >>> -- >>> 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 [email protected]. >>> To post to this group, send email to [email protected]. >>> Visit this group at https://groups.google.com/group/modwsgi. >>> For more options, visit https://groups.google.com/d/optout. >>> >>> >>> >>> >>> -- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "modwsgi" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/modwsgi/wyo2bJP0Cfc/unsubscribe. >>> To unsubscribe from this group and all its topics, send an email to >>> [email protected]. >>> To post to this group, send email to [email protected]. >>> Visit this group at https://groups.google.com/group/modwsgi. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> >> -- >> 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 [email protected]. >> To post to this group, send email to [email protected]. >> Visit this group at https://groups.google.com/group/modwsgi. >> For more options, visit https://groups.google.com/d/optout. >> >> >> >> -- >> You received this message because you are subscribed to a topic in the >> Google Groups "modwsgi" group. >> To unsubscribe from this topic, visit >> https://groups.google.com/d/topic/modwsgi/wyo2bJP0Cfc/unsubscribe. >> To unsubscribe from this group and all its topics, send an email to >> [email protected]. >> To post to this group, send email to [email protected]. >> Visit this group at https://groups.google.com/group/modwsgi. >> For more options, visit https://groups.google.com/d/optout. >> > > > -- > 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 [email protected]. > To post to this group, send email to [email protected]. > Visit this group at https://groups.google.com/group/modwsgi. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to a topic in the > Google Groups "modwsgi" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/modwsgi/wyo2bJP0Cfc/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > [email protected]. > To post to this group, send email to [email protected]. > Visit this group at https://groups.google.com/group/modwsgi. > For more options, visit https://groups.google.com/d/optout. > -- 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 [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/modwsgi. For more options, visit https://groups.google.com/d/optout.
