Zużycie pamięci przez aplikacje Django - przypadki
28 July 2009
Comments
Iterowanie po dużych zbiorach danych
Należy unikać pobierania dużej ilości pełnych rekordów, szczególnie tych o dużym rozmiarze (np. artykuły), gdy chcemy operować na niektórych kolumnach. Należy użyć wtedy metod takich jak .values() i .distinct() by nie pobierać zbędnych danych do pamięci RAM.
Whoosh
Odpalając JobMastera zastosowałem parę nowych rozwiązań, w tym Whoosha zgodnie z przykładem zaprezentowanym na blogu arnebrodowski.de. Najważniejszy jest widok wyszukiwania, gdyż zaprezentowane tam rozwiązanie powoduje wycieki pamięci (hosting Nginx/FastCGI), a dokładnie: searcher = ix.searcher(). Każde wyszukiwanie na stronie zwiększało ilość zużywanej pamięci (memstat -v). Rozwiązanie to nie tworzyć tego obiektu co żądanie, a schować jeden w settingsach aplikacji (gdzie dla pewności wrzuciłem resztę obiektów, które można ponownie wykorzystać):WHOOSH_SCHEMA = fields.Schema(title=fields.TEXT(stored=True),
content=fields.TEXT,
slug=fields.ID(stored=True, unique=True))
storage = store.FileStorage(WHOOSH_INDEX)
ix = index.Index(storage, schema=WHOOSH_SCHEMA)
PARSER = QueryParser("content", schema=ix.schema)
SEARCHER = ix.searcher()
# -*- coding: utf-8 -*-
from socket import *
for i in range(0, 100):
s = socket(AF_INET, SOCK_STREAM) #utworzenie gniazda
s.connect(('localhost', 8889)) # nawiazanie polaczenia
s.send('popularna fraza tutaj')
res = s.recv(102400)
s.close()
print i
print res
print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
# -*- coding: utf-8 -*-
from socket import *
import simplejson as json
from whoosh import index, store, fields
from whoosh.qparser import QueryParser
from whoosh import store, fields, index
# dane indeksu whoosh
WHOOSH_INDEX = '/ściezka/do/indeksu/whoosh/'
WHOOSH_SCHEMA = fields.Schema(title=fields.TEXT(stored=True),
content=fields.TEXT,
slug=fields.ID(stored=True, unique=True))
# konfiguracja whoosh
storage = store.FileStorage(WHOOSH_INDEX)
ix = index.Index(storage, schema=WHOOSH_SCHEMA)
parser = QueryParser("content", schema=ix.schema)
# konfiguracja serwera
s = socket(AF_INET, SOCK_STREAM) #utworzenie gniazda
s.bind(('', 8889))
s.listen(5)
while 1:
client,addr = s.accept() # odebranie polaczenia
print 'Polaczenie z ', addr
while 1:
# odebranie frazy do wyszukania
query = client.recv(1024)
if not query: break
# przygotowanie jej do wyszukiwania
query = query.replace('+', ' AND ').replace(' -', ' NOT ').replace(', ', ' AND ')
hits = []
try:
qry = parser.parse(query)
except:
qry = None
if qry is not None:
# TO CIEKNIE
searcher = ix.searcher()
hits = searcher.search(qry)
# przygotowanie wyników do wysłania
if len(hits) > 0:
res = []
for i in hits:
res.append({'slug': i['slug'], 'title': i['title']})
hits = json.dumps(res)
else:
hits = '||'
client.send(hits) # wyslanie danych do klienta
client.close()
# -*- coding: utf-8 -*-
from socket import *
import simplejson as json
from whoosh import index, store, fields
from whoosh.qparser import QueryParser
from whoosh import store, fields, index
# dane indeksu whoosh
WHOOSH_INDEX = '/ściezka/do/indeksu/whoosh/'
WHOOSH_SCHEMA = fields.Schema(title=fields.TEXT(stored=True),
content=fields.TEXT,
slug=fields.ID(stored=True, unique=True))
# konfiguracja whoosh
storage = store.FileStorage(WHOOSH_INDEX)
ix = index.Index(storage, schema=WHOOSH_SCHEMA)
searcher = ix.searcher()
parser = QueryParser("content", schema=ix.schema)
# konfiguracja serwera
s = socket(AF_INET, SOCK_STREAM) #utworzenie gniazda
s.bind(('', 8889))
s.listen(5)
while 1:
client,addr = s.accept() # odebranie polaczenia
print 'Polaczenie z ', addr
while 1:
# odebranie frazy do wyszukania
query = client.recv(1024)
if not query: break
# przygotowanie jej do wyszukiwania
query = query.replace('+', ' AND ').replace(' -', ' NOT ').replace(', ', ' AND ')
hits = []
try:
qry = parser.parse(query)
except:
qry = None
if qry is not None:
hits = searcher.search(qry)
# przygotowanie wyników do wysłania
if len(hits) > 0:
res = []
for i in hits:
res.append({'slug': i['slug'], 'title': i['title']})
hits = json.dumps(res)
else:
hits = '||'
client.send(hits) # wyslanie danych do klienta
client.close()
Sitemaps
Okazuje się także że generowane przez Djangowski framework Sitemaps mapy sitemap są w jakiś sposób "trzymane" w RAMie - jeżeli mamy dużą mapę, to jej wygenerowanie zajmie sporą ilość pamięci RAM. Dla przykładu moja mapa miała około 9000 elementów, co dawało plik sitemap.xml o rozmiarze 1,7MB. Jej wygenerowanie spowodowało wzrost zużycia pamięci przez aplikację z około 6 do 105MB. Kolejne żądania sitemapy nie podnosiły zużycia RAM. Rozwiązanie: używać statycznych map.
RkBlog
Comment article