perf(全链路): 连接池/事务边界/轮询与 IO 效率收口

Java:
- LLM 180s 读超时不再被全局 call-timeout 静默截断成 90s(长思考请求被掐断→重试→付费网关二次计费)
- 代理 HttpClient 缓存改有界 LRU(jikip 每次提取新 IP,无界缓存持续泄漏 selector 线程与连接池)
- 12 个 service 的 Redis 任务锁移出 @Transactional(自旋最坏 10s 白占 DB 连接,池仅 30),远端对象删/传改 afterCommit
- 结果文件 Job 闸门拒绝时不再回退内联执行(改重新入队,避免把背压转嫁给 MQ 消费线程)
- imagevideo 每秒扫描加列投影、过期清理加 LIMIT;权限页整表查询改列投影(不再拉回密码哈希)
- 哈希改 HexFormat;补 5 处"不能改"的技术依据注释(批量插入会丢回填主键、流式丢模板与图片等)

前端:4 个工具页轮询改轻量端点(带 fallback);PriceTrack 快照节流写盘;候选店铺表分页;页面隐藏时停表

客户端:HTTP 连接池按出口复用(Session 仍每请求新建,保持无跨请求状态);品牌检测 WIPO 逐请求握手;
代理配置按 mtime 缓存;串行任务改专属池;异常降级为标签页重连;紫鸟启动改端口轮询;模板编译缓存;
日志上报连接与落盘收口;Flask 版本 API 改按请求复用连接
This commit is contained in:
2026-09-15 23:01:59 +08:00
parent d6f8368493
commit 228d481211
44 changed files with 1550 additions and 423 deletions
+4 -1
View File
@@ -11,7 +11,7 @@ import secrets
from flask import Flask
from flask_cors import CORS
from utils.db import init_db
from utils.db import close_db, init_db
from blueprints.version import version_bp
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -36,6 +36,9 @@ app.secret_key = os.environ.get('SECRET_KEY', secrets.token_hex(32))
# 注册蓝图:仅版本公开 API(管理后台 API 已迁 Java,见模块 docstring
app.register_blueprint(version_bp)
# 请求级数据库连接随请求结束释放(utils/db.get_db 复用同一连接)
app.teardown_appcontext(close_db)
def run_app(host='0.0.0.0', port=15124):
init_db()
+85 -1
View File
@@ -1,9 +1,26 @@
"""
数据库连接与初始化
请求级连接复用:pymysql 每次 connect 都要做一次完整的鉴权握手,而本进程
15124)只服务 /api/version、/api/version/latest 这类轻量查询,握手开销
占了单次请求的大头。连接因此挂在 flask.g 上按请求复用,请求结束由
close_db(注册在 app.teardown_appcontext)统一释放。
"""
import re
import pymysql
try:
from flask import g, has_app_context
except ImportError: # 非 Flask 环境(脚本/离线核查)下退化为每次新建连接
g = None
def has_app_context() -> bool:
return False
# 请求级连接挂在 flask.g 上的属性名(避免与业务字段冲突)
_CONN_ATTR = "_shufu_db_conn"
try:
from config import mysql_host as config_mysql_host
from config import mysql_user as config_mysql_user
@@ -44,7 +61,7 @@ def describe_db_target():
)
def get_db():
def _connect():
return pymysql.connect(
host=mysql_host,
user=mysql_user,
@@ -55,6 +72,73 @@ def get_db():
)
def _is_alive(conn) -> bool:
"""连接可用性探测:已关闭直接判死,否则发一次 COM_PING。
COM_PING 一次往返远小于一次完整鉴权握手;不用 ping(reconnect=True)
(该参数在新版 pymysql 已废弃,且失败时会自行重连、语义不可控)。
"""
try:
if not conn.open:
return False
conn.ping(reconnect=False)
return True
except Exception:
return False
def _close_quietly(conn) -> None:
"""静默关闭连接(可能为 None / 已关闭 / 断连)。"""
if conn is None:
return
try:
conn.close()
except Exception:
pass
def get_db():
"""取当前请求的数据库连接(同一请求内复用,避免每次请求都做鉴权握手)。
连接挂在 flask.g 上,请求结束由 close_db 释放;被服务端 wait_timeout
断开、或调用方提前 close 过,这里都会静默换成新连接,调用方无感知。
无 Flask 应用上下文时(脚本调用)退回每次新建,保持旧行为。
"""
ctx = g if has_app_context() else None
conn = getattr(ctx, _CONN_ATTR, None) if ctx is not None else None
if conn is not None:
if _is_alive(conn):
return conn
# 断连/已被关闭:丢弃旧连接后重建(不把坏连接交给业务查询)
_close_quietly(conn)
try:
delattr(ctx, _CONN_ATTR)
except Exception:
pass
conn = _connect()
if ctx is not None:
setattr(ctx, _CONN_ATTR, conn)
return conn
def close_db(exc=None) -> None:
"""释放当前请求的连接(注册为 app.teardown_appcontext 回调)。
异常路径同样会走 teardown,因此查询抛错时连接不会泄漏到下一次请求。
"""
ctx = g if has_app_context() else None
if ctx is None:
return
conn = getattr(ctx, _CONN_ATTR, None)
if conn is None:
return
try:
delattr(ctx, _CONN_ATTR)
except Exception:
pass
_close_quietly(conn)
def init_db():
"""确保版本公开 API 依赖的最小表结构存在。