Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to log memory usage of an Django app per request

Do you know about an efficient way to log memory usage of a django app per request ?

I have an apache/mod_wsgi/django stack, which runs usually well, but sometimes one process ends up eating a huge lot of memory. The servers ends up being short on mem, swapping a lot, and services are dramatically slowed down.

This situation is quite hard to fix because I don't know which request is to be blamed for this behavior, I can't reproduce it.

I'd like to have something deployed in production which logs the memory usage of the process before and after each request, with minimal overhead.


Before I start reinventing the wheel, do the community of my fellow djangoists know any existing solution to address this problem ? Advices, middleware, snippet or maybe apache log configuration appreciated.

What (I think) I don't need is:

  • a set of dev-stage profiling/debugging tools, I already know some and I'd use them if I knew what to profile/debug, it looks a little bit too much to be forever monitoring services running in production. On top of that, what is usually displayed by those tol is a mem usage report of the code shred to pieces, It would really be helpful to just pinpoint the faulty request.
  • generic advices on how to optimize mem usage of a django app, well it's always good to read, but the idea here is rather «how to efficiently track down requests which need to be optimized».

My closest search results:

  • Django / WSGI - How to profile partial request? My profiling tools are per-request but app runs out of memory before then
  • Django memory usage going up with every request
  • Average php memory usage per request?
like image 507
ddelemeny Avatar asked Sep 03 '12 13:09

ddelemeny


2 Answers

A Django middleware for tracking memory usage and generating a usable result immediately, needs to hook both process request and process response. In other words, look at difference between start and finish of request and log a warning if exceeds some threshold.

A complete middleware example is:

import os
import psutil
import sys

THRESHOLD = 2*1024*1024

class MemoryUsageMiddleware(object):

    def process_request(self, request):
        request._mem = psutil.Process(os.getpid()).memory_info()

   def process_response(self, request, response):
        mem = psutil.Process(os.getpid()).memory_info()
        diff = mem.rss - request._mem.rss
        if diff > THRESHOLD:
            print >> sys.stderr, 'MEMORY USAGE %r' % ((diff, request.path),)
        return response

This requires the 'psutil' module to be installed for doing memory calculation.

Is brute force and can lead to false positives in a multithread system. Because of lazy loading, you will also see it trigger on first few requests against new process as stuff loads up.

like image 71
Graham Dumpleton Avatar answered Sep 19 '22 13:09

Graham Dumpleton


This may not fully cover your question, but I recommend trying nginx+uwsgi instead of apache2+mod_wsgi. In my tests it turned out to be much more stable (mod_wsgi choked at some point completely), much faster and uses a lot less memory (it may just fix all your issues altogether).

About tracking memory usage, you can create a simple middleware:

class SaveMemoryUsageMiddleware(object):
    def process_response(self, request, response):
        # track memory usage here and append to file or db
        return response

and add it to your middlewares.

For memory tracking code I recommend checking out: Total memory used by Python process?

However, it would probably be better if you could avoid doing this on production. Just for dev and tests to track down real problem.

like image 30
arkens Avatar answered Sep 22 '22 13:09

arkens