构建带数据库和消息队列的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
-
运行
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代理
-
构建任务队列模块
:在
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
-
在
src/app.py中导入并使用Celery构造函数 :
...
from task_queue.engine import make_celery
app = Flask(__name__)
celery = make_celery(app)
...
-
定义后端存储系统
:在
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的融合以及更复杂的业务需求做好准备。同时,不断关注代码的性能、安全和可维护性,确保应用的稳定运行。
超级会员免费看
25

被折叠的 条评论
为什么被折叠?



