feat: 添加Gunicorn配置优化并改进Docker构建配置

- 新增 gunicorn_conf.py 配置文件,实现:
  - GC冻结优化以改善Copy-on-Write内存共享
  - Worker RSS内存监控日志
  - 添加 --max-requests 和 --max-requests-jitter 防止内存泄漏

- 改进 Dockerfile 配置:
  - 修复 Nginx 静态文件目录权限问题

- 简化 docker-compose 配置:
  - 移除冗余的 PYTHONIOENCODING/LANG/LC_ALL 环境变量
This commit is contained in:
AAEE86
2026-01-29 22:53:42 +08:00
parent c26598c773
commit b0b1bdf158
5 changed files with 26 additions and 8 deletions

View File

@@ -24,10 +24,12 @@ COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/
COPY --from=builder /usr/local/bin/alembic /usr/local/bin/
# 从 builder 阶段复制前端构建产物
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html
# 复制后端代码
COPY src/ ./src/
COPY alembic.ini ./
COPY alembic/ ./alembic/
COPY gunicorn_conf.py ./
# Nginx 配置模板
# 智能处理 IP有外层代理头就透传没有就用直连 IP
RUN printf '%s\n' \
@@ -123,7 +125,7 @@ RUN printf '%s\n' \
'stderr_logfile=/var/log/nginx/error.log' \
'' \
'[program:app]' \
'command=gunicorn src.main:app --preload -w %(ENV_GUNICORN_WORKERS)s -k uvicorn.workers.UvicornWorker --bind 127.0.0.1:8084 --timeout 120 --access-logfile - --error-logfile - --log-level info' \
'command=gunicorn src.main:app -c gunicorn_conf.py --preload -w %(ENV_GUNICORN_WORKERS)s -k uvicorn.workers.UvicornWorker --bind 127.0.0.1:8084 --timeout 120 --max-requests 2000 --max-requests-jitter 100 --access-logfile - --error-logfile - --log-level info' \
'directory=/app' \
'autostart=true' \
'autorestart=true' \

View File

@@ -33,11 +33,13 @@ COPY --from=builder /usr/local/bin/alembic /usr/local/bin/
# 从 builder 阶段复制前端构建产物
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html
# 复制后端代码
COPY src/ ./src/
COPY alembic.ini ./
COPY alembic/ ./alembic/
COPY gunicorn_conf.py ./
# Nginx 配置模板
# 智能处理 IP有外层代理头就透传没有就用直连 IP
@@ -126,7 +128,7 @@ RUN printf '%s\n' \
'stderr_logfile=/var/log/nginx/error.log' \
'' \
'[program:app]' \
'command=gunicorn src.main:app --preload -w %(ENV_GUNICORN_WORKERS)s -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:%(ENV_PORT)s --timeout 120 --access-logfile - --error-logfile - --log-level info' \
'command=gunicorn src.main:app -c gunicorn_conf.py --preload -w %(ENV_GUNICORN_WORKERS)s -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:%(ENV_PORT)s --timeout 120 --max-requests 2000 --max-requests-jitter 100 --access-logfile - --error-logfile - --log-level info' \
'directory=/app' \
'autostart=true' \
'autorestart=true' \

View File

@@ -54,9 +54,6 @@ services:
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-4}
# 容器级别设置
TZ: Asia/Shanghai
PYTHONIOENCODING: utf-8
LANG: C.UTF-8
LC_ALL: C.UTF-8
depends_on:
postgres:
condition: service_healthy

View File

@@ -45,9 +45,6 @@ services:
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-4}
# 容器级别设置
TZ: Asia/Shanghai
PYTHONIOENCODING: utf-8
LANG: C.UTF-8
LC_ALL: C.UTF-8
depends_on:
postgres:
condition: service_healthy

20
gunicorn_conf.py Normal file
View File

@@ -0,0 +1,20 @@
# Gunicorn configuration file
import gc
def when_ready(server):
"""
Called just after the server is started.
Freeze GC before forking workers to optimize Copy-on-Write memory sharing.
"""
gc.freeze()
server.log.info("GC frozen for Copy-on-Write optimization")
server.log.info(f"Objects in permanent generation: {gc.get_freeze_count()}")
def post_fork(server, worker):
try:
import resource
rss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
server.log.info(f"Worker {worker.pid} RSS after fork: {rss} KB")
except ImportError:
pass # Windows 不支持 resource 模块