update:1.更新readme.txt
This commit is contained in:
+43
-52
@@ -11,19 +11,21 @@ APP_NAME=MuMuAINovel
|
||||
APP_VERSION=1.0.0
|
||||
APP_HOST=0.0.0.0
|
||||
APP_PORT=8000
|
||||
DEBUG=True
|
||||
DEBUG=false
|
||||
TZ=Asia/Shanghai
|
||||
|
||||
# ==========================================
|
||||
# 数据库配置
|
||||
# PostgreSQL 数据库配置
|
||||
# ==========================================
|
||||
|
||||
# 选项1: PostgreSQL(生产环境推荐)
|
||||
# DATABASE_URL=postgresql+asyncpg://username:password@localhost:5432/database_name
|
||||
# 示例:
|
||||
# DATABASE_URL=postgresql+asyncpg://mumuai:your_password@localhost:5432/mumuai_novel
|
||||
# PostgreSQL 连接信息
|
||||
POSTGRES_DB=mumuai_novel
|
||||
POSTGRES_USER=mumuai
|
||||
POSTGRES_PASSWORD=your_secure_password_here
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
# 选项2: SQLite(开发环境,默认)
|
||||
DATABASE_URL=sqlite+aiosqlite:///data/ai_story.db
|
||||
# 数据库连接 URL(Docker 部署时自动生成)
|
||||
DATABASE_URL=postgresql+asyncpg://mumuai:your_secure_password_here@localhost:5432/mumuai_novel
|
||||
|
||||
# PostgreSQL 连接池配置(优化后,支持80-150并发用户)
|
||||
DATABASE_POOL_SIZE=30 # 核心连接数(默认30,小团队可用20)
|
||||
@@ -37,73 +39,69 @@ DATABASE_POOL_USE_LIFO=True # 使用LIFO策略提高连接复用率
|
||||
DATABASE_SESSION_MAX_ACTIVE=50 # 活跃会话警告阈值
|
||||
DATABASE_SESSION_LEAK_THRESHOLD=100 # 会话泄漏严重告警阈值
|
||||
|
||||
# SQLite 性能优化配置(仅在使用SQLite时生效)
|
||||
SQLITE_CACHE_SIZE_MB=128 # SQLite缓存大小(MB),默认128
|
||||
SQLITE_MMAP_SIZE_MB=256 # 内存映射I/O大小(MB),默认256
|
||||
SQLITE_WAL_AUTOCHECKPOINT=1000 # WAL自动检查点间隔
|
||||
|
||||
# 数据库监控配置
|
||||
DATABASE_ENABLE_SLOW_QUERY_LOG=True # 启用慢查询日志
|
||||
DATABASE_SLOW_QUERY_THRESHOLD=1.0 # 慢查询阈值(秒)
|
||||
DATABASE_ENABLE_METRICS=True # 启用性能指标收集
|
||||
|
||||
# ==========================================
|
||||
# 代理配置(可选)
|
||||
# ==========================================
|
||||
# HTTP_PROXY=http://your-proxy:port
|
||||
# HTTPS_PROXY=http://your-proxy:port
|
||||
# NO_PROXY=localhost,127.0.0.1
|
||||
|
||||
# ==========================================
|
||||
# 日志配置
|
||||
# ==========================================
|
||||
LOG_LEVEL=INFO
|
||||
LOG_TO_FILE=True
|
||||
LOG_TO_FILE=true
|
||||
LOG_FILE_PATH=logs/app.log
|
||||
LOG_MAX_BYTES=10485760
|
||||
LOG_BACKUP_COUNT=30
|
||||
|
||||
# ==========================================
|
||||
# CORS配置
|
||||
# CORS 配置
|
||||
# ==========================================
|
||||
CORS_ORIGINS=["http://localhost:8000","http://127.0.0.1:8000"]
|
||||
|
||||
# ==========================================
|
||||
# AI服务配置
|
||||
# AI 服务配置(至少配置一个)
|
||||
# ==========================================
|
||||
|
||||
# OpenAI配置
|
||||
# OpenAI 配置
|
||||
OPENAI_API_KEY=your_openai_api_key_here
|
||||
OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# 或使用兼容的API服务(如DeepSeek)
|
||||
# OPENAI_BASE_URL=https://api.deepseek.com/v1
|
||||
|
||||
# Gemini配置(可选)
|
||||
# GEMINI_API_KEY=your_gemini_api_key_here
|
||||
# GEMINI_BASE_URL=https://generativelanguage.googleapis.com
|
||||
|
||||
# Anthropic配置(可选)
|
||||
# Anthropic 配置(可选)
|
||||
# ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||
# ANTHROPIC_BASE_URL=https://api.anthropic.com
|
||||
|
||||
# 默认AI配置
|
||||
# 默认 AI 配置
|
||||
DEFAULT_AI_PROVIDER=openai
|
||||
DEFAULT_MODEL=gpt-4
|
||||
DEFAULT_MODEL=gpt-4o-mini
|
||||
DEFAULT_TEMPERATURE=0.7
|
||||
DEFAULT_MAX_TOKENS=2000
|
||||
|
||||
# ==========================================
|
||||
# LinuxDO OAuth2 配置(可选)
|
||||
# LinuxDO OAuth 配置(可选)
|
||||
# ==========================================
|
||||
# LINUXDO_CLIENT_ID=your_client_id
|
||||
# LINUXDO_CLIENT_SECRET=your_client_secret
|
||||
# LINUXDO_CLIENT_ID=your_client_id_here
|
||||
# LINUXDO_CLIENT_SECRET=your_client_secret_here
|
||||
# LINUXDO_REDIRECT_URI=http://localhost:8000/api/auth/callback
|
||||
|
||||
# 前端URL(OAuth回调后重定向)
|
||||
# 前端 URL(OAuth 回调后重定向)
|
||||
FRONTEND_URL=http://localhost:8000
|
||||
|
||||
# 初始管理员(LinuxDO user_id)
|
||||
# INITIAL_ADMIN_LINUXDO_ID=12345
|
||||
# INITIAL_ADMIN_LINUXDO_ID=your_linuxdo_user_id
|
||||
|
||||
# ==========================================
|
||||
# 本地账户登录配置
|
||||
# ==========================================
|
||||
LOCAL_AUTH_ENABLED=True
|
||||
LOCAL_AUTH_ENABLED=true
|
||||
LOCAL_AUTH_USERNAME=admin
|
||||
LOCAL_AUTH_PASSWORD=admin123
|
||||
LOCAL_AUTH_PASSWORD=your_secure_password_here
|
||||
LOCAL_AUTH_DISPLAY_NAME=本地管理员
|
||||
|
||||
# ==========================================
|
||||
@@ -113,28 +111,21 @@ SESSION_EXPIRE_MINUTES=120
|
||||
SESSION_REFRESH_THRESHOLD_MINUTES=30
|
||||
|
||||
# ==========================================
|
||||
# 部署配置说明
|
||||
# 部署配置示例
|
||||
# ==========================================
|
||||
|
||||
# 生产环境 PostgreSQL 配置示例(50-100并发用户):
|
||||
# DATABASE_URL=postgresql+asyncpg://mumuai:SecurePassword123@db.example.com:5432/mumuai_prod
|
||||
# DATABASE_POOL_SIZE=30
|
||||
# DATABASE_MAX_OVERFLOW=20
|
||||
# DATABASE_POOL_TIMEOUT=60
|
||||
# DATABASE_POOL_RECYCLE=1800
|
||||
# DATABASE_SESSION_MAX_ACTIVE=50
|
||||
# DEBUG=False
|
||||
# LOG_LEVEL=WARNING
|
||||
|
||||
# 高并发环境 PostgreSQL 配置示例(100+并发用户):
|
||||
# DATABASE_URL=postgresql+asyncpg://mumuai:SecurePassword123@db.example.com:5432/mumuai_prod
|
||||
# Docker 生产环境配置:
|
||||
# POSTGRES_PASSWORD=your_very_secure_password
|
||||
# DATABASE_POOL_SIZE=40
|
||||
# DATABASE_MAX_OVERFLOW=30
|
||||
# DATABASE_SESSION_MAX_ACTIVE=80
|
||||
# DATABASE_SESSION_LEAK_THRESHOLD=150
|
||||
# DEBUG=false
|
||||
# LOG_LEVEL=WARNING
|
||||
|
||||
# Docker 部署配置示例:
|
||||
# DATABASE_URL=postgresql+asyncpg://mumuai:password@postgres:5432/mumuai_novel
|
||||
# OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# 外网访问配置:
|
||||
# FRONTEND_URL=https://your-domain.com
|
||||
# LINUXDO_REDIRECT_URI=https://your-domain.com/api/auth/callback
|
||||
# LINUXDO_REDIRECT_URI=https://your-domain.com/api/auth/callback
|
||||
# APP_PORT=8000
|
||||
|
||||
# 中转 API 配置示例:
|
||||
# OPENAI_BASE_URL=https://api.new-api.com/v1
|
||||
# DEFAULT_MODEL=gpt-4o-mini
|
||||
+5
-14
@@ -13,15 +13,11 @@ DATA_DIR.mkdir(exist_ok=True)
|
||||
# 配置模块使用标准logging(在logger.py初始化之前)
|
||||
config_logger = logging.getLogger(__name__)
|
||||
|
||||
# 数据库配置:支持PostgreSQL和SQLite
|
||||
# 优先使用环境变量DATABASE_URL,否则使用SQLite
|
||||
DB_FILE = DATA_DIR / "ai_story.db"
|
||||
DEFAULT_SQLITE_URL = f"sqlite+aiosqlite:///{str(DB_FILE.absolute()).replace(chr(92), '/')}"
|
||||
# 数据库配置:PostgreSQL
|
||||
# 从环境变量获取数据库URL
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://mumuai:password@localhost:5432/mumuai_novel")
|
||||
|
||||
# 从环境变量获取数据库URL,如果未设置则使用SQLite
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", DEFAULT_SQLITE_URL)
|
||||
|
||||
config_logger.debug(f"数据库类型: {'PostgreSQL' if 'postgresql' in DATABASE_URL else 'SQLite'}")
|
||||
config_logger.debug(f"数据库类型: PostgreSQL")
|
||||
config_logger.debug(f"数据库URL: {DATABASE_URL}")
|
||||
|
||||
class Settings(BaseSettings):
|
||||
@@ -44,7 +40,7 @@ class Settings(BaseSettings):
|
||||
# CORS配置
|
||||
cors_origins: list[str] = ["http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
|
||||
# 数据库配置 - 支持PostgreSQL和SQLite
|
||||
# 数据库配置 - PostgreSQL
|
||||
database_url: str = DATABASE_URL
|
||||
|
||||
# PostgreSQL连接池配置(优化后支持80-150并发用户)
|
||||
@@ -59,11 +55,6 @@ class Settings(BaseSettings):
|
||||
database_session_max_active: int = 50 # 活跃会话警告阈值(从100降低到50)
|
||||
database_session_leak_threshold: int = 100 # 会话泄漏严重告警阈值
|
||||
|
||||
# SQLite优化配置
|
||||
sqlite_cache_size_mb: int = 128 # SQLite缓存大小MB(从64提升到128)
|
||||
sqlite_mmap_size_mb: int = 256 # 内存映射I/O大小MB
|
||||
sqlite_wal_autocheckpoint: int = 1000 # WAL自动检查点间隔
|
||||
|
||||
# 数据库监控配置
|
||||
database_enable_slow_query_log: bool = True # 启用慢查询日志
|
||||
database_slow_query_threshold: float = 1.0 # 慢查询阈值(秒)
|
||||
|
||||
+42
-104
@@ -1,11 +1,10 @@
|
||||
"""数据库连接和会话管理 - 支持多用户数据隔离"""
|
||||
"""数据库连接和会话管理 - PostgreSQL 多用户数据隔离"""
|
||||
import asyncio
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
from sqlalchemy import select, text
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||
from sqlalchemy.orm import declarative_base
|
||||
from sqlalchemy.pool import StaticPool
|
||||
from fastapi import Request, HTTPException
|
||||
from app.config import settings
|
||||
from app.logger import get_logger
|
||||
@@ -46,9 +45,7 @@ _session_stats = {
|
||||
async def get_engine(user_id: str):
|
||||
"""获取或创建用户专属的数据库引擎(线程安全)
|
||||
|
||||
支持PostgreSQL和SQLite两种数据库:
|
||||
- PostgreSQL: 所有用户共享一个数据库,通过user_id字段隔离数据
|
||||
- SQLite: 每个用户一个独立的数据库文件
|
||||
PostgreSQL: 所有用户共享一个数据库,通过user_id字段隔离数据
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
@@ -57,99 +54,45 @@ async def get_engine(user_id: str):
|
||||
用户专属的异步引擎
|
||||
"""
|
||||
# PostgreSQL模式:所有用户共享同一个引擎
|
||||
if "postgresql" in settings.database_url:
|
||||
cache_key = "shared_postgres"
|
||||
if cache_key in _engine_cache:
|
||||
return _engine_cache[cache_key]
|
||||
|
||||
async with _cache_lock:
|
||||
if cache_key not in _engine_cache:
|
||||
# 优化后的PostgreSQL连接配置
|
||||
connect_args = {
|
||||
"server_settings": {
|
||||
"application_name": settings.app_name,
|
||||
"jit": "off", # 关闭JIT以提高短查询性能
|
||||
},
|
||||
"command_timeout": 60, # 命令超时60秒
|
||||
"statement_cache_size": 500, # 启用语句缓存,提升重复查询性能
|
||||
}
|
||||
|
||||
engine = create_async_engine(
|
||||
settings.database_url,
|
||||
echo=False, # 生产环境关闭SQL日志
|
||||
future=True,
|
||||
pool_size=settings.database_pool_size, # 核心连接数:30
|
||||
max_overflow=settings.database_max_overflow, # 溢出连接数:20
|
||||
pool_timeout=settings.database_pool_timeout, # 连接超时:60秒
|
||||
pool_pre_ping=settings.database_pool_pre_ping, # 连接前检测
|
||||
pool_recycle=settings.database_pool_recycle, # 连接回收:1800秒
|
||||
pool_use_lifo=settings.database_pool_use_lifo, # LIFO策略提高复用
|
||||
connect_args=connect_args
|
||||
)
|
||||
_engine_cache[cache_key] = engine
|
||||
logger.info(
|
||||
f"✅ PostgreSQL引擎已创建(优化配置)\n"
|
||||
f" ├─ 连接池: {settings.database_pool_size} 核心 + {settings.database_max_overflow} 溢出 = {settings.database_pool_size + settings.database_max_overflow} 总连接\n"
|
||||
f" ├─ 超时: {settings.database_pool_timeout}秒\n"
|
||||
f" ├─ 回收: {settings.database_pool_recycle}秒\n"
|
||||
f" ├─ 策略: LIFO(提高复用率)\n"
|
||||
f" └─ 预估并发: 80-150用户"
|
||||
)
|
||||
|
||||
return _engine_cache[cache_key]
|
||||
|
||||
# SQLite模式:每个用户独立的数据库文件
|
||||
if user_id in _engine_cache:
|
||||
return _engine_cache[user_id]
|
||||
cache_key = "shared_postgres"
|
||||
if cache_key in _engine_cache:
|
||||
return _engine_cache[cache_key]
|
||||
|
||||
async with _cache_lock:
|
||||
if user_id not in _engine_locks:
|
||||
_engine_locks[user_id] = asyncio.Lock()
|
||||
user_lock = _engine_locks[user_id]
|
||||
|
||||
async with user_lock:
|
||||
if user_id not in _engine_cache:
|
||||
db_url = f"sqlite+aiosqlite:///data/ai_story_user_{user_id}.db"
|
||||
engine = create_async_engine(
|
||||
db_url,
|
||||
echo=False,
|
||||
future=True,
|
||||
poolclass=StaticPool,
|
||||
pool_pre_ping=True,
|
||||
pool_recycle=3600,
|
||||
connect_args={
|
||||
"timeout": 30,
|
||||
"check_same_thread": False
|
||||
}
|
||||
)
|
||||
if cache_key not in _engine_cache:
|
||||
# 优化后的PostgreSQL连接配置
|
||||
connect_args = {
|
||||
"server_settings": {
|
||||
"application_name": settings.app_name,
|
||||
"jit": "off", # 关闭JIT以提高短查询性能
|
||||
},
|
||||
"command_timeout": 60, # 命令超时60秒
|
||||
"statement_cache_size": 500, # 启用语句缓存,提升重复查询性能
|
||||
}
|
||||
|
||||
try:
|
||||
# 应用优化后的SQLite配置
|
||||
cache_size = -1024 * settings.sqlite_cache_size_mb # 负数表示KB单位
|
||||
mmap_size = settings.sqlite_mmap_size_mb * 1024 * 1024 # 转换为字节
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.execute(text("PRAGMA journal_mode=WAL"))
|
||||
await conn.execute(text("PRAGMA synchronous=NORMAL"))
|
||||
await conn.execute(text(f"PRAGMA cache_size={cache_size}")) # 128MB缓存
|
||||
await conn.execute(text(f"PRAGMA mmap_size={mmap_size}")) # 256MB内存映射
|
||||
await conn.execute(text("PRAGMA temp_store=MEMORY"))
|
||||
await conn.execute(text("PRAGMA busy_timeout=5000"))
|
||||
await conn.execute(text(f"PRAGMA wal_autocheckpoint={settings.sqlite_wal_autocheckpoint}"))
|
||||
|
||||
logger.info(
|
||||
f"✅ 用户 {user_id} 的SQLite数据库已优化\n"
|
||||
f" ├─ WAL模式\n"
|
||||
f" ├─ 缓存: {settings.sqlite_cache_size_mb}MB\n"
|
||||
f" ├─ 内存映射: {settings.sqlite_mmap_size_mb}MB\n"
|
||||
f" └─ 预估并发: 15-20写入用户"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ 用户 {user_id} SQLite数据库优化失败: {str(e)}")
|
||||
_engine_cache[user_id] = engine
|
||||
logger.info(f"为用户 {user_id} 创建SQLite数据库引擎")
|
||||
engine = create_async_engine(
|
||||
settings.database_url,
|
||||
echo=False, # 生产环境关闭SQL日志
|
||||
future=True,
|
||||
pool_size=settings.database_pool_size, # 核心连接数:30
|
||||
max_overflow=settings.database_max_overflow, # 溢出连接数:20
|
||||
pool_timeout=settings.database_pool_timeout, # 连接超时:60秒
|
||||
pool_pre_ping=settings.database_pool_pre_ping, # 连接前检测
|
||||
pool_recycle=settings.database_pool_recycle, # 连接回收:1800秒
|
||||
pool_use_lifo=settings.database_pool_use_lifo, # LIFO策略提高复用
|
||||
connect_args=connect_args
|
||||
)
|
||||
_engine_cache[cache_key] = engine
|
||||
logger.info(
|
||||
f"✅ PostgreSQL引擎已创建(优化配置)\n"
|
||||
f" ├─ 连接池: {settings.database_pool_size} 核心 + {settings.database_max_overflow} 溢出 = {settings.database_pool_size + settings.database_max_overflow} 总连接\n"
|
||||
f" ├─ 超时: {settings.database_pool_timeout}秒\n"
|
||||
f" ├─ 回收: {settings.database_pool_recycle}秒\n"
|
||||
f" ├─ 策略: LIFO(提高复用率)\n"
|
||||
f" └─ 预估并发: 80-150用户"
|
||||
)
|
||||
|
||||
return _engine_cache[user_id]
|
||||
return _engine_cache[cache_key]
|
||||
|
||||
|
||||
async def get_db(request: Request):
|
||||
@@ -411,7 +354,7 @@ async def get_database_stats():
|
||||
"engine_keys": list(_engine_cache.keys()),
|
||||
},
|
||||
"config": {
|
||||
"database_type": "PostgreSQL" if "postgresql" in settings.database_url else "SQLite",
|
||||
"database_type": "PostgreSQL",
|
||||
"pool_size": settings.database_pool_size,
|
||||
"max_overflow": settings.database_max_overflow,
|
||||
"total_connections": settings.database_pool_size + settings.database_max_overflow,
|
||||
@@ -469,19 +412,14 @@ async def check_database_health(user_id: str = None) -> dict:
|
||||
|
||||
try:
|
||||
# 检查引擎是否存在
|
||||
cache_key = "shared_postgres"
|
||||
if user_id:
|
||||
engine = await get_engine(user_id)
|
||||
cache_key = user_id
|
||||
else:
|
||||
if "postgresql" in settings.database_url:
|
||||
cache_key = "shared_postgres"
|
||||
if cache_key not in _engine_cache:
|
||||
result["checks"]["engine"] = {"status": "not_initialized", "healthy": True}
|
||||
return result
|
||||
engine = _engine_cache[cache_key]
|
||||
else:
|
||||
result["checks"]["engine"] = {"status": "skipped", "message": "需要提供user_id检查SQLite"}
|
||||
if cache_key not in _engine_cache:
|
||||
result["checks"]["engine"] = {"status": "not_initialized", "healthy": True}
|
||||
return result
|
||||
engine = _engine_cache[cache_key]
|
||||
|
||||
# 测试数据库连接
|
||||
AsyncSessionLocal = async_sessionmaker(
|
||||
|
||||
@@ -5,9 +5,8 @@ python-multipart==0.0.20
|
||||
|
||||
# 数据库
|
||||
sqlalchemy==2.0.25
|
||||
aiosqlite==0.19.0 # SQLite支持(保留用于开发环境)
|
||||
asyncpg==0.29.0 # PostgreSQL异步驱动(生产环境)
|
||||
psycopg2-binary==2.9.9 # PostgreSQL同步驱动(备用)
|
||||
asyncpg==0.29.0 # PostgreSQL异步驱动
|
||||
psycopg2-binary==2.9.9 # PostgreSQL同步驱动(用于迁移脚本)
|
||||
|
||||
# 数据验证
|
||||
pydantic==2.12.4
|
||||
|
||||
Reference in New Issue
Block a user