后端服务部署.md 31 KB

后端服务部署

本文引用的文件

  • pom.xml
  • ai-gateway/pom.xml
  • ai-server/pom.xml
  • deploy/env.sh
  • ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java
  • ai-server/src/main/java/com/zsjz/ai/App.java
  • ai-gateway/src/main/resources/application.yaml
  • ai-server/src/main/resources/application.yaml
  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java
  • ai-gateway/src/main/java/com/zsjz/gateway/route/LoginRequestFilter.java
  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java
  • ai-server/src/main/java/com/zsjz/ai/common/config/CorsConfig.java
  • ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java

目录

  1. 简介
  2. 项目结构
  3. Maven 编译与打包
  4. 环境变量与启动命令
  5. 网关服务启动流程
  6. 业务服务启动流程
  7. 健康检查行为
  8. 粘性路由职责
  9. 典型部署拓扑
  10. 性能参数调优
  11. 故障排查
  12. 结论

简介

本指南面向生产环境,说明 ai-gateway 与 ai-server 的 Maven 构建、环境变量、启动流程、健康检查、日志位置、粘性路由策略和常见故障。系统由一个 Maven 父工程管理两个 Spring Boot 子模块:

组件 角色 默认端口 对外路径
ai-gateway 按用户粘性转发请求到指定 ai-server 节点 8080 /js/a 前缀的服务配置在 YAML
ai-server 业务后端,承载平台、Agent、清洗、知识图谱、检索等模块 8980 /js/a

网关不复制业务逻辑,只负责解析登录态、选择节点、重写目标地址并流式转发;鉴权、会话、案件数据源都保留在 ai-server。

项目结构

graph TB
    subgraph "Maven 父工程"
        Parent["zsjz-ai<br/>packaging=pom"]
        ServerMod["ai-server"]
        GatewayMod["ai-gateway"]
    end

    subgraph "ai-server 业务进程"
        App["App.java<br/>SpringBootApplication"]
        Cors["CorsConfig.java<br/>跨域过滤器"]
        HealthCtrl["SystemController.java<br/>/sys/health"]
        HealthSvc["SystemHealthService.java<br/>PG/Redis/ES 探测"]
    end

    subgraph "ai-gateway 网关进程"
        GwApp["GatewayApplication.java<br/>SpringBootApplication"]
        LoginFilter["LoginRequestFilter.java<br/>登录预处理"]
        StickyFilter["StickyRouteFilter.java<br/>粘性路由"]
        HealthCheck["HealthChecker.java<br/>节点探活"]
    end

    DB["PostgreSQL"]
    Redis["Redis"]
    ES["Elasticsearch"]
    Neo4j["Neo4j(可选)"]

    Parent --> ServerMod
    Parent --> GatewayMod
    Client["浏览器 / Electron 前端"] --> GwApp
    GwApp --> App
    App --> DB
    App --> Redis
    App --> ES
    App --> Neo4j

图示来源

  • pom.xml:1-23
  • ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java:1-23
  • ai-server/src/main/java/com/zsjz/ai/App.java:1-49
  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java:1-180
  • ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java:32-55
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java:1-200

章节来源

  • pom.xml:1-23

Maven 编译与打包

父工程与模块顺序

根 pom.xml 声明父为 Spring Boot 3.5.16,自身是 packaging=pom,并按以下顺序声明模块:

  1. ai-server
  2. ai-gateway

Maven 聚合构建时按声明顺序处理模块,因此应先编译 ai-server,再编译 ai-gateway。若只构建某个模块,需确保父 POM 可从当前目录解析。

构建产物

模块 构建插件 产物 启动方式
ai-server spring-boot-maven-plugin ai-server/target/ai-server-1.0.jar java -jar ai-server.jar
ai-gateway spring-boot-maven-plugin ai-gateway/target/ai-gateway-1.0.jar java -jar ai-gateway.jar

ai-gateway 还通过 maven-resources-plugin 在 generate-resources 阶段把仓库根的 sql/gateway.sql 复制到 target/classes/db/gateway.sql,供 spring.sql.init 使用。该 DDL 使用幂等建表语句,可重复执行。

推荐构建命令

mvn clean package -DskipTests

生产构建建议跳过测试,避免测试依赖本地开发数据库或外部中间件。若必须运行测试,应提前准备 PostgreSQL、Redis、Elasticsearch 等依赖。

章节来源

  • pom.xml:1-23
  • ai-gateway/pom.xml:1-148

环境变量与启动命令

环境变量文件定位

所有 ai-server 的配置项采用 ${ENV_NAME:默认值} 形式,未设置环境变量时回退到 YAML 默认值。统一变量定义位于 deploy/env.sh。

shell 导入方式

set -a; source deploy/env.sh; set +a
java -jar ai-server.jar
  • set -a:后续 export 形式的赋值自动导出为当前 shell 的环境变量。
  • source deploy/env.sh:加载数据库、Redis、ES、DuckDB、RAG、向量模型等配置。
  • set +a:关闭自动导出,避免污染后续命令。

这种方式适合运维脚本、CI 流水线或临时调试。

systemd EnvironmentFile 方式

systemd 单元中配置:

[Service]
EnvironmentFile=/opt/zsjz-ai/deploy/env.sh
ExecStart=java -jar /opt/zsjz-ai/ai-server.jar

systemd 会读取文件中 KEY="value" 形式的变量并注入进程环境。注意:

  • env.sh 注释明确标注其同时支持上述两种用法。
  • 不要混用 Environment= 与 EnvironmentFile= 重复声明同一变量,否则可能覆盖预期值。
  • SPRING_PROFILES_ACTIVE 由 Spring 原生机制控制,默认 dev;生产可取消注释该行启用正式 profile。

数据库口令权限控制

deploy/env.sh 包含 PostgreSQL、Redis、Neo4j 的连接信息,其中数据库口令属于敏感凭据。部署时必须:

  1. 将 env.sh 放在受控目录,例如 /opt/zsjz-ai/deploy/env.sh。
  2. 仅允许服务账户和运维人员访问:chmod 600 deploy/env.sh。
  3. 不要把该文件提交到公开仓库。
  4. 对 systemd 服务的运行用户限制文件读权限。
  5. 不同环境(开发、预发、生产)分别维护独立副本,不要共用口令。

章节来源

  • deploy/env.sh:1-172

网关服务启动流程

入口类

GatewayApplication 是网关唯一入口,注解包括:

  • @SpringBootApplication:启用自动装配与组件扫描。
  • @EnableScheduling:开启定时任务。
  • @ConfigurationPropertiesScan:扫描 gateway.* 配置属性。

main 方法直接调用 SpringApplication.run(GatewayApplication.class, args)。

关键依赖加载顺序

  1. Spring Boot 初始化 WebFlux/Netty 容器。
  2. 加载 application.yaml,激活 dev profile,并拷贝 gateway.sql。
  3. 初始化 JDBC,执行 classpath:db/gateway.sql 建表。
  4. 初始化 Reactor Redis,用于 token 解析与路由缓存。
  5. 初始化 sa-token Reactor 客户端,从共享 Redis 解析 x-token → loginId。
  6. 启动调度器,HealthChecker 开始轮询节点健康状态。
  7. 应用启动完成后,监听 8080 端口。

重要配置要点

  • 网关端口:server.port=8080。
  • 后端连接超时:connect-timeout=3000ms。
  • 响应头去重:默认添加 DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE,防止后端跨域响应头重复。
  • 网关自身跨域默认关闭,因为后端已有全局 CORS。
  • sa-token 配置(token 名称、超时、并发模式等)必须与 ai-server 一致,否则 token 键位无法解析。

    sequenceDiagram
    participant JVM as "JVM"
    participant Boot as "SpringApplication"
    participant SqlInit as "SQL 初始化"
    participant Redis as "Reactive Redis"
    participant SaToken as "sa-token 客户端"
    participant Scheduler as "调度器"
    participant Health as "HealthChecker"
    
    JVM->>Boot: 启动 GatewayApplication
    Boot->>SqlInit: 执行 gateway.sql
    SqlInit-->>Boot: 建表完成
    Boot->>Redis: 连接 Redis
    Boot->>SaToken: 初始化 token 解析
    Boot->>Scheduler: 启用 @EnableScheduling
    Scheduler->>Health: initialDelay=5s 后首次探活
    Health-->>JVM: 周期探测后端节点
    

图示来源

  • ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java:1-23
  • ai-gateway/src/main/resources/application.yaml:1-81
  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-62

章节来源

  • ai-gateway/src/main/java/com/zsjz/gateway/GatewayApplication.java:1-23
  • ai-gateway/src/main/resources/application.yaml:1-81

业务服务启动流程

入口类

App 是 ai-server 的启动类,注解包括:

  • @Slf4j
  • @EnableScheduling:启用 SSE 心跳、数据源回收等定时任务。
  • @SpringBootApplication

main 方法先打印“开始启动服务...”,再调用 SpringApplication.run(App.class, args)。注释中的 init() 工作空间迁移逻辑当前被注释掉,不影响正常启动。

模块化能力

ai-server 不是按 Spring Module 拆分,而是按业务域组织在 com.zsjz.ai.module 下。启动时由 Spring 自动发现这些包下的控制器、服务、Mapper、配置等组件。主要业务域包括:

模块 职责
plat 平台基础:用户、授权、系统信息、健康检查、文件下载
agent Agent 框架、LLM 调用、RAG、附件解析、Python 执行、洞察会话
aiclean AI 智能清洗、模板向量索引、模板匹配
knowledge 知识库文档与向量索引
graph 图谱相关能力
person 人物关系与亲密度
call 通话记录查询与分析
trans 交易记录查询
track 轨迹与同行分析
govern 治理树、公共配置
search 全文检索封装
dm 数据管理、文件上传、AI 识别
otg 时序数据
external 外部数据接入

关键依赖加载顺序

  1. 加载 application.yaml,端口 8980,上下文路径 /js/a。
  2. 根据 SPRING_PROFILES_ACTIVE 加载 application-dev.yaml 或 application-pro.yaml。
  3. 初始化 Tomcat/Spring MVC。
  4. 注册全局 CORS 过滤器(优先级最高)。
  5. 初始化 PostgreSQL、Redis、Elasticsearch、Neo4j 等外部依赖。
  6. 初始化 MyBatis-Plus、动态数据源、DuckDB 预算与回收器。
  7. 启动定时任务:SSE 心跳、数据源兜底回收、AI 清洗看门狗、附件孤儿清理等。
  8. 暴露 /js/a/** 业务接口。

    flowchart TD
    Start["启动 App.main()"] --> Log["打印启动日志"]
    Log --> Boot["SpringApplication.run()"]
    Boot --> Config["加载 application.yaml<br/>+ 环境变量覆盖"]
    Config --> Cors["注册全局 CORS 过滤器"]
    Config --> DataSource["初始化 PostgreSQL 主库"]
    Config --> Redis["初始化 Redis"]
    Config --> ES["初始化 Elasticsearch"]
    Config --> DuckDB["初始化 DuckDB 预算与回收器"]
    Config --> Modules["扫描 plat/agent/aiclean/knowledge/graph/person/call/trans/track/govern/search/dm/otg/external"]
    Modules --> Scheduling["启用 @EnableScheduling"]
    Scheduling --> Ready["服务就绪 8980/js/a"]
    

图示来源

  • ai-server/src/main/java/com/zsjz/ai/App.java:1-49
  • ai-server/src/main/resources/application.yaml:1-193
  • ai-server/src/main/java/com/zsjz/ai/common/config/CorsConfig.java:1-70

章节来源

  • ai-server/src/main/java/com/zsjz/ai/App.java:1-49
  • ai-server/src/main/resources/application.yaml:1-193

健康检查行为

系统中存在两层健康检查:

层级 接口/实现 作用 是否检查下游
网关侧节点探活 HealthChecker 周期性 GET {base-url}{health-path} 只检查 HTTP 可达性
业务侧健康接口 SystemController.health() /js/a/sys/health 只返回成功,不查 PG/Redis/ES
业务侧服务健康详情 SystemHealthService.check() /js/a/sys/serviceHealth 并行探测 PG、Redis、ES

网关节点探活

HealthChecker 每 gateway.health-check.interval(默认 10s)遍历所有启用节点,调用其健康路径。连续失败达到 failure-threshold(默认 3)标记 DOWN,一次成功恢复 UP。探活只证明进程存活,不验证数据库或搜索引擎可用。

业务健康接口

/sys/health 始终返回成功,适合 Kubernetes liveness/readiness 探针或负载均衡健康检查。/sys/serviceHealth 才真正探测 PostgreSQL、Redis、Elasticsearch,并使用虚拟线程并行执行,单项探测最多等待 3s。

sequenceDiagram
    participant GW as "HealthChecker"
    participant Node as "ai-server 节点"
    participant Ctrl as "SystemController"

    loop 每 10 秒
        GW->>Node: GET {base-url}/js/a/sys/health
        Node->>Ctrl: 映射 /sys/health
        Ctrl-->>GW: 200 OK
    end

图示来源

  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-62
  • ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java:32-55

章节来源

  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-62
  • ai-server/src/main/java/com/zsjz/ai/module/plat/controller/SystemController.java:32-55
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java:1-200

粘性路由职责

核心规则

StickyRouteFilter 是网关粘性路由的核心,order 为 10001,在 Spring Cloud Gateway 的 URL 计算过滤器之后执行。其职责如下:

场景 行为
登录请求且用户名已绑定 固定转发到绑定节点
登录请求且未绑定 从健康节点轮询选候选节点,但不写绑定关系
普通请求且 token 有效且有绑定 转发到绑定节点
普通请求且 token 有效但无绑定 尝试绑定到 default-node
token 无效、过期或被顶掉 按匿名请求轮询健康节点,后端返回 401
绑定节点停用或 DOWN 返回 503,不自动切换
无 token 的匿名请求 轮询健康节点

登录预处理

LoginRequestFilter(order 9999)只对配置的登录路径生效:

  1. 缓存不超过 64KB 的请求体。
  2. 解析 JSON 中的 username。
  3. 将 Accept-Encoding 改为 identity,避免后端 gzip 响应影响响应体解析。
  4. 原样重建请求体并转发。
  5. 解析失败时不阻断请求,按匿名轮询处理。

    flowchart TD
    Req["网关收到请求"] --> CheckPath{"是否登录路径?"}
    CheckPath -->|否| Normal["走普通粘性路由"]
    CheckPath -->|是| ReadBody["缓存请求体 ≤64KB"]
    ReadBody --> ParseUser{"能否解析 username?"}
    ParseUser -->|能| MarkLogin["标记 LOGIN_REQUEST<br/>携带 username"]
    ParseUser -->|否| Anonym["按匿名轮询"]
    MarkLogin --> RewriteEncoding["Accept-Encoding = identity"]
    RewriteEncoding --> Forward["转发给 ai-server"]
    Anonym --> Forward
    Normal --> Decide{"有 x-token?"}
    Decide -->|有| Resolve["解析 loginId → userId → 绑定节点"]
    Decide -->|无| SelectNode["轮询健康节点"]
    Resolve --> Route["重写目标 URI 并转发"]
    SelectNode --> Route
    

图示来源

  • ai-gateway/src/main/java/com/zsjz/gateway/route/LoginRequestFilter.java:1-120
  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java:1-180

CORS 与跨域

网关默认关闭自身跨域,并在 default filter 中对响应头做去重。实际跨域由 ai-server 的 CorsConfig 处理:

  • 默认开启。
  • 允许所有头部与方法。
  • 暴露 Content-Disposition,以便跨域下载时取文件名。
  • 允许凭据,以兼容带 credentials: include 的 fetch 与 SSE。
  • 可通过 app.cors.allowed-origin-patterns 收敛到具体域名。

章节来源

  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java:1-180
  • ai-gateway/src/main/java/com/zsjz/gateway/route/LoginRequestFilter.java:1-120
  • ai-server/src/main/java/com/zsjz/ai/common/config/CorsConfig.java:1-70
  • ai-gateway/src/main/resources/application.yaml:1-81

典型部署拓扑

单节点开发环境

适合单机调试:

  • 安装 PostgreSQL、Redis、Elasticsearch。
  • 启动 ai-server,端口 8980。
  • 可在 application.yaml 的 gateway.services.nodes 中把 node-1 指向本机 http://localhost:8980。
  • 启动 ai-gateway,端口 8080。
  • 前端访问 http://host:8080/js/a。

优点:链路完整,可验证网关粘性路由。缺点:没有多节点容灾。

多节点 ai-server + 单网关

生产常用形态:

  • 多个 ai-server 实例,每个实例配置不同的 node.id 和 base-url。
  • 单台 ai-gateway 作为入口。
  • 数据库、Redis、Elasticsearch 集中部署。
  • 前端只访问网关地址。

当新用户登录时,网关从健康节点中选择候选;已绑定用户始终回到同一节点,保证案件本地文件和 DuckDB 快照一致性。

多网关高可用

需要至少两台网关配合反向代理:

  • Nginx/HAProxy/云负载均衡在前端放两个 ai-gateway。
  • 任意一台网关故障,流量可切换到另一台。
  • 两个网关共享同一个 PostgreSQL gateway_service 表和 Redis。
  • 新节点下线时,两网关都会把该节点标记 DOWN。
  • 已绑定用户仍会被导向其原始节点,除非管理员解除绑定。

    graph TB
    LB["负载均衡器"]
    GW1["ai-gateway #1"]
    GW2["ai-gateway #2"]
    SRV1["ai-server node-1"]
    SRV2["ai-server node-2"]
    PG["PostgreSQL"]
    RDS["Redis"]
    ES["Elasticsearch"]
    
    LB --> GW1
    LB --> GW2
    GW1 --> SRV1
    GW1 --> SRV2
    GW2 --> SRV1
    GW2 --> SRV2
    GW1 --> PG
    GW2 --> PG
    GW1 --> RDS
    GW2 --> RDS
    SRV1 --> ES
    SRV2 --> ES
    

图示来源

  • ai-gateway/src/main/resources/application.yaml:51-81
  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-62
  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java:1-180

章节来源

  • ai-gateway/src/main/resources/application.yaml:51-81

性能参数调优

Spring 调度池

默认值为 4。调度器承载 SSE 心跳、数据源回收、AI 清洗看门狗、附件孤儿清理等任务;任一批量任务变慢都可能拖住心跳,导致空闲 SSE 连接被上游代理断开。生产建议保持 4,仅在大量长耗时调度任务时才考虑扩大。

参数 默认值 生产建议 说明
SPRING_TASK_SCHEDULING_POOL_SIZE 4 4 避免心跳被批量任务阻塞

HTTP 编解码器

默认最大内存大小为 10MB。大模型对话、图谱快照、JSON 响应较大时应适当提高。

参数 默认值 生产建议 说明
SPRING_HTTP_CODECS_MAX_IN_MEMORY_SIZE 10MB 50MB~200MB 取决于图谱快照、Agent 响应大小

文件上传大小

默认单文件 200MB,总请求 500MB。AI 清洗、升级包、附件解析可能触发大文件上传。

参数 默认值 生产建议 说明
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE 200MB 500MB~2GB 视升级包和大附件需求
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE 500MB 1GB~4GB 防止单请求堆溢出

DuckDB 内存与线程

DuckDB 使用 SET GLOBAL 配置,每个案件实例独立占用内存和线程。配置错误可能导致内存叠加膨胀。

参数 默认值 生产建议 说明
ZSJZ_DUCKDB_MAX_OPEN_CASES 8 根据并发开案数调整 超出直接拒绝开案
ZSJZ_DUCKDB_MEMORY_RATIO 0.6 0.3~0.6 所有案件合计物理内存比例
ZSJZ_DUCKDB_THREADS_PER_INSTANCE 4 2~4 每个案件实例线程数

线程数与并发

参数 默认值 生产建议 说明
ZSJZ_FILE_AI_MAX_CONCURRENT 3 3~10 非表格文件 AI 识别并发
ZSJZ_FILE_AI_MAX_PENDING 200 200~1000 排队上限,防止拖入大批文件撑爆队列
ZSJZ_EMBEDDING_BATCH_SIZE 8 4~16 向量推理批大小
ZSJZ_EMBEDDING_INTRA_OP_THREADS 0 0 或 CPU 核数的一半 0 表示交给 ONNX Runtime 默认策略

RAG top_k

配置段 参数 默认值 生产建议 说明
Agent RAG ETL_RAG_TOP_K 5 5~10 Agent 表结构语义检索召回条数
AI 清洗向量 ZSJZ_AI_CLEAN_VECTOR_TOP_K 12 8~20 模板匹配候选补充条数
聊天附件 RAG ZSJZ_CHAT_ATTACHMENT_TOP_K 8 5~15 附件片段检索条数

top_k 越大,召回越全,但 LLM 输入 token 越多、延迟越高;太小则容易漏召同义模板或片段。

其他生产建议

  • 关闭本地向量模型预热:ZSJZ_EMBEDDING_EAGER_LOAD=false,让首次业务调用承担模型加载成本,避免启动时间过长。
  • 合理设置 ZSJZ_EMBEDDING_MODEL_PATH,确保部署机上有 tokenizer.json 与 onnx/model.onnx。
  • 对大型 ES 集群,SPRING_ELASTICSEARCH_CONNECTION_TIMEOUT 和 SPRING_ELASTICSEARCH_SOCKET_TIMEOUT 应与网络延迟匹配。
  • 网关后端连接超时 3s 适用于内网;跨机房或云专线可适当增大。

章节来源

  • ai-server/src/main/resources/application.yaml:1-193
  • deploy/env.sh:1-172

故障排查

网关返回 503

常见原因:

  1. 服务不存在或已停用。
  2. 没有可用节点。
  3. 用户绑定的节点不存在、已停用或 DOWN。
  4. 用户未绑定节点且未配置 default-node。

排查步骤:

  1. 检查 ai-gateway 日志中的 StickyUnavailableException。
  2. 确认 gateway.services 中节点 enabled=true。
  3. 检查 gateway.health-check.interval 与 failure-threshold。
  4. 手动访问后端健康路径:curl http://{node-base-url}/js/a/sys/health。
  5. 若绑定节点 DOWN,联系管理员解除绑定或修复节点;网关不会自动切换,因为数据在该节点本地磁盘上。

章节来源

  • ai-gateway/src/main/java/com/zsjz/gateway/route/StickyRouteFilter.java:1-180
  • ai-gateway/src/main/java/com/zsjz/gateway/registry/HealthChecker.java:1-62

跨域失败

现象:浏览器控制台报跨域错误,或对话出现 “Failed to fetch”。

排查步骤:

  1. 确认 ai-server 的 app.cors.enabled=true。
  2. 检查 app.cors.allowed-origin-patterns 是否包含前端来源。
  3. 不要同时在网关层开启跨域,否则可能出现重复响应头。
  4. 确认前端 fetch 发送了 credentials: include,且服务端允许凭据。
  5. 桌面端 file:// 加载前端时必须允许跨域。

章节来源

  • ai-server/src/main/java/com/zsjz/ai/common/config/CorsConfig.java:1-70
  • ai-gateway/src/main/resources/application.yaml:1-81

登录态丢失

现象:登录后刷新页面或切标签后需要重新登录。

排查步骤:

  1. 检查前端是否携带 x-token 请求头。
  2. 检查 ai-gateway 与 ai-server 的 sa-token 配置是否完全一致,尤其是 token 名称、超时、Redis 地址。
  3. 检查 Redis 是否可用;SystemHealthService 的 Redis 探测会返回 PING/PONG。
  4. 检查账号是否被顶下线;ZSJZ_AUTH_IN_USE_WINDOW_MINUTES 控制“账号正在使用”窗口。
  5. 查看 Redis 中对应 token 是否被删除或过期。

章节来源

  • ai-gateway/src/main/resources/application.yaml:23-49
  • ai-server/src/main/resources/application.yaml:161-193
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java:1-200

Redis 断开

现象:登录接口异常、token 解析失败、会话无法维持。

排查步骤:

  1. 检查 SPRING_DATA_REDIS_HOST、SPRING_DATA_REDIS_PORT。
  2. 检查 Redis 服务状态和网络连通性。
  3. 查看 SystemHealthService 中 Redis 探测结果。
  4. 检查 Redis 内存、持久化、连接数。
  5. 确认网关与业务使用同一个 Redis 实例,且 sa-token 配置一致。

章节来源

  • deploy/env.sh:1-172
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java:1-200

Elasticsearch 连接超时

现象:搜索、RAG、向量索引相关接口超时或报错。

排查步骤:

  1. 检查 SPRING_ELASTICSEARCH_URIS。
  2. 检查 SPRING_ELASTICSEARCH_CONNECTION_TIMEOUT 和 SPRING_ELASTICSEARCH_SOCKET_TIMEOUT。
  3. 若启用鉴权,取消注释用户名和密码配置。
  4. 查看 SystemHealthService 中 ES 探测返回的集群状态。
  5. 检查 ES 集群是否为 red 状态,以及节点数是否正常。

章节来源

  • deploy/env.sh:1-172
  • ai-server/src/main/java/com/zsjz/ai/module/plat/service/SystemHealthService.java:120-200

Neo4j 连接问题

Neo4j 是可选依赖,仅图谱能力需要。若未启用图谱功能,连接失败不应阻断核心业务。

排查步骤:

  1. 检查 NEO4J_URI、用户名、密码。
  2. 确认 Neo4j 服务端口可达。
  3. 查看 Neo4j 日志和认证错误。
  4. 若不需要图谱,可评估关闭相关能力以减少启动依赖。

章节来源

  • deploy/env.sh:1-172

文件上传超限

现象:上传大文件或升级包时报 multipart 超限。

排查步骤:

  1. 检查 SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE 和 SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE。
  2. 检查 Nginx 或其他前置代理的 client_max_body_size。
  3. 检查 STORAGE_LOCAL_ROOT_PATH 所在磁盘空间。
  4. 检查 STORAGE_LOCAL_BASE_URL 是否与 SERVER_PORT 和 context-path 一致。

章节来源

  • ai-server/src/main/resources/application.yaml:1-193
  • deploy/env.sh:1-172

结论

生产部署应以 ai-gateway 作为用户入口,以 ai-server 作为业务节点。构建时先 ai-server 后 ai-gateway;启动前先通过 set -a; source deploy/env.sh; set +a 或 systemd EnvironmentFile 注入环境变量;严格保护含数据库口令的 deploy/env.sh。

网关的核心价值是粘性路由:登录后固定用户到同一节点,避免案件本地数据和 DuckDB 快照跨节点不一致。业务健康接口只证明进程存活,深层依赖探测通过 /js/a/sys/serviceHealth 获取。性能调优应优先关注调度池、HTTP 编解码、multipart 大小、DuckDB 内存比例、向量推理 batch size 和 RAG top_k,而不是盲目放大线程数。