上一篇 下一篇 分享链接 返回 返回顶部

AI搜索扛不住并发?从限流、缓存到压测的一套生产级落地方案

发布人:慈云数据-客服中心 发布时间:15小时前 阅读量:2

AI搜索 高并发解决方案|附完整命令

随着大模型应用逐渐从“演示阶段”进入“生产阶段”,AI搜索成为企业知识库、智能客服、内容检索、代码助手、研发问答、私域数据分析等场景中的核心能力。所谓AI搜索,通常不是简单的关键词匹配,而是结合了向量检索、全文检索、重排序、上下文组装以及大模型生成的增强型搜索方案,也就是常见的 RAG(Retrieval-Augmented Generation,检索增强生成)架构。

然而,很多团队在做AI搜索系统时,前期只关注“效果能不能跑通”,一旦进入真实业务,就会立刻遇到高并发问题:请求变慢、向量库查询超时、大模型接口排队、CPU飙高、GPU利用率不稳定、数据库连接耗尽、Redis击穿、Nginx 504、服务实例频繁重启等。

本文将围绕“AI搜索高并发解决方案”进行系统梳理,并给出一套可落地的部署架构、优化思路和完整命令示例,帮助你从单机Demo平滑升级到可支撑高并发访问的生产级AI搜索服务。


一、AI搜索为什么容易出现高并发瓶颈?

AI搜索的链路通常比传统搜索更长,一个完整请求可能包含以下步骤:

  1. 用户输入问题;
  2. 网关层鉴权、限流;
  3. 服务层进行问题改写或意图识别;
  4. 调用Embedding模型生成查询向量;
  5. 查询向量数据库;
  6. 查询全文索引;
  7. 多路召回结果融合;
  8. 对候选文档进行重排序;
  9. 拼接上下文;
  10. 调用大模型生成答案;
  11. 流式返回结果;
  12. 记录日志、埋点、评估数据。

这条链路中,每一步都有可能成为瓶颈。尤其是以下几个环节最容易出问题:

环节 常见问题
Embedding生成 模型推理耗时、GPU/CPU资源不足
向量检索 索引参数不合理、连接数不足、磁盘IO高
重排序模型 Cross Encoder计算成本高
大模型生成 Token生成慢、上下文过长、并发限制
数据库 连接池耗尽、慢查询、日志写入阻塞
网关 超时配置不合理、限流策略缺失
应用服务 同步阻塞、线程池不足、无队列削峰

所以,AI搜索高并发优化不能只盯着某一个组件,而应该从架构、模型、缓存、队列、服务治理、资源隔离和监控体系整体设计。


二、生产级AI搜索推荐架构

一个较为稳定的高并发AI搜索架构可以设计如下:

用户/客户端
   |
   v
Nginx / API Gateway
   |
   v
认证鉴权 / 限流 / 黑白名单
   |
   v
AI Search API 服务集群
   |
   |---- Redis 缓存
   |---- Kafka / RabbitMQ / Celery 队列
   |---- PostgreSQL / MySQL 业务库
   |---- Elasticsearch / OpenSearch 全文检索
   |---- Milvus / Qdrant / Weaviate 向量数据库
   |---- Embedding 服务
   |---- Rerank 服务
   |---- LLM 推理服务 / 第三方大模型API
   |
   v
日志、指标、链路追踪、评估系统

为了支撑高并发,这个架构需要满足几个核心原则:

  1. 无状态服务横向扩展:AI Search API服务尽量保持无状态,方便通过Kubernetes或Docker Compose扩容。
  2. 缓存优先:对热门问题、热门向量、热门检索结果进行缓存。
  3. 异步削峰:非实时任务进入队列,例如文档解析、向量化、索引构建、日志分析。
  4. 模型服务独立部署:Embedding、Rerank、LLM推理不要和业务API混在一个进程里。
  5. 多级限流:网关限流、用户级限流、接口级限流、模型服务限流。
  6. 超时和降级:向量检索超时后可回退全文检索,重排序超时后可跳过。
  7. 监控闭环:必须看到QPS、P95、P99、错误率、Token吞吐、缓存命中率等指标。

三、核心优化方向

1. 网关层限流与负载均衡

高并发系统最怕没有入口保护。没有限流的AI搜索服务,很容易被突发流量打垮,尤其是大模型调用成本高,单个恶意用户就可能消耗大量资源。

推荐使用 Nginx 做基础反向代理和限流。

安装Nginx

以 Ubuntu 为例:

sudo apt update
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx

Nginx限流配置示例

编辑配置文件:

sudo vim /etc/nginx/conf.d/ai-search.conf

写入以下内容:

limit_req_zone $binary_remote_addr zone=ai_search_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr_conn:10m;

upstream ai_search_backend {
    least_conn;
    server 127.0.0.1:8001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8002 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8003 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name your-domain.com;

    client_max_body_size 20m;

    location / {
        limit_req zone=ai_search_limit burst=20 nodelay;
        limit_conn addr_conn 20;

        proxy_pass http://ai_search_backend;
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 300s;
    }
}

检查配置并重载:

sudo nginx -t
sudo systemctl reload nginx

这里需要注意,AI搜索通常会用流式输出,因此 proxy_read_timeout 不能设置太短,否则用户还没接收完模型输出,请求就被Nginx断开了。


2. API服务使用异步框架

AI搜索服务建议使用 FastAPI、Sanic、Node.js NestJS、Go Gin 等高并发框架。Python场景下,FastAPI配合Uvicorn/Gunicorn是比较常见的选择。

安装依赖

mkdir ai-search-service
cd ai-search-service

python3 -m venv venv
source venv/bin/activate

pip install fastapi uvicorn gunicorn redis httpx pydantic

示例 FastAPI 服务

创建文件:

vim main.py

写入:

import asyncio
import hashlib
import json
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
import redis.asyncio as redis

app = FastAPI()

redis_client = redis.Redis(
    host="127.0.0.1",
    port=6379,
    db=0,
    decode_responses=True,
    max_connections=200
)

def cache_key(query: str) -> str:
    return "ai_search:" + hashlib.md5(query.encode("utf-8")).hexdigest()

async def fake_vector_search(query: str):
    await asyncio.sleep(0.05)
    return [
        {"title": "文档A", "content": "这是与问题相关的知识片段A"},
        {"title": "文档B", "content": "这是与问题相关的知识片段B"}
    ]

async def fake_llm_stream(query: str, docs):
    answer = f"根据检索到的资料,问题「{query}」的答案如下:"
    for ch in answer:
        await asyncio.sleep(0.02)
        yield ch.encode("utf-8")

@app.get("/health")
async def health():
    return {"status": "ok"}

@app.post("/search")
async def search(request: Request):
    body = await request.json()
    query = body.get("query", "").strip()

    if not query:
        return {"error": "query is required"}

    key = cache_key(query)
    cached = await redis_client.get(key)

    if cached:
        async def cached_stream():
            for ch in cached:
                await asyncio.sleep(0.002)
                yield ch.encode("utf-8")
        return StreamingResponse(cached_stream(), media_type="text/plain")

    docs = await fake_vector_search(query)

    async def stream_and_cache():
        chunks = []
        async for token in fake_llm_stream(query, docs):
            text = token.decode("utf-8")
            chunks.append(text)
            yield token

        full_answer = "".join(chunks)
        await redis_client.setex(key, 300, full_answer)

    return StreamingResponse(stream_and_cache(), media_type="text/plain")

启动单实例

uvicorn main:app --host 0.0.0.0 --port 8001

使用Gunicorn多进程启动

gunicorn main:app \
  -k uvicorn.workers.UvicornWorker \
  -w 4 \
  -b 0.0.0.0:8001 \
  --timeout 300 \
  --keep-alive 30 \
  --access-logfile - \
  --error-logfile -

参数说明:

  • -w 4:启动4个Worker进程;
  • --timeout 300:适配大模型长响应;
  • --keep-alive 30:保持连接,减少频繁握手;
  • UvicornWorker:支持异步请求处理。

如果是多核CPU,可以根据机器规格设置Worker数量:

workers = CPU核心数 * 2 + 1

但AI搜索并不是纯CPU应用,还涉及大量IO等待,因此需要通过压测找到最佳值。


3. Redis缓存热点问题

AI搜索中缓存的价值非常大,尤其是以下内容适合缓存:

  1. 相同问题的最终答案;
  2. 查询Embedding向量;
  3. 检索结果;
  4. 用户权限数据;
  5. 文档元数据;
  6. 热门问题推荐;
  7. 模型配置和Prompt模板。

安装Redis

sudo apt update
sudo apt install -y redis-server
sudo systemctl enable redis-server
sudo systemctl start redis-server
sudo systemctl status redis-server

修改Redis配置

sudo vim /etc/redis/redis.conf

建议修改:

bind 0.0.0.0
protected-mode yes
maxmemory 4gb
maxmemory-policy allkeys-lru
tcp-keepalive 60
timeout 0

重启Redis:

sudo systemctl restart redis-server

查看Redis状态

redis-cli ping
redis-cli info memory
redis-cli info clients
redis-cli info stats

设置密码

sudo vim /etc/redis/redis.conf

加入:

requirepass your_strong_password

重启:

sudo systemctl restart redis-server

测试:

redis-cli -a your_strong_password ping

生产环境建议使用Redis Cluster或云厂商托管版Redis,避免单点故障。


4. 向量数据库优化

AI搜索系统中的向量数据库是核心组件之一。常见选择包括 Milvus、Qdrant、Weaviate、pgvector、Elasticsearch dense_vector 等。

如果数据量较大、并发较高,推荐使用 Milvus 或 Qdrant;如果数据规模不大并且希望架构简单,可以使用 PostgreSQL + pgvector。

下面以 Qdrant 为例。

Docker启动Qdrant

docker run -d \
  --name qdrant \
  -p 6333:6333 \
  -p 6334:6334 \
  -v $(pwd)/qdrant_storage:/qdrant/storage \
  qdrant/qdrant:latest

查看状态:

curl http://127.0.0.1:6333/healthz

创建Collection

假设Embedding维度为768:

curl -X PUT "http://127.0.0.1:6333/collections/ai_docs" \
  -H "Content-Type: application/json" \
  -d '{
    "vectors": {
      "size": 768,
      "distance": "Cosine"
    },
    "optimizers_config": {
      "default_segment_number": 4
    },
    "hnsw_config": {
      "m": 16,
      "ef_construct": 100,
      "full_scan_threshold": 10000
    }
  }'

查询Collection信息

curl "http://127.0.0.1:6333/collections/ai_docs"

搜索示例

curl -X POST "http://127.0.0.1:6333/collections/ai_docs/points/search" \
  -H "Content-Type: application/json" \
  -d '{
    "vector": [0.01, 0.02, 0.03],
    "limit": 5,
    "with_payload": true,
    "params": {
      "hnsw_ef": 128,
      "exact": false
    }
  }'

实际请求中,vector 必须是完整的768维向量。这里为了展示命令,仅放了3个数字,真实执行时需要传完整向量。

Qdrant优化建议

  • hnsw_ef 越高,召回率越好,但查询越慢;
  • m 越高,索引质量越好,但内存占用更高;
  • 热门集合建议放在SSD;
  • 大规模数据要分片;
  • 写入和查询高峰尽量错开;
  • 检索结果不宜过多,通常召回Top 20~50,再重排Top 5~10。

5. Elasticsearch全文检索辅助召回

单纯向量检索有时会漏掉精确关键词,例如产品型号、错误码、人名、专有名词。高质量AI搜索通常采用“混合检索”:

最终候选 = 向量检索结果 + BM25全文检索结果 + 业务规则召回结果

Docker启动Elasticsearch

docker network create ai-search-net

docker run -d \
  --name elasticsearch \
  --network ai-search-net \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -e "ES_JAVA_OPTS=-Xms2g -Xmx2g" \
  elasticsearch:8.12.2

检查状态:

curl http://127.0.0.1:9200

创建索引

curl -X PUT "http://127.0.0.1:9200/ai_docs" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 0,
      "refresh_interval": "5s"
    },
    "mappings": {
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "standard"
        },
        "content": {
          "type": "text",
          "analyzer": "standard"
        },
        "doc_id": {
          "type": "keyword"
        },
        "created_at": {
          "type": "date"
        }
      }
    }
  }'

写入文档

curl -X POST "http://127.0.0.1:9200/ai_docs/_doc/1" \
  -H "Content-Type: application/json" \
  -d '{
    "doc_id": "doc_001",
    "title": "AI搜索高并发架构",
    "content": "AI搜索系统需要结合向量检索、全文检索、缓存、限流和异步队列实现高并发。",
    "created_at": "2025-01-01T00:00:00Z"
  }'

查询文档

curl -X POST "http://127.0.0.1:9200/ai_docs/_search" \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "multi_match": {
        "query": "AI搜索 高并发",
        "fields": ["title^2", "content"]
      }
    },
    "size": 10
  }'

Elasticsearch优化建议

  1. 查询高峰期避免大量写入;
  2. 批量写入使用 _bulk
  3. 合理设置分片数量;
  4. 热数据放SSD;
  5. 查询只返回必要字段;
  6. 设置慢查询日志;
  7. 对高频过滤字段使用 keyword 类型;
  8. 避免深分页,使用 search_after

四、Embedding服务独立化

Embedding是AI搜索的关键入口,它负责把用户问题和文档片段转成向量。高并发场景下,Embedding服务一定要独立部署,避免阻塞主API服务。

如果使用开源模型,可以通过 Text Embeddings Inference、FastAPI自建服务或 vLLM 等方式部署。

以下以 Hugging Face 的 Text Embeddings Inference 为例。

Docker部署Embedding服务

docker run -d \
  --name text-embeddings \
  --gpus all \
  -p 8080:80 \
  -v $PWD/data:/data \
  ghcr.io/huggingface/text-embeddings-inference:latest \
  --model-id BAAI/bge-base-zh-v1.5

如果没有GPU,可以尝试CPU模式,但并发性能会下降:

docker run -d \
  --name text-embeddings-cpu \
  -p 8080:80 \
  -v $PWD/data:/data \
  ghcr.io/huggingface/text-embeddings-inference:cpu-latest \
  --model-id BAAI/bge-base-zh-v1.5

调用Embedding接口

curl -X POST "http://127.0.0.1:8080/embed" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": ["AI搜索如何支撑高并发?"]
  }'

Embedding优化建议

  • 对相同问题的Embedding结果进行缓存;
  • 批量文档向量化时使用batch;
  • 查询向量化和文档向量化分开资源;
  • 对长文本先切片再向量化;
  • 尽量选择维度适中、推理速度快的模型;
  • 如果业务允许,可以使用量化模型降低资源消耗。

五、Rerank重排序优化

重排序模型通常比Embedding检索更慢,因为它需要对“问题-文档”成对计算相关性。高并发场景下,如果每个请求都对50个候选文档做重排,系统很快会被拖垮。

推荐策略:

  1. 向量检索Top 30;
  2. 全文检索Top 20;
  3. 合并去重后最多保留30条;
  4. Rerank最多处理10~20条;
  5. 设置重排超时,例如300ms或500ms;
  6. 超时直接降级,不影响主流程。

如果你的业务对实时性要求极高,可以不使用Cross Encoder重排,而是采用轻量级打分融合:

final_score = 0.6 * vector_score + 0.3 * bm25_score + 0.1 * business_score

这样虽然精度略低,但吞吐量会明显提高。


六、大模型生成层优化

大模型生成通常是AI搜索链路中最慢、最贵、最容易拥塞的部分。高并发优化必须重点关注Token吞吐和上下文长度。

vLLM部署本地大模型

如果你有GPU资源,可以使用 vLLM 提供OpenAI兼容接口。

安装Docker和NVIDIA运行时后启动

docker run -d \
  --name vllm-qwen \
  --gpus all \
  -p 8000:8000 \
  -v $PWD/models:/models \
  vllm/vllm-openai:latest \
  --model Qwen/Qwen2.5-7B-Instruct \
  --host 0.0.0.0 \
  --port 8000 \
  --tensor-parallel-size 1 \
  --gpu-memory-utilization 0.90 \
  --max-model-len 8192

测试大模型接口

curl -X POST "http://127.0.0.1:8000/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-7B-Instruct",
    "messages": [
      {
        "role": "user",
        "content": "请用三句话解释AI搜索高并发优化方法"
      }
    ],
    "temperature": 0.7,
    "max_tokens": 512,
    "stream": false
  }'

流式调用测试

curl -N -X POST "http://127.0.0.1:8000/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-7B-Instruct",
    "messages": [
      {
        "role": "user",
        "content": "请详细说明AI搜索系统如何做限流、缓存和降级"
      }
    ],
    "temperature": 0.7,
    "max_tokens": 1024,
    "stream": true
  }'

大模型层优化建议

  1. 限制最大输入长度:上下文越长,推理越慢;
  2. 限制最大输出Token:防止单个请求占用过多资源;
  3. 开启流式输出:降低用户感知延迟;
  4. 使用更小模型处理简单问题:复杂问题再交给大模型;
  5. Prompt模板压缩:减少无效指令;
  6. 上下文去重:避免重复片段浪费Token;
  7. 请求排队:超过并发阈值进入队列;
  8. 熔断降级:模型不可用时返回检索摘要或兜底答案。

七、异步队列削峰

AI搜索中有两类任务:

  • 在线任务:用户搜索、实时问答;
  • 离线任务:文档解析、切片、向量化、索引写入、日志分析、质量评估。

离线任务必须使用队列,不能和在线请求争抢资源。

安装RabbitMQ

docker run -d \
  --name rabbitmq \
  -p 5672:5672 \
  -p 15672:15672 \
  -e RABBITMQ_DEFAULT_USER=admin \
  -e RABBITMQ_DEFAULT_PASS=admin123 \
  rabbitmq:3-management

访问管理页面:

http://127.0.0.1:15672

账号密码:

admin / admin123

使用Celery处理向量化任务

安装依赖:

pip install celery redis

创建 tasks.py

vim tasks.py

写入:

from celery import Celery
import time

app = Celery(
    "ai_search_tasks",
    broker="amqp://admin:admin123@127.0.0.1:5672//",
    backend="redis://127.0.0.1:6379/1"
)

@app.task
def build_doc_index(doc_id: str):
    time.sleep(3)
    return {
        "doc_id": doc_id,
        "status": "indexed"
    }

启动Worker:

celery -A tasks worker \
  --loglevel=info \
  --concurrency=4 \
  --queues=celery

提交任务:

python - <<'EOF'
from tasks import build_doc_index
result = build_doc_index.delay("doc_001")
print(result.id)
EOF

查看任务结果:

python - <<'EOF'
from tasks import app
task_id = input("task_id: ")
result = app.AsyncResult(task_id)
print(result.status)
print(result.result)
EOF

队列优化建议

  • 在线搜索请求不要全部进入队列,否则会增加延迟;
  • 文档索引构建必须队列化;
  • 为不同任务设置不同队列;
  • 重任务和轻任务使用不同Worker;
  • 设置重试次数和死信队列;
  • 高峰期可以临时扩容Worker。

八、Docker Compose一键部署示例

下面给出一个简化版 docker-compose.yml,包含 Redis、Qdrant、Elasticsearch、RabbitMQ 等基础组件。

创建目录:

mkdir ai-search-stack
cd ai-search-stack

创建配置:

vim docker-compose.yml

写入:

version: "3.9"

services:
  redis:
    image: redis:7
    container_name: ai-redis
    command: redis-server --appendonly yes --maxmemory 2gb --maxmemory-policy allkeys-lru
    ports:
      - "6379:6379"
    volumes:
      - ./data/redis:/data
    restart: always

  qdrant:
    image: qdrant/qdrant:latest
    container_name: ai-qdrant
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - ./data/qdrant:/qdrant/storage
    restart: always

  elasticsearch:
    image: elasticsearch:8.12.2
    container_name: ai-elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms2g -Xmx2g
    ports:
      - "9200:9200"
    volumes:
      - ./data/elasticsearch:/usr/share/elasticsearch/data
    restart: always

  rabbitmq:
    image: rabbitmq:3-management
    container_name: ai-rabbitmq
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin123
    ports:
      - "5672:5672"
      - "15672:15672"
    restart: always

启动服务:

docker compose up -d

查看服务:

docker compose ps

查看日志:

docker compose logs -f redis
docker compose logs -f qdrant
docker compose logs -f elasticsearch
docker compose logs -f rabbitmq

停止服务:

docker compose down

清理数据:

docker compose down -v

九、Kubernetes横向扩展方案

如果已经进入生产环境,建议使用 Kubernetes 部署AI搜索服务,便于弹性扩容、滚动发布和故障恢复。

API服务Deployment示例

创建文件:

vim ai-search-deployment.yaml

写入:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-search-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ai-search-api
  template:
    metadata:
      labels:
        app: ai-search-api
    spec:
      containers:
        - name: ai-search-api
          image: your-registry/ai-search-api:latest
          ports:
            - containerPort: 8000
          env:
            - name: REDIS_HOST
              value: "redis"
            - name: QDRANT_URL
              value: "http://qdrant:6333"
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "2"
              memory: "4Gi"
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 30
            periodSeconds: 10

应用配置:

kubectl apply -f ai-search-deployment.yaml

查看Pod:

kubectl get pods -l app=ai-search-api

Service配置

vim ai-search-service.yaml

写入:

apiVersion: v1
kind: Service
metadata:
  name: ai-search-api
spec:
  selector:
    app: ai-search-api
  ports:
    - port: 80
      targetPort: 8000
  type: ClusterIP

应用:

kubectl apply -f ai-search-service.yaml

HPA自动扩容

kubectl autoscale deployment ai-search-api \
  --cpu-percent=60 \
  --min=3 \
  --max=20

查看HPA:

kubectl get hpa

手动扩容:

kubectl scale deployment ai-search-api --replicas=10

滚动重启:

kubectl rollout restart deployment ai-search-api

查看发布状态:

kubectl rollout status deployment ai-search-api

十、超时、熔断与降级策略

AI搜索高并发系统必须设计失败路径。如果没有降级策略,一个下游服务抖动就可能拖垮整个系统。

推荐设置如下:

组件 建议超时
Redis读取 50ms~100ms
Embedding服务 300ms~1000ms
向量检索 100ms~500ms
全文检索 100ms~500ms
Rerank服务 300ms~800ms
LLM首Token 2s~8s
LLM总响应 30s~180s

降级策略示例:

  1. Redis不可用:直接走主流程;
  2. Embedding超时:返回提示或使用关键词搜索;
  3. 向量库超时:回退Elasticsearch;
  4. Elasticsearch超时:只使用向量结果;
  5. Rerank超时:跳过重排;
  6. LLM超时:返回检索摘要;
  7. 所有检索失败:返回兜底话术。

一个优秀的AI搜索系统不是保证所有链路永远不失败,而是保证部分失败时系统仍然可用。


十一、压测方案与完整命令

上线前必须进行压测。压测至少关注:

  • QPS;
  • 平均响应时间;
  • P95响应时间;
  • P99响应时间;
  • 错误率;
  • CPU使用率;
  • 内存使用率;
  • Redis连接数;
  • 向量库延迟;
  • LLM Token吞吐;
  • 网关504数量。

使用wrk压测

安装:

sudo apt update
sudo apt install -y wrk

创建Lua脚本:

vim search.lua

写入:

wrk.method = "POST"
wrk.body   = '{"query":"AI搜索如何进行高并发优化?"}'
wrk.headers["Content-Type"] = "application/json"

执行压测:

wrk -t8 -c200 -d60s -s search.lua http://127.0.0.1/search

参数说明:

  • -t8:8个线程;
  • -c200:200个并发连接;
  • -d60s:持续60秒;
  • -s search.lua:使用Lua脚本构造POST请求。

使用hey压测

安装:

go install github.com/rakyll/hey@latest

执行:

~/go/bin/hey \
  -n 10000 \
  -c 200 \
  -m POST \
  -H "Content-Type: application/json" \
  -d '{"query":"AI搜索高并发解决方案"}' \
  http://127.0.0.1/search

查看系统资源

top
htop
free -h
df -h
iostat -x 1
vmstat 1

如果没有相关工具:

sudo apt install -y htop sysstat

查看端口连接

ss -antp | grep 8000
ss -antp | grep 6379
ss -s

查看Docker资源

docker stats

查看Nginx日志

sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

十二、生产参数建议

下面给出一组适合中小规模AI搜索系统的初始参数,可根据压测结果调整。

模块 建议配置
API服务 3~10个实例
单实例Worker 2~8个
Redis连接池 100~500
Qdrant搜索TopK 20~50
Elasticsearch搜索Size 10~30
Rerank候选数 10~20
最终上下文片段 3~8段
最大输入Token 4K~8K
最大输出Token 512~2048
Nginx限流 单IP 5~20 r/s
API超时 60s~300s
缓存TTL 5分钟~24小时

对于企业知识库问答,通常不建议把几十个文档片段全部塞给大模型。上下文过多会降低速度,也可能增加幻觉概率。更好的方式是对检索结果进行去重、压缩和排序,只保留最相关、信息密度最高的片段。


十三、常见故障排查

1. Nginx 504 Gateway Timeout

排查命令:

sudo tail -f /var/log/nginx/error.log
curl -v http://127.0.0.1:8001/health

解决方向:

  • 增大 proxy_read_timeout
  • 检查后端服务是否卡死;
  • 检查LLM响应是否过慢;
  • 增加流式返回;
  • 降低最大输出Token。

2. Redis连接数耗尽

查看:

redis-cli info clients
redis-cli client list

解决方向:

  • 增加连接池;
  • 复用连接;
  • 限制最大客户端;
  • 检查是否每个请求都创建新连接。

3. 向量检索延迟过高

查看Qdrant状态:

curl http://127.0.0.1:6333/collections/ai_docs

解决方向:

  • 降低TopK;
  • 调整 hnsw_ef
  • 增加内存;
  • 使用SSD;
  • 分片部署;
  • 缓存热门检索结果。

4. 大模型首Token慢

解决方向:

  • 减少Prompt长度;
  • 减少上下文片段;
  • 使用更小模型;
  • 开启连续批处理;
  • 检查GPU显存和利用率;
  • 限制并发队列长度。

查看GPU状态:

nvidia-smi
watch -n 1 nvidia-smi

十四、推荐上线流程

AI搜索高并发系统建议按照以下顺序上线:

  1. 单机跑通完整链路;
  2. 加入Redis缓存;
  3. 拆分Embedding服务;
  4. 拆分向量库和全文检索;
  5. 加入Nginx限流;
  6. 使用Gunicorn多Worker部署API;
  7. 进行100并发压测;
  8. 优化慢查询和慢接口;
  9. 加入队列处理离线任务;
  10. 接入监控告警;
  11. 灰度发布;
  12. 扩容到多实例;
  13. 做300、500、1000并发阶梯压测;
  14. 根据P95和错误率调整参数;
  15. 正式上线。

十五、总结

AI搜索高并发优化不是简单地“加机器”或“换大模型”,而是一套系统工程。它涉及网关限流、无状态服务扩容、Redis缓存、向量数据库调优、全文检索辅助召回、Embedding服务独立化、Rerank降级、大模型推理优化、异步队列削峰、Kubernetes弹性伸缩以及完整监控压测体系。

如果要用一句话总结生产级方案,可以概括为:

前端限流保护入口,API服务无状态扩容,Redis缓存热点请求,向量检索和全文检索混合召回,Rerank控制候选规模,大模型流式输出并限制Token,离线任务全部队列化,最后通过压测和监控持续调优。

在实际落地中,建议不要一开始就追求复杂架构,而是先搭建一条稳定链路,然后逐步拆分瓶颈组件。真正可靠的AI搜索系统,一定是通过压测数据驱动优化,而不是依赖经验猜测。只要按照本文的架构和命令逐步实施,就可以从一个简单的AI搜索Demo,演进为具备高并发能力的生产级AI搜索平台。

目录结构
全文