使用Gunicorn(含Worker)部署FastAPI服务器的数据更新异常问题
问题:FastAPI接口刷新后有时无法获取最新数据
我用FastAPI完成了一个简单的后端测试:通过Docs页面的POST接口提交数据,再通过GET接口读取数据。但每次按下F5刷新时,有时能获取到更新后的数据,有时却无法获取到最新数据。相关代码文件如下:
db_class.py
from sqlalchemy import Column, TEXT, INT, BIGINT from sqlalchemy.orm import declarative_base Base = declarative_base() class Test(Base): __tablename__ = 'test' id = Column(BIGINT,nullable=False, autoincrement=True, primary_key=True) name = Column(TEXT, nullable=False) number = Column(INT, nullable=False)
db_conn.py
from sqlalchemy import * from sqlalchemy.orm import sessionmaker conn_string = "mysql+pymysql://root:password@mariadb:3306/example" class engineconn: def __init__(self): self.engine = create_engine(conn_string, pool_recycle =500) def sessionmaker(self): Session = sessionmaker(bind=self.engine) session = Session() return session def connection(self): conn = self.engine.connect() return conn
main.py
from fastapi import FastAPI from pydantic import BaseModel from db_conn import engineconn from db_class import Test app = FastAPI() engine = engineconn() session = engine.sessionmaker() class Item(BaseModel): name: str number: int @app.get("/") async def first_get(): example = session.query(Test).all() return example @app.post("/post") async def first_post(item: Item): addMemo = Test(name=item.name, number=item.number) session.add(addMemo) session.commit() return item
Dockerfile
FROM python:3.9.0 WORKDIR /home/ RUN echo '2323' RUN git clone (my git) WORKDIR /home/(my_folder) RUN pip install -r requirements.txt EXPOSE 8080 CMD ["bash", "-c", "gunicorn main:app --worker-class=uvicorn.workers.UvicornWorker --workers=3 --bind 0.0.0.0:8080"]
docker-compose.yml
version: "3.7" services: nginx: image: nginx:1.19.5 networks: - network volumes: - /home/fastapi_chk/nginx.conf:/etc/nginx/nginx.conf ports: - 80:80 fastapi_test: image: fastapi_test networks: - network mariadb: image: mariadb:10.5 networks: - network volumes: - mariadb-database:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: rkwkrh13!# ports: - 3306:3306 networks: network: volumes: mariadb-database:
问题原因分析
- 全局会话复用问题:
main.py中全局创建了一个session对象,所有请求共用同一个数据库会话。SQLAlchemy的会话会缓存查询结果,后续GET请求会优先读取缓存,不会实时从数据库拉取最新数据。 - 多Worker进程冲突:Dockerfile中配置了3个gunicorn Worker进程,每个Worker都会初始化独立的全局
session。当请求被分配到不同Worker时,部分Worker的会话缓存仍是旧数据,导致读取不到最新内容。 - 会话生命周期管理错误:全局会话长期存在,未在请求结束后关闭或刷新,缓存无法及时更新。
解决方案
1. 为每个请求创建独立数据库会话
使用FastAPI的依赖注入机制,为每个请求分配独立的数据库会话,请求结束后自动关闭。修改main.py如下:
from fastapi import FastAPI, Depends from pydantic import BaseModel from sqlalchemy.orm import Session from db_conn import engineconn from db_class import Test app = FastAPI() engine = engineconn() # 依赖函数:为每个请求创建新会话,请求结束后自动关闭 def get_db(): db = engine.sessionmaker() try: yield db finally: db.close() class Item(BaseModel): name: str number: int @app.get("/") async def first_get(db: Session = Depends(get_db)): # 使用请求级别的会话查询,避免缓存 example = db.query(Test).all() return example @app.post("/post") async def first_post(item: Item, db: Session = Depends(get_db)): addMemo = Test(name=item.name, number=item.number) db.add(addMemo) db.commit() db.refresh(addMemo) # 可选:返回包含数据库自动生成字段的最新对象 return item
2. 验证效果
修改后,每个请求都会获取全新的数据库会话,查询时直接从数据库读取最新数据,彻底解决缓存导致的不一致问题。即使多Worker进程运行,每个请求的会话都是独立的,不会出现数据不同步的情况。
内容的提问来源于stack exchange,提问作者Chang yong Park
相关产品推荐
相关产品推荐

