限时福利领取


开篇:高并发下的“慢”与“卡”

去年双十一,我们给电商客户上线第一版 Decagon 智能客服。零点刚过,并发飙到 1.2 w/s,接口 P99 延迟直接冲到 2.8 s,CPU 利用率 95%+,用户排队页面卡成 PPT。监控大屏一片红,客服同学只能手动兜底,场面一度尴尬。

事后拉数据复盘,发现三大共性痛点:

  • 平均响应时间 2.1 s,其中 60% 消耗在“对话理解”环节;
  • 单节点 QPS 仅 120,横向扩容 10 台才扛住峰值,成本翻倍;
  • 失败重试风暴:超时后客户端无脑重试,导致后端雪崩。

痛定思痛,我们把 Decagon 重新“回炉”,目标只有一个——让智能客服既能“答得快”,又能“扛得住”。

性能监控大屏

协议选型:RESTful vs gRPC

先解决“最后一公里”的传输效率。同样一条 0.5 KB 的问答请求,在千兆内网下对比:

指标 RESTful(JSON) gRPC(pb)
序列化耗时 0.9 ms 0.15 ms
网络往返 3.2 ms 1.4 ms
单并发 RPS 1.8 k 4.5 k

结论:对话场景请求包小、往返多,gRPC 的 HTTP/2 多路复用 + Protobuf 二进制序列化优势明显。最终选型:

  • 内部微服务全部切 gRPC;
  • 对外开放仍保留 RESTful,方便老系统兼容,通过 Envoy 做协议转换。

核心实现三板斧

1. 带指数退避的重试机制

无论选什么协议,网络抖动都不可避免。我们封装了统一 SDK,默认策略:

  • 最多 3 次重试;
  • 退避基数 200 ms,指数 2,最大间隔 5 s;
  • 异常细分:可重试(超时/502/503) vs 不可重试( 4xx 业务异常)。

Python 示例(Java 版思路完全一致,用 resilience4j 即可):

import os, time, random, requests
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter

RETRY_TOTAL = int(os.getenv("DECAGON_RETRY_TOTAL", "3"))
BACKOFF_FACTOR = float(os.getenv("DECAGON_BACKOFF_FACTOR", "0.2"))

def call_decagon(query: str, uid: str) -> str:
    sess = requests.Session()
    retry = Retry(total=RETRY_TOTAL,
                  backoff_factor=BACKOFF_FACTOR,
                  status_forcelist=[502, 503, 504],
                  allowed_methods=frozenset(['POST']))
    sess.mount("https://", HTTPAdapter(max_retries=retry))
    try:
        rsp = sess.post("https://decagon-api/chat",
                        json={"q": query, "uid": uid},
                        timeout=1.5)
        rsp.raise_for_status()
        return rsp.json()["answer"]
    except requests.exceptions.RequestException as e:
        # 记录日志、告警、返回兜底文案
        logger.exception("decagon error")
        return "系统繁忙,稍后再试"

要点:所有配置走环境变量,方便 K8s 不同环境注入;超时时间 ≤1.5 s,避免重试“拖”住线程池。

2. 对话状态机 Redis 缓存

Decagon 的“多轮对话”依赖状态机:userId → 当前节点 + 槽位数据。每次请求都要回写 DB,高并发下 DB 成为瓶颈。

优化思路:Redis 缓存 + 异步刷盘。

  • key: decagon:state:{userId},value 为 Protobuf 序列化后的二进制,TTL 15 min;
  • 写操作先写 Redis,再抛消息到 Kafka,消费端批量落 MySQL;
  • 采用 Lua 脚本保证“读-改-写”原子性,避免并发覆盖。
-- set_state.lua
local key = KEYS[1]
local new = ARGV[1]
local ttl = tonumber(ARGV[2])
redis.call("SET", key, new, "PX", ttl)
return 1

分布式锁:当同一用户并发进入多节点时,用 Redlock 保证单节点修改,锁超时 200 ms,防止死锁。

3. 突发流量限流算法

重试 + 缓存解决后,仍可能被外部流量打爆。我们自研令牌桶 + 漏桶双层限流:

  • 令牌桶:接口级,保证微服务自身不超 5 k/s;
  • 漏桶:用户级,单 UID 最大 10 req/s,防止“热点用户”。

Go 代码片段(生产环境已编译为 SO,Java 通过 JNI 调用):

type Limiter struct {
    rate  int
    burst int
    bucket chan struct{}
}

func NewLimiter(rate, burst int) *Limiter {
    l := &Limiter{
        rate:   rate,
        burst:  burst,
        bucket: make(chan struct{}, burst),
    }
    // 预填充
    for i := 0; i < burst; i++ {
        l.bucket <- struct{}{}
    }
    // 匀速放令牌
    go func() {
        ticker := time.NewTicker(time.Second / time.Duration(rate))
        defer ticker.Stop()
        for range ticker.C {
            select一秒一个
            case l.bucket <- struct{}{}:
            default:
            }
        }
    }()
    return l
}

func (l *Limiter) Allow() bool {
    select {
    case <-l.bucket:
        return true
    default:
        return false
    }
}

限流返回 429,客户端识别后走本地兜底缓存,避免用户“白屏”。

压测数据:优化前后对比

使用 JMeter 20 台施压机,200 并发线程,循环 5 min,采样间隔 1 s。

指标 优化前 优化后
平均 QPS dubbo 1.3 k 4.6 k
平均 RT 2.1 s 380 ms
P99 RT 2.8 s 550 ms
CPU 峰值 95% 42%
错误率 3.4% 0.12%

QPS 提升 3.5 倍,延迟降 80%,机器数从 10 台缩到 4 台,直接砍掉 60% 预算。

压测报告截图

生产环境注意事项

  1. 会话粘性处理
    如果接入层用 Nginx,记得打开 ip_hash,保证同一 UID 落到同一 Pod,避免状态机漂移;若用 K8s Ingress,可在注解里开启 sessionAffinity: ClientIP

  2. 敏感信息过滤
    对话里常出现手机号、身份证。我们在 SDK 侧加正则脱敏,再送模型;返回前同样做一层反向替换,日志端同步打码,确保合规。

  3. 冷启动预热
    Decagon 的模型容器首次拉起推理延迟高达 8 s。我们写了一个 warmup Job:启动后自动发 50 条伪请求,把 GPU 显存/CPU 缓存吃满,再注册到注册中心,保证正式流量进来时 RT 直接达标。

  4. 分布式锁选型
    用户级并发不高,用 Redis Redlock 足够;若后续做群聊、客服协同,建议升级到 DB 乐观锁,避免 Redis 失效场景下数据漂移。

开放讨论:精度与速度的天平

做完这一圈优化,我们也在反思:为了 300 ms 的 RT,把模型层剪枝 30%、缓存命中率提到 85%,确实牺牲了一些复杂问题的准确率。线上 A/B 显示,Top-1 解决率从 92% 降到 88%,但用户满意度反而提升——因为“答得快”比“答得准”更先留住人。

那么问题来了:在你的业务场景里,你会用什么指标去量化“足够好”?模型继续轻量压缩?还是把耗时模块拆到异步队列,让“快”和“准”分道扬镳?欢迎留言聊聊你的解法。

限时福利领取


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐