首页 > 解决方案 > 高山 docker 容器内存泄漏中的 Flask REST-API

问题描述

几天来,我试图在我的烧瓶 REST-API 中找到一种内存泄漏,但没有任何相关进展。

我有一个使用 mysql 数据库(如 SQLAlchemy、connexion 和 marshmallow 等软件包)的烧瓶 REST-API。它可以通过 docker 容器获得,该容器具有来自 alpine:latest 的基本映像。

我遇到的主要问题是:对 REST-API 的每个请求都会增加 docker 容器的内存使用量并且不会释放内存。API 不缓存结果。

下面是来自 server.py 的代码(REST-API 的主程序):

"""
Main module of the server file
"""

# 3rd party moudles

# local modules
import config

# Get the application instance
connex_app = config.connex_app

# Read the swagger.yml file to configure the endpoints
connex_app.add_api("swagger_2.0.yml")

# create a URL route in our application for "/"
@connex_app.route("/")
def home():
    return None

if __name__ == "__main__":
    connex_app.run(debug=True)

和配置文件:

import os

import connexion
from flask_cors import CORS
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from memory_profiler import memory_usage


basedir = os.path.abspath(os.path.dirname(__file__))

# Create the Connexion application instance
connex_app = connexion.App(__name__, specification_dir=basedir)

# Get the underlying Flask app instance
app = connex_app.app
CORS(app)

# Configure the SQLAlchemy part of the app instance
app.config['SQLALCHEMY_ECHO'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:somepassword@someHostId/sponge"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False


@app.after_request
def add_header(response):
    #response.cache_control.no_store = True
    if 'Cache-Control' not in response.headers:
        response.headers['Cache-Control'] = 'max-age=0'
    print(memory_usage(-1, interval=.2, timeout=1), "after request")
    return response


# Create the SQLAlchemy db instance
db = SQLAlchemy(app)

# Initialize Marshmallow
ma = Marshmallow(app)

您可以在此处看到的端点示例:

from flask import abort
import models

def read(disease_name=None):
    """
       This function responds to a request for /sponge/dataset/?disease_name={disease_name}
       with one matching entry to the specifed diesease_name

       :param disease_name:   name of the dataset to find (if not given, all available datasets will be shown)
       :return:            dataset matching ID
       """

    if disease_name is None:
        # Create the list of people from our data
        data = models.Dataset.query \
            .all()
    else:
        # Get the dataset requested
        data = models.Dataset.query \
            .filter(models.Dataset.disease_name.like("%" + disease_name + "%")) \
            .all()

    # Did we find a dataset?
    if len(data) > 0:
        # Serialize the data for the response
        return models.DatasetSchema(many=True).dump(data).data
    else:
        abort(404, 'No data found for name: {disease_name}'.format(disease_name=disease_name))

我尝试使用 memory_profiler 工具在代码中查找内存泄漏,但由于可以在每个 REST-API 端点观察到相同的行为(在每个请求中增加 docker 容器的内存使用量)。

任何人都可以解释发生了什么,或者知道我如何解决缓存问题。

标签: pythondockerflaskmemory-leakssqlalchemy

解决方案


问题已解决。其实没问题。由于 python 的实现,docker stats 内存使用量增加。如果 rest-api 请求是数 GB 大,那么 python 会分配一定比例的已用内存,并且不会立即释放它。因此,500 GB 的峰值是在一个非常好的答案之后。我向 API 端点添加了一个固定限制,并提示用户如果超过此限制,他应该将整个数据库下载为 zip fornat 并在本地使用它。


推荐阅读