推理算力需求反超训练:数据库面临新压力模型
启明创投在WAIC 2026期间披露,2026年AI推理算力需求已反超训练算力,推理服务在算力消耗中的占比从2024年的35%攀升至62%。推理场景的特征是高并发、低延迟、短事务,这与传统数据库面向批处理和长事务优化的方向截然不同。推理服务每次请求可能涉及模型元数据查询、用户上下文加载、对话历史检索、Token计费记录写入,这四类操作对数据库的读写模式提出了新的要求。
推理服务数据库访问模式分析
一次AI推理请求的数据库交互链路:
| 阶段 | 操作类型 | 延迟要求 | 数据特征 |
|---|---|---|---|
| 模型元数据加载 | 读 | <5ms | 读多写少,变更频率低 |
| 用户上下文加载 | 读 | <10ms | 按用户ID精准查询 |
| 对话历史检索 | 读 | <20ms | 按会话ID范围查询,数据量大 |
| Token计费记录 | 写 | <50ms | 高并发写入,可异步 |
关键发现:4次数据库交互中有3次是读操作,1次是写操作。读操作需要极低延迟(5-20ms),写操作可以容忍更高延迟(50ms+)。这种读多写少的模式天然适合引入Redis缓存层。
Redis缓存策略:对话历史的热数据分层
对话历史是最频繁访问的数据,但不是所有历史都需要缓存。基于会话活跃度分层的缓存策略:
import redis
import json
from datetime import timedelta
class ConversationCache:
def __init__(self, redis_client: redis.Redis):
self.r = redis_client
self.hot_ttl = timedelta(hours=2) # 活跃会话缓存2小时
self.warm_ttl = timedelta(hours=24) # 近期会话缓存24小时
def get_conversation(self, session_id: str) -> list:
"""获取对话历史,优先从缓存读取"""
cache_key = f"conv:{session_id}"
cached = self.r.get(cache_key)
if cached:
# 命中缓存,续期TTL
self.r.expire(cache_key, self.hot_ttl)
return json.loads(cached)
# 缓存未命中,从MySQL加载
messages = self._load_from_mysql(session_id)
if messages:
self.r.setex(cache_key, self.hot_ttl, json.dumps(messages))
return messages
def append_message(self, session_id: str, role: str, content: str):
"""追加消息到对话历史"""
cache_key = f"conv:{session_id}"
# 方案1:直接读-改-写(适合短对话)
cached = self.r.get(cache_key)
if cached:
messages = json.loads(cached)
messages.append({"role": role, "content": content})
self.r.setex(cache_key, self.hot_ttl, json.dumps(messages))
# 方案2:用Redis List实现追加(适合长对话,避免全量读写)
msg_key = f"conv:msgs:{session_id}"
self.r.rpush(msg_key, json.dumps({"role": role, "content": content}))
self.r.expire(msg_key, self.hot_ttl)
def _load_from_mysql(self, session_id: str) -> list:
# 实际项目中替换为ORM查询
pass
Redis List方案比全量JSON读写更高效:每次追加消息只需RPUSH一条记录,无需读取和反序列化完整对话。但需要注意Redis List不支持中间删除,如果需要编辑历史消息,仍需用JSON方案。
MySQL分表策略:对话历史按月分表应对数据膨胀
对话历史表是增长最快的数据源。日均100万次推理请求、每次请求平均产生10条消息记录,每日新增1000万行。单表超过5000万行后查询性能显著下降,按月分表是必要的:
-- 对话历史分表DDL
CREATE TABLE conversation_messages_202608 (
id BIGINT AUTO_INCREMENT,
session_id VARCHAR(36) NOT NULL,
role ENUM('system', 'user', 'assistant', 'tool') NOT NULL,
content MEDIUMTEXT NOT NULL,
token_count INT DEFAULT 0,
model VARCHAR(64) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_session (session_id, created_at),
INDEX idx_created (created_at)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
-- 应用层路由函数
def get_table_name(date=None):
if date is None:
date = datetime.now()
return f"conversation_messages_{date.strftime('%Y%m')}"
-- 查询跨月对话时自动合并
def query_conversation(session_id: str, start_date, end_date) -> list:
"""跨月查询对话历史"""
results = []
current = start_date.replace(day=1)
while current <= end_date:
table = get_table_name(current)
try:
rows = db.execute(
f"SELECT * FROM {table} "
f"WHERE session_id = %s AND created_at BETWEEN %s AND %s "
f"ORDER BY created_at",
(session_id, start_date, end_date)
)
results.extend(rows)
except TableNotFoundError:
pass # 该月分表不存在,跳过
current += timedelta(days=32)
current = current.replace(day=1)
return sorted(results, key=lambda x: x['created_at'])
ROW_FORMAT=COMPRESSED配合KEY_BLOCK_SIZE=8可将存储空间压缩50%以上。对话内容以文本为主,压缩比高,对CPU开销影响在1-2%以内。
Token计费记录的异步写入方案
Token计费是唯一的高并发写操作,不适合同步写入MySQL。用消息队列+批量写入方案:
import asyncio
from collections import defaultdict
class TokenBillingWriter:
def __init__(self, db_pool, batch_size=500, flush_interval=5.0):
self.db = db_pool
self.buffer = []
self.batch_size = batch_size
self.flush_interval = flush_interval
self._lock = asyncio.Lock()
async def record(self, record: dict):
"""异步追加计费记录"""
async with self._lock:
self.buffer.append(record)
if len(self.buffer) >= self.batch_size:
await self._flush()
async def _flush(self):
"""批量写入数据库"""
if not self.buffer:
return
records = self.buffer[:]
self.buffer.clear()
# 批量INSERT
values = []
placeholders = []
for r in records:
placeholders.append("(%s, %s, %s, %s, %s)")
values.extend([
r['user_id'], r['model'], r['input_tokens'],
r['output_tokens'], r['cost_cny']
])
sql = f"""
INSERT INTO token_billing
(user_id, model, input_tokens, output_tokens, cost_cny)
VALUES {','.join(placeholders)}
"""
try:
await self.db.execute(sql, values)
except Exception as e:
# 写入失败,回滚到buffer头部等待重试
self.buffer = records + self.buffer
raise
async def start_periodic_flush(self):
"""定时刷新缓冲区"""
while True:
await asyncio.sleep(self.flush_interval)
async with self._lock:
await self._flush()
批量INSERT比逐条INSERT性能提升10-50倍。500条一批在MySQL单次事务中完成,减少事务提交开销和binlog写入量。
数据库高可用:推理服务的容错底线
推理服务对数据库可用性的容忍度极低——模型元数据查询失败直接导致请求报错。数据库高可用配置要点:
- 主从复制延迟:从库读对话历史时设置1秒超时,超时则切回主库读
- Redis集群:至少3主3从,单节点故障不影响缓存读取
- 读写分离路由:计费写操作走主库,对话历史读操作走从库+Redis
- 连接池配置:max_connections=200,idle_timeout=300s,避免连接风暴
推理算力占比的持续攀升不会逆转。数据库架构从训练导向转向推理导向,核心变化是读路径极致优化+写路径异步化。这条路线调整越早,推理服务的稳定性越有保障。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/ai-tui-li-suan-li-fan-chao-xun-lian-suan-li-tui-li-you-xian/