Search code examples
djangomemoryuwsgigeoipgeoip2

"[Errno 12] Cannot allocate memory" on Geoip2() in Django with uWSGI


The following code runs successfully in manage.py shell:

from django.contrib.gis.geoip2 import GeoIP2
g = GeoIP2()

If I start the server manually with manage.py runserver and put the code in my Django view, it also runs fine.

My Django application is hosted with uWSGI and Nginx as reverse proxy. Both uWSGI and Nginx run with www-data user.

Here is the exception that I get when running on uWSGI:

...
File "/home/myuser/Env/virtenv/myproject/index/views.py" in index
  28.     g = GeoIP2()

File "/home/myuser/Env/virtenv/local/lib/python2.7/site-packages/django/contrib/gis/geoip2/base.py" in __init__
  95.                 self._city = geoip2.database.Reader(city_db, mode=cache)

File "/home/myuser/Env/virtenv/local/lib/python2.7/site-packages/geoip2/database.py" in __init__
  82.         self._db_reader = maxminddb.open_database(filename, mode)

File "/home/myuser/Env/virtenv/local/lib/python2.7/site-packages/maxminddb/__init__.py" in open_database
  37.         return maxminddb.reader.Reader(database, mode)

File "/home/myuser/Env/virtenv/local/lib/python2.7/site-packages/maxminddb/reader.py" in __init__
  52.                     db_file.fileno(), 0, access=mmap.ACCESS_READ)

Exception Type: error at /
Exception Value: [Errno 12] Cannot allocate memory

Local variables are:

Variable    Value
database    '/home/myuser/Env/virtenv/myproject/geoip/GeoLite2-City.mmdb'
db_file     <closed file '/home/myuser/Env/virtenv/myproject/geoip/GeoLite2-City.mmdb',     mode 'rb' at 0x7f8c5cf5d390>
mode        0
self        <maxminddb.reader.Reader object at 0x7f8c5cf5f550>

I use Virtualbox and my guest OS is Ubuntu 16.04. I have 4GB swap file there. If I free up some RAM the problem persists. This shouldn't be a memory issue on OS level, though, as I can create the GeoIP2 object in the shell and also if I run the server manually.

Next thing I checked is that the geoip directory in my project is owned by www-data and has 775. Both files inside (GeoLite2-City.mmdb and GeoLite2-Country.mmdb) are also owned by www-data and have 774.

/etc/systemd/system/uwsgi.service contains:

[Unit]
Description=uWSGI Emperor service

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown www-data:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

/etc/uwsgi/sites/my_site.ini contains:

[uwsgi]

project = myproject
base = /home/myuser
home = %(base)/Env/virtenv/%(project)

binary-path = /usr/local/bin/uwsgi
chdir = %(home)
chmod-socket = 660
chown-socket = www-data:www-data
#emperor = true
#enable-threads = true
gid = www-data
limit-as = 1024
logto = /tmp/uwsgi.log
master = true
module = myproject.wsgi:application
pidfile = /opt/logs/uwsgi/master.pid
# number of cores on machine
processes = 2
python-path = %(home)
py-autoreload = 2
socket = /run/uwsgi/%(project).sock
uid = www-data
vacuum = true
virtualenv = %(base)/Env/virtenv
vhost = true
workers = 4

env = AWS_KEY=***************
env = AWS_SECRET=***************
env = DJANGO_SETTINGS_MODULE=myproject.settings.local
env = GMAIL_PASS=***************
env = PSQL_PASS=***************
env = SECRET_KEY=*********************************************

I am wondering where the limitation of uWSGI is?


Solution

  • limit-as = 512 in uWSGI's ini file was the culprit. Doubling it to 1024 mb resolves the problem.

    From the official uWSGI 2 documentation here:

    limit-as

    Argument: number

    Limit process address space (vsz) (in megabytes).

    Limits the address space usage of each uWSGI (worker) process using POSIX/UNIX setrlimit(). For example, limit-as 256 will disallow uWSGI processes to grow over 256MB of address space. Address space is the virtual memory a process has access to. It does not correspond to physical memory. Read and understand this page before enabling this option: http://en.wikipedia.org/wiki/Virtual_memory