2017-01-01 1 views
7

외부 API에 연결하여 일부 데이터를 검색하고 데이터베이스에 저장 한 다음 수백 번 반복하는 Heroku에서 셀로 작업을했습니다. 매우 빨리 (~ 10 루프 이후) Heroku는 높은 메모리 사용량에 대한 경고를 시작합니다. 어떤 아이디어?Heroku에 대한 Django Celery 작업이 높은 메모리 사용을 초래합니다.

tasks.py

@app.task 
def retrieve_details(): 
    for p in PObj.objects.filter(some_condition=True): 
     p.fetch() 

models.py

def fetch(self): 
    v_data = self.service.getV(**dict(
     Number=self.v.number 
    )) 
    response = self.map_response(v_data) 

    for key in ["some_key","some_other_key",]: 
     setattr(self.v, key, response.get(key)) 

    self.v.save() 

Heroky 로그

2017-01-01 10:26:25.634 
132 <45>1 2017-01-01T10:26:25.457411+00:00 heroku run.5891 - - Error R14 (Memory quota exceeded) 

Go to the log: https://api.heroku.com/myapps/[email protected]/addons/logentries 

You are receiving this email because your Logentries alarm "Memory quota exceeded" 
has been triggered. 

In context: 
2017-01-01 10:26:25.568 131 <45>1 2017-01-01T10:26:25.457354+00:00 heroku run.5891 - - Process running mem=595M(116.2%) 
2017-01-01 10:26:25.634 132 <45>1 2017-01-01T10:26:25.457411+00:00 heroku run.5891 - - Error R14 (Memory quota exceeded) 
+0

'fetch'에서 호출 한 메서드 본문을 게시 할 수 있습니까? – 2ps

답변

1

실제적인 확장에 대한 생각을 확장하기 위해 과거 셀러리/파이썬으로 메모리 사용 공간을 줄이기 위해 사용한 두 가지 전략은 다음과 같습니다. (1) 정확히 하나의 객체를 처리하는 하위 작업을 시작하십시오. (2) 발전기를 사용하십시오.

@app.task 
def retrieve_details(): 
    qs = PObj.objects.filter(some_condition=True) 
    for p in qs.values_list('id', flat=True): 
     do_fetch.delay(p) 

@app.task 
def do_fetch(n_id): 
    p = PObj.objects.get(id=n_id) 
    p.fetch() 

지금 당신이 조정 셀러리는 POBJ (작업)의 N 번호를 처리 한 후 프로세스의 사망 있도록 사용 메모리 풋 프린트를 낮게 유지 할 수 있습니다 : 각 프로세스는 정확히 하나의 객체 하위 오프

  1. --max-tasks-per-child. 발전기를 사용

  2. : 당신은 (이론적으로)를 POBJ을 버릴 수 있도록 내 돈 들어

    def ps_of_interest(chunk=10): 
        n = chunk 
        start = 0 
        while n == chunk: 
         some_ps = list(PObj.objects.filter(some_condition=True)[start:start + n]) 
         n = len(some_ps) 
         start += chunk 
         for p in some_ps: 
          yield p 
    
    @app.task 
    def retrieve_details(): 
        for p in ps_of_interest(): 
         p.fetch() 
    

를 가져 호출 후이 사용하는 발전기를 시도 할 수 있습니다, 내가 옵션으로 갈 것 #1.

6

당신이있는 거 BASICA lly는 메모리에있는 파이썬 사전에 많은 양의 데이터를로드합니다. 이것은 특히 많은 양의 객체를 로컬 데이터베이스에서 가져 오는 경우 많은 메모리 오버 헤드를 유발합니다.

사전에 이러한 모든 개체를 저장해야합니까?

무엇 대부분의 사람들이 이런 일을 위해 할 것은 :

  • 데이터베이스에서 한 번에 하나 개의 객체를 검색합니다.
  • 해당 항목을 처리합니다 (필요한 모든 논리 수행).
  • 반복.

이 방법을 사용하면 주어진 시간에 메모리에 단일 개체를 저장하기 만함으로써 메모리 사용 공간을 크게 줄일 수 있습니다.

내가 너라면, 내 논리를 데이터베이스 쿼리로 옮기거나 각 항목을 개별적으로 처리하는 방법을 모색 할 것입니다.

관련 문제