22、构建带数据库和消息队列的Python Flask应用

构建带数据库和消息队列的Python Flask应用

1. 应用数据库访问层到斐波那契计算视图

要将数据库添加到部署中,需要将其添加到 docker-compose 部署,并更新配置文件以映射到 docker-compose 部署中的数据库服务。具体步骤如下:
1. 重构 deployment/docker-compose.yml 文件

services:
    flask_app:
        container_name: fib-calculator
        image: "flask-fib:latest"
        restart: always
        ports:
          - "5002:5002"
        expose:
            - 5002
        depends_on:
          - postgres
        links:
          - postgres
    nginx:
        ...
    postgres:
        container_name: 'fib-live-postgres'
        image: 'postgres:11.2'
        restart: always
        ports:
            - '5432:5432'
        environment:
            - 'POSTGRES_USER=user'
            - 'POSTGRES_DB=fib'
            - 'POSTGRES_PASSWORD=password'

这里数据库容器名与开发数据库不同,以避免冲突,同时声明了Flask应用依赖并链接到数据库。
2. 指向Flask应用到Docker数据库 :在 src/Dockerfile 中管理配置文件切换,代码如下:

# Copy the current directory contents into the 
  container at /app
ADD . /app
RUN rm ./config.yml
RUN mv live_config.yml config.yml
...

此步骤移除 config.yml 文件,并将 live_config.yml 重命名为 config.yml
3. 创建 src/live_config.yml 文件

DB_URL: "postgresql://user:password@postgres:5432/fib"

@localhost 改为 @postgres ,因为服务分类名为 postgres
4. 重建Flask镜像 :使用以下命令:

docker build . -t flask-fib
  1. 运行 docker-compose 部署并执行迁移
docker exec -it fib-calculator alembic upgrade head

docker-compose 运行时执行迁移,因为Flask应用在与数据库不同步时,直到查询数据库才会报错。

2. 构建消息总线

为避免计算大斐波那契数时请求挂起,将实现消息总线。使用Celery和Redis包构建和运行消息总线,具体步骤如下:

2.1 安装依赖

使用 pip 安装以下包:
- Celery:消息总线代理。
- Redis:Celery使用的存储系统。
同时更新 src/requirements.txt 文件,添加Celery和Redis。

2.2 构建Flask的Celery代理

  1. 构建任务队列模块 :在 src/ 目录下,任务队列模块结构如下:
└── task_queue
    ├── __init__.py
    ├── engine.py
    └── fib_calc_task.py

engine.py 文件包含考虑Flask应用上下文的Celery构造函数。
2. 构建Celery构造函数 :在 engine.py 文件中:

from celery import Celery
from config import GlobalParams

def make_celery(flask_app):
    params = GlobalParams()
    celery = Celery(
        backend=params.get("QUEUE_BACKEND"),
        broker=params.get("QUEUE_BROKER")
    )
    celery.conf.update(flask_app.config)
    class ContextTask(celery.Task):
        def __call__(self, *args, **kwargs):
            with flask_app.app_context():
                return self.run(*args, **kwargs)
    celery.Task = ContextTask
    return celery
  1. src/app.py 中导入并使用Celery构造函数
...
from task_queue.engine import make_celery
app = Flask(__name__)
celery = make_celery(app)
...
  1. 定义后端存储系统 :在 src/config.yml 文件中:
QUEUE_BACKEND: "redis://localhost:6379/0"
QUEUE_BROKER: "redis://localhost:6379/0"

2.3 构建斐波那契计算任务

src/task_queue/fib_calc_task.py 文件中:

from data_access import dal
from fib_calcs.fib_calculation import FibCalculation
from models.database.fib_entry import FibEntry

def create_calculate_fib(input_celery):
    @input_celery.task()
    def calculate_fib(number):
        calculation = FibCalculation(input_number=number)
        fib_entry = FibEntry(
            input_number=calculation.input_number,
            calculated_number=calculation.fib_number
        )
        dal.session.add(fib_entry)
        dal.session.commit()
    return calculate_fib

src/app.py 中导入并使用:

...
from task_queue.engine import make_celery
app = Flask(__name__)
celery = make_celery(app)
from task_queue.fib_calc_task import create_calculate_fib
calculate_fib = create_calculate_fib(input_celery=celery)
...

2.4 更新计算视图

@app.route("/calculate/<int:number>")
def calculate(number):
    fib_calc = dal.session.query(FibEntry).filter_by(
                       input_number=number).one_or_none()
    if fib_calc is None:
        if number < 31:
            calc = FibCalculation(input_number=number)
            new_calc = FibEntry(input_number=number,
                                calculated_number=calc.
                                fib_number)
            dal.session.add(new_calc)
            dal.session.commit()
            return f"you entered {calc.input_number} " \
                   f"which has a Fibonacci number of " \
                   f"{calc.fib_number}"
        calculate_fib.delay(number)
        return "calculate fib sent to queue because " \
               "it's above 30"
    return f"you entered {fib_calc.input_number} " \
           f"which has an existing Fibonacci number of " \
           f"{fib_calc.calculated_number}"

当输入数字小于31且不在数据库中时,执行标准计算;否则,将计算任务发送到Celery代理并告知用户已发送到队列。

2.5 在Docker中定义Celery服务

docker-compose.yml 文件中定义Redis服务:

...
    redis:
      container_name: 'main-dev-redis'
      image: 'redis:5.0.3'
      ports:
        - '6379:6379'

运行整个系统的开发模式:
1. 在项目根目录运行 docker-compose 文件。
2. 使用Python运行 app.py 文件,设置 PYTHONPATH src
3. 打开新终端,进入 src 目录,运行:

celery -A app.celery worker -l info

以下是构建消息总线的流程图:

graph LR;
    A[安装依赖] --> B[构建Celery代理];
    B --> C[构建斐波那契计算任务];
    C --> D[更新计算视图];
    D --> E[定义Celery服务];

3. 应用Celery到 docker-compose 部署

docker-compose.yml 文件中修改配置:

...
    main_cache:
        container_name: 'main-live-redis'
        image: 'redis:5.0.3'
        ports:
            - '6379:6379'
    queue_worker:
        container_name: fib-worker
        image: "flask-fib:latest"
        restart: always
        entrypoint: "celery -A app.celery worker -l info"
        ports:
            - "5003:5003"
        expose:
            - 5003
        depends_on:
            - main_cache
        links:
            - main_cache

同时在 live_config.yml 文件中添加参数:

QUEUE_BACKEND: "redis://main_cache:6379/0"
QUEUE_BROKER: "redis://main_cache:6379/0"

将Redis服务命名,使打包的Celery工作进程和Flask应用连接到 docker-compose 部署中的Redis服务。

4. 常见问题解答

问题 答案
从开发环境切换到 docker-compose 部署环境时,URI中要更改什么? 将URI中的 localhost 部分改为 docker-compose 服务的标签。
为什么使用配置文件? 配置文件便于切换上下文,如从开发到生产环境;若Celery服务需连接不同数据库,修改配置文件即可;还可避免硬编码数据库URI带来的安全问题。
是否真的需要alembic管理数据库? 技术上不需要,可编写SQL脚本按顺序运行,但使用alembic可节省时间、减少错误。
如何确保数据库不被挂起会话淹没? 在定义数据库引擎的文件中只初始化一次数据库引擎,在需要的地方导入该初始化引擎;同时在Flask的teardown函数中关闭会话。
Celery工作进程是否需要Redis? 需要存储机制,如Redis,但也可使用RabbitMQ或MongoDB代替。

通过以上步骤,我们构建了一个带数据库和消息队列的Python Flask应用,可在开发和部署环境中运行,并可进一步与Rust融合。

5. 总结

我们成功构建了一个具备数据库访问和消息队列功能的Python Flask应用。通过一系列操作,实现了将数据库集成到 docker-compose 部署中,同时利用Celery和Redis构建消息总线来处理繁重的计算任务。具体来说:
- 数据库集成 :通过修改 docker-compose.yml 文件添加数据库服务,使用不同的配置文件区分开发和部署环境,确保数据库的正确连接和使用。
- 消息总线构建 :安装必要的依赖,构建Celery代理、斐波那契计算任务,更新计算视图,并在Docker中定义Celery服务,实现了任务的异步处理。
- 部署优化 :将Celery应用到 docker-compose 部署中,通过修改配置文件和服务定义,使应用在部署环境中也能正常运行。

以下是整个构建过程的关键步骤总结表格:
|步骤|操作内容|
|----|----|
|应用数据库访问层|重构 docker-compose.yml ,更新配置文件,重建镜像并运行迁移|
|构建消息总线|安装依赖,构建模块、代理、任务,更新视图,定义服务|
|应用Celery到部署|修改 docker-compose.yml 和配置文件|

6. 后续操作建议

6.1 代码维护与扩展

  • 模块化管理 :继续保持代码的模块化结构,将不同功能封装在独立的模块中,便于维护和扩展。例如,对于斐波那契计算任务,可以进一步优化算法或添加更多的计算逻辑。
  • 配置管理 :使用配置文件管理不同环境的配置,确保代码的可移植性。可以考虑使用环境变量或外部配置服务,提高配置的灵活性。

6.2 性能优化

  • 缓存机制 :在数据库查询和计算过程中引入缓存机制,减少重复计算和数据库访问,提高应用的响应速度。例如,可以使用Redis作为缓存存储计算结果。
  • 并发处理 :优化Celery的并发配置,根据服务器资源合理调整工作进程数量,提高任务处理的效率。

6.3 安全保障

  • 数据加密 :对于敏感数据,如数据库连接信息、用户输入等,进行加密处理,确保数据的安全性。
  • 访问控制 :在Flask应用中实现访问控制机制,限制对敏感接口和资源的访问,防止非法请求。

以下是后续操作建议的流程图:

graph LR;
    A[代码维护与扩展] --> B[模块化管理];
    A --> C[配置管理];
    D[性能优化] --> E[缓存机制];
    D --> F[并发处理];
    G[安全保障] --> H[数据加密];
    G --> I[访问控制];

通过以上总结和建议,我们可以更好地管理和优化这个Python Flask应用,为后续与Rust的融合以及更复杂的业务需求做好准备。同时,不断关注代码的性能、安全和可维护性,确保应用的稳定运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值