基于腾讯云TKE与vLLM的AI写作服务弹性伸缩与推理加速实践
基于腾讯云TKE与vLLM的AI写作服务弹性伸缩与推理加速实践
1. 业务痛点与目标
我们的AI写作业务需要为数千家电商客户实时生成营销文案,日均调用量超50万次。早期使用云上GPU裸金属服务器,面临三大难题:

本文记录我们如何基于腾讯云TKE(容器服务)、vLLM推理引擎、CLS日志和弹性伸缩,构建了一套成本降低60%、P99延迟稳定在450ms、支持灰度发布的AI写作服务。所有调优参数和压测数据均来自线上真实环境。
2. 整体架构与腾讯云产品选型
组件 | 腾讯云产品/自建 | 作用与理由 |
|---|---|---|
容器编排 | TKE(托管集群) | 免运维Master,集成GPU调度,支持Spot实例 |
GPU节点 | 竞价实例(GN7.2XLARGE32) | 成本为按量付费的30%,适合无状态推理 |
模型存储 | 对象存储COS | 存放基座模型和LoRA权重,跨可用区高可用 |
推理引擎 | vLLM(自建镜像) | 高吞吐,支持LoRA热加载,无需重启 |
缓存层 | 云数据库Redis | 缓存高频prompt结果,命中率约40% |
日志与监控 | CLS Prometheus | CLS采集容器日志,Prometheus抓取vLLM指标(请求数、延迟、GPU利用率) |
弹性伸缩 | HPA CronHPA | 基于QPS伸缩,同时定时扩缩应对早晚高峰 |
3. 模型微调与权重管理(基于COS)
3.1 数据构建与LoRA训练
使用电商文案数据集(10万条),采用QLoRA微调Qwen2-7B。训练脚本采用LLaMA-Factory,训练完成后将生成的adapter_model.bin上传至COS桶(路径:cos://ai-models/lora/marketing-v2/)。
关键优化:训练时将lora_alpha设为32,lora_dropout设为0.05,避免过拟合;训练3个epoch后,在验证集上困惑度从2.1降至1.3。
3.2 权重热加载机制
vLLM支持从本地或远程HTTP加载LoRA,但我们利用COSFS将COS挂载到TKE Pod的/models目录,实现启动时自动拉取最新权重:
# 在Deployment中增加COSFS挂载volumes:- name: model-storageflexVolume:driver: "cosfs"options:bucket: "ai-models-125xxxxxx"url: "https://cos.ap-guangzhou.myqcloud.com"path: "/lora"
这样,每次更新LoRA只需替换COS中的文件,vLLM通过--lora-modules指定路径,无需重启Pod(vLLM支持动态加载)。
4. 推理服务构建与性能调优(核心代码)
4.1 vLLM启动参数精调
基于多轮压测,我们确定最佳启动参数:
代码语言:ja vascript复制python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2-7B-Instruct --enable-lora --lora-modules marketing=/models/lora/marketing-v2 --max-num-seqs 64 --max-model-len 8192 --gpu-memory-utilization 0.92 --block-size 16 --max-num-batched-tokens 16384 --disable-log-requests# 减少日志IOmax-num-seqs:从默认的32提升到64,核心目的就是增强并发批处理能力;当然,这个参数不是越大越好,显存得跟得上,A100 40G基本可以承受。block-size=16:这样设置可以更好地控制内存碎片,吞吐通常能提升约8%。max-num-batched-tokens:用于限制单次迭代处理的 token 数,避免长序列把整体延迟直接拉高。
4.2 FastAPI封装与异步缓存
这里没有直接采用 vLLM 自带的 OpenAI 接口,而是额外做了一层自定义封装,补充支持temperature、top_p、presence_penalty等参数,同时接入 Redis 缓存机制(只针对精确匹配的 prompt 生效)。代码片段:
from fastapi import FastAPI, BackgroundTasksimport redis.asyncio as redisimport timeimport hashlibapp = FastAPI()redis_client = redis.Redis(host=os.getenv("REDIS_HOST"), port=6379, decode_responses=True)# 预先初始化vLLM引擎(使用AsyncLLMEngine)from vllm import AsyncLLMEngine, SamplingParamsfrom vllm.lora.request import LoRARequestengine = AsyncLLMEngine.from_engine_args(...)# 同上@app.post("/v1/writing")async def writing(request: WritingRequest):# 缓存键cache_key = hashlib.md5(f"{request.prompt}_{request.temperature}".encode()).hexdigest()cached = await redis_client.get(cache_key)if cached:return {"result": cached, "source": "cache"}# 构造Qwen2聊天模板(使用transformers tokenizer)tokenizer = get_tokenizer()# 全局单例messages = [{"role": "system", "content": "你是专业文案助手"}, {"role": "user", "content": request.prompt}]formatted = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)sampling_params = SamplingParams(max_tokens=request.max_tokens,temperature=request.temperature,top_p=0.9,presence_penalty=0.1)lora_req = LoRARequest("marketing", 1, "/models/lora/marketing-v2")# 异步生成,设置超时try:result = await asyncio.wait_for(engine.generate(formatted, sampling_params, lora_request=lora_req),timeout=10.0)text = result.outputs[0].textexcept asyncio.TimeoutError:raise HTTPException(408, "Generation timeout")# 异步写入缓存(TTL=1小时)background_tasks.add_task(redis_client.setex, cache_key, 3600, text)return {"result": text, "source": "model"}
性能优化点:
使用async全链路,避免阻塞事件循环;设置timeout防止个别请求拖垮整个引擎(vLLM内部有超时机制,但需应用层配合);缓存异步写入,不阻塞返回。5. 弹性伸缩与成本优化(基于TKE)
5.1 指标采集与HPA配置
我们通过Prometheus采集vLLM的vllm:num_requests_running和vllm:request_success_total,自定义QPS指标。利用腾讯云TKE的自定义指标HPA:
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata:name: writing-hpanamespace: prodspec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: writing-deployminReplicas: 2maxReplicas: 20metrics:- type: Podspods:metric:name: qps_per_pod # 由Prometheus adapter暴露target:type: A verageValuea verageValue: 50# 每个Pod目标QPS=50
同时我们使用CronHPA(腾讯云提供)在每日9:00-11:00和20:00-22:00高峰时段提前扩容至10个副本,避免冷启动延迟。
5.2 使用竞价实例降低计算成本
在TKE节点池中,我们混合使用按量付费节点(保留2个)和竞价实例节点(动态伸缩)。竞价实例价格低但可能被回收,为此我们:
为Pod设置podAntiAffinity,确保至少1个Pod落在按量节点;利用TKE的节点池自动伸缩,当竞价实例回收时,自动补充按量节点;监控竞价实例中断事件,通过CLS告警通知。配置示例:
代码语言:ja vascript复制nodeSelector:node.kubernetes.io/instance-type: gn7.2xlargetolerations:# 允许调度到竞价节点- key: "spot"operator: "Equal"value: "true"effect: "NoSchedule"
实际运行三个月,竞价实例平均中断率约5%,但通过快速重调度,服务可用性维持在99.99%。
6. 日志与监控(CLS Grafana)
6.1 CLS日志采集结构化
在TKE中启用CLS日志组件,采集容器stdout和日志文件。我们自定义日志格式为JSON,方便检索:
代码语言:ja vascript复制import structloglogger = structlog.get_logger()logger.info("generation_success", prompt_length=len(prompt), tokens=len(text), latency=latency_ms)
把 CLS 的索引配置好之后,定位某个用户对应的请求链会快很多,排查问题时尤其省事。同时还可以顺手把告警规则配上:比如错误率一旦超过 5%,或者 P99 延迟高于 800ms,就立即触发微信通知。
6.2 关键指标看板
Grafana面板展示:
实时QPS / 平均延迟 / P99延迟GPU显存使用率、温度缓存命中率副本数量变化曲线这些数据帮助我们持续调优max-num-seqs和targetQPS阈值。
7. 压测结果与最终性能
使用腾讯云性能测试服务PTS,模拟真实流量(包含不同长度prompt,平均输入200 token,输出150 token),对比调优前后:
配置 | 平均延迟(ms) | P99延迟(ms) | 吞吐量(req/s/GPU) | 单月成本(元) |
|---|---|---|---|---|
基线(HF 原生服务) | 920 | 3200 | 12 | 105,000 |
优化后(vLLM 缓存 弹性伸缩) | 410 | 720 | 38 | 42,000 |
8. 灰度发布与LoRA快速迭代
我们通过TKE的滚动更新配合服务加权(使用Istio或腾讯云CLB),实现金丝雀发布:
新建Deploymentwriting-deploy-canary,加载新LoRA权重(COS路径不同);在CLB配置转发规则,将10%流量导入灰度版本;观察延迟和错误率,若无异常则逐步切流,最终替换主版本。整个过程无需停机,用户无感知。
9. 总结与踩坑记录
关键收获:
vLLM的max-num-seqs并非越大越好,需根据显存和请求长度动态调整(我们通过反复测试定为64);Redis缓存策略要避免缓存穿透(可以缓存空值或默认文案);竞价实例的优雅退出:为Pod添加preStop钩子,等待已有请求处理完毕再销毁。未来规划:引入腾讯云TI-ONE进行自动化模型训练和版本管理,进一步减少人工干预。
附录:完整Deployment YAML示例
代码语言:ja vascript复制apiVersion: apps/v1kind: Deploymentmetadata:name: writing-deployspec:replicas: 3strategy:rollingUpdate:maxSurge: 1maxUna vailable: 0selector:matchLabels:app: writingtemplate:metadata:labels:app: writingspec:containers:- name: vllmimage: ccr.ccs.tencentyun.com/ai/writing:v2resources:limits:nvidia.com/gpu: 1memory: 64Gicpu: 16requests:nvidia.com/gpu: 1memory: 32Gicpu: 8ports:- containerPort: 8000env:- name: REDIS_HOSTvalue: "redis.prod.svc.cluster.local"- name: COS_MOUNTvalue: "/models"volumeMounts:- name: model-storagemountPath: /modelsreadinessProbe:httpGet:path: /healthport: 8000initialDelaySeconds: 120lifecycle:preStop:exec:command: ["sh", "-c", "sleep 30"]# 等待已有请求volumes:- name: model-storageflexVolume:driver: "cosfs"options:bucket: "ai-models-125xxxxxx"url: "https://cos.ap-guangzhou.myqcloud.com"path: "/"nodeSelector:node.kubernetes.io/instance-type: gn7.2xlargetolerations:- key: "spot"operator: "Equal"value: "true"effect: "NoSchedule"
本文所有调优参数、YAML配置和代码均脱敏自线上环境,已在腾讯云TKE集群稳定运行超过4个月。欢迎在评论区交流,我会分享更多压测数据和调优细节。
-
下载
-
- 关于柯南的沙雕网名有哪些
- 角色扮演 | 1
- 网名
-
- 最新中性名字男女通用网名有哪些
- 角色扮演 | 1
- 网名
-
- 关于蓝色说唱的网名有哪些
- 角色扮演 | 1
- 网名
-
- 我好喜欢你是什么梗?
- 角色扮演 |