Функции Google превышают объем памяти

#python #google-cloud-platform #google-cloud-functions

#python #google-облачная платформа #google-cloud-функции

Вопрос:

Мы развернули функцию python в функциях GCP, которая в основном получает HTTP POST JSON и вызывает другую систему для выполнения некоторой обработки. Эта другая система возвращает JSON, и мы отправляем JSON обратно исходному вызывающему.

Функция отлично работает со 128 МБ памяти, но после того, как у нас появился новый клиент, они выполняют один вызов функции за другим, и теперь GCP выдает ошибку превышения лимита памяти и прерывает процесс.

Я понимаю, что если клиент ждет несколько минут между вызовами, объем памяти снова уменьшается, но я не могу попросить их сделать это.

Мой вопрос в том, есть ли способ предотвратить это значительное увеличение объема памяти после различных последовательных вызовов функции? Или любая альтернатива для обнаружения его достижения предела и отправки обратно ошибки тайм-аута?

Часть моего кода

 #!venv/bin/python
from flask import Flask, request, Response,jsonify,make_response
import json
import requests
from functools import wraps
import hashlib
from google.cloud import firestore
import datetime



app = Flask(__name__)
app.secret_key = b'NOTHERE'

def check_auth(username, password): 
    pwd = hashlib.sha1(str(password).encode('utf-8')).hexdigest()

    db = firestore.Client()

    users_ref = db.collection('XXX')
    doc_ref = users_ref.document(username)
    try:
        doc = doc_ref.get()
        dic = doc.to_dict()
        return pwd == dic['password']
    except:
        pass 

    return False

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Please Login', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

#main function that google calls
@requires_auth
def brokering(request):
    db = firestore.Client()
    if request.method == 'POST':
    ......... here I do some write/reads on the firestore db
  

График памяти до тех пор, пока он не сломается (130 вызовов)

введите описание изображения здесь

Комментарии:

1. Похоже, у вас утечка памяти. Вам не следует испытывать нехватку памяти под давлением, пока ваша функция не сохранит данные в глобальной памяти.

2. Я переместился db = firestore.Client() наружу, и, похоже, он работает лучше…. скоро будет обновлено

Ответ №1:

Я бы переместил как можно больше за пределы функции. Например, в данный момент вы создаете два firestore.Client() экземпляра, один в brokering и один в check_auth , для каждого отдельного запроса. Вы должны переместить это за пределы ваших определений функций и повторно использовать один экземпляр клиента внутри функций.

Вы также делаете некоторые ненужные вещи, например, инициализируете все приложение Flask, которое не используется облачными функциями, но сокращает нагрузку на вашу память.

Я бы переписал всю вашу функцию примерно так:

 from flask import request, Response
from functools import wraps
import hashlib
from google.cloud import firestore

db = firestore.Client()
users_ref = db.collection('XXX')

def check_auth(username, password): 
    pwd = hashlib.sha1(str(password).encode('utf-8')).hexdigest()
    doc_ref = users_ref.document(username)

    try:
        return pwd == doc_ref.get().to_dict()['password']
    except:
        pass 

    return False

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Please Login', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

@requires_auth
def brokering(request):
    if request.method == 'POST':
        ... # here I do some write/reads on the firestore db
  

Комментарии:

1. Я удалил приложение flask и поместил клиент за пределы функции… теперь он стабилен на уровне 70 мб 🙂 tks

2. Нет проблем! Не забудьте также удалить ненужный импорт.

3. @DustinIngram Я решаю аналогичную проблему. Хранение users_ref = db.collection(‘XXX’) внутри функции также вызывает значительную проблему с памятью? или это было перенесено за пределы функции только для удобства?

4. @zd5151 полностью зависит от вашего варианта использования, но, скорее всего, вам не нужно получать эту ссылку при каждом вызове функции.