feat(redis): refactor Redis configuration to use multiple logical databases

- Updated default REDIS_URL to remove explicit /0 suffix
- Added dedicated Redis clients:
  - db0: general cache (redis_client)
  - db1: message cache (redis_message_client)
  - db2: binary storage (redis_binary_client)
  - db3: rate limiting (redis_rate_limit_client)
- Updated configuration, Docker files, and main startup lifecycle accordingly
- Replaced `get_redis()` usage in notification server with `redis_message_client`
This commit is contained in:
MingxuanGame
2025-10-04 05:39:59 +00:00
parent c2bfafc67a
commit 216d3ab3bf
7 changed files with 53 additions and 27 deletions

View File

@@ -6,7 +6,7 @@ MYSQL_DATABASE="osu_api"
MYSQL_USER="osu_api" MYSQL_USER="osu_api"
MYSQL_PASSWORD="password" MYSQL_PASSWORD="password"
MYSQL_ROOT_PASSWORD="password" MYSQL_ROOT_PASSWORD="password"
REDIS_URL="redis://127.0.0.1:6379/0" REDIS_URL="redis://127.0.0.1:6379"
# JWT Settings # JWT Settings
# Use `openssl rand -hex 32` to generate a secure key # Use `openssl rand -hex 32` to generate a secure key

View File

@@ -141,7 +141,7 @@ STORAGE_SETTINGS='{
] ]
redis_url: Annotated[ redis_url: Annotated[
str, str,
Field(default="redis://127.0.0.1:6379/0", description="Redis 连接 URL"), Field(default="redis://127.0.0.1:6379", description="Redis 连接 URL"),
"数据库设置", "数据库设置",
] ]

View File

@@ -35,13 +35,16 @@ engine = create_async_engine(
) )
# Redis 连接 # Redis 连接
redis_client = redis.from_url(settings.redis_url, decode_responses=True) redis_client = redis.from_url(settings.redis_url, decode_responses=True, db=0)
# Redis 二进制数据连接 (不自动解码响应,用于存储音频等二进制数据)
redis_binary_client = redis.from_url(settings.redis_url, decode_responses=False)
# Redis 消息缓存连接 (db1) # Redis 消息缓存连接 (db1)
redis_message_client: redis.Redis = redis.from_url(settings.redis_url, decode_responses=True, db=1) redis_message_client = redis.from_url(settings.redis_url, decode_responses=True, db=1)
# Redis 二进制数据连接 (不自动解码响应用于存储音频等二进制数据db2)
redis_binary_client = redis.from_url(settings.redis_url, decode_responses=False, db=2)
# Redis 限流连接 (db3)
redis_rate_limit_client = redis.from_url(settings.redis_url, decode_responses=True, db=3)
# 数据库依赖 # 数据库依赖

View File

@@ -8,7 +8,7 @@ from app.dependencies.database import (
DBFactory, DBFactory,
Redis, Redis,
get_db_factory, get_db_factory,
get_redis, redis_message_client,
with_db, with_db,
) )
from app.dependencies.user import get_current_user_and_token from app.dependencies.user import get_current_user_and_token
@@ -31,7 +31,7 @@ class ChatServer:
def __init__(self): def __init__(self):
self.connect_client: dict[int, WebSocket] = {} self.connect_client: dict[int, WebSocket] = {}
self.channels: dict[int, list[int]] = {} self.channels: dict[int, list[int]] = {}
self.redis: Redis = get_redis() self.redis: Redis = redis_message_client
self.tasks: set[asyncio.Task] = set() self.tasks: set[asyncio.Task] = set()
self.ChatSubscriber = ChatSubscriber() self.ChatSubscriber = ChatSubscriber()

View File

@@ -11,7 +11,7 @@ services:
environment: environment:
- MYSQL_HOST=mysql - MYSQL_HOST=mysql
- MYSQL_PORT=3306 - MYSQL_PORT=3306
- REDIS_URL=redis://redis:6379/0 - REDIS_URL=redis://redis:6379
- ENABLE_OSU_RX=true - ENABLE_OSU_RX=true
- ENABLE_OSU_AP=true - ENABLE_OSU_AP=true
- ENABLE_ALL_MODS_PP=true - ENABLE_ALL_MODS_PP=true

View File

@@ -13,7 +13,7 @@ services:
environment: environment:
- MYSQL_HOST=mysql - MYSQL_HOST=mysql
- MYSQL_PORT=3306 - MYSQL_PORT=3306
- REDIS_URL=redis://redis:6379/0 - REDIS_URL=redis://redis:6379
env_file: env_file:
- .env - .env
depends_on: depends_on:

55
main.py
View File

@@ -4,7 +4,14 @@ from pathlib import Path
from app.config import settings from app.config import settings
from app.database import User from app.database import User
from app.dependencies.database import Database, engine, get_redis, redis_client from app.dependencies.database import (
Database,
engine,
redis_binary_client,
redis_client,
redis_message_client,
redis_rate_limit_client,
)
from app.dependencies.fetcher import get_fetcher from app.dependencies.fetcher import get_fetcher
from app.dependencies.scheduler import start_scheduler, stop_scheduler from app.dependencies.scheduler import start_scheduler, stop_scheduler
from app.log import system_logger from app.log import system_logger
@@ -50,39 +57,55 @@ import sentry_sdk
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): # noqa: ARG001 async def lifespan(app: FastAPI): # noqa: ARG001
# on startup # === on startup ===
# init mods and achievements
init_mods() init_mods()
init_ranked_mods() init_ranked_mods()
await FastAPILimiter.init(get_redis()) load_achievements()
fetcher = await get_fetcher() # 初始化 fetcher
await init_geoip() # 初始化 GeoIP 数据库 # init rate limiter
await FastAPILimiter.init(redis_rate_limit_client)
# init fetcher
fetcher = await get_fetcher()
# init GeoIP
await init_geoip()
# init game server
await create_rx_statistics() await create_rx_statistics()
await calculate_user_rank(True) await calculate_user_rank(True)
await daily_challenge_job() await daily_challenge_job()
await process_daily_challenge_top() await process_daily_challenge_top()
await create_banchobot() await create_banchobot()
await start_email_processor() # 启动邮件队列处理器
await download_service.start_health_check() # 启动下载服务健康检查 # services
await start_cache_tasks() # 启动缓存调度器 await start_email_processor()
await download_service.start_health_check()
await start_cache_tasks()
init_beatmapset_update_service(fetcher) # 初始化谱面集更新服务 init_beatmapset_update_service(fetcher) # 初始化谱面集更新服务
redis_message_system.start() # 启动 Redis 消息系统 redis_message_system.start()
load_achievements()
start_scheduler() start_scheduler()
# 显示资源代理状态 # show the status of AssetProxy
if settings.enable_asset_proxy: if settings.enable_asset_proxy:
system_logger("AssetProxy").info(f"Asset Proxy enabled - Domain: {settings.custom_asset_domain}") system_logger("AssetProxy").info(f"Asset Proxy enabled - Domain: {settings.custom_asset_domain}")
# on shutdown
yield yield
# === on shutdown ===
# stop services
bg_tasks.stop() bg_tasks.stop()
redis_message_system.stop() # 停止 Redis 消息系统 await stop_cache_tasks()
await stop_cache_tasks() # 停止缓存调度器
stop_scheduler() stop_scheduler()
await download_service.stop_health_check() # 停止下载服务健康检查 await download_service.stop_health_check()
await stop_email_processor() # 停止邮件队列处理器 await stop_email_processor()
# close database & redis
await engine.dispose() await engine.dispose()
await redis_client.aclose() await redis_client.aclose()
await redis_binary_client.aclose()
await redis_message_client.aclose()
await redis_rate_limit_client.aclose()
desc = f"""osu! API 模拟服务器,支持 osu! API v1, v2 和 osu!lazer 的绝大部分功能。 desc = f"""osu! API 模拟服务器,支持 osu! API v1, v2 和 osu!lazer 的绝大部分功能。