当前位置: 首页 > news >正文

Knative Serving:ABP 应用的 scale-to-zero 与并发模型

Knative Serving:ABP 应用的 scale-to-zero 与并发模型 🚀


📚 目录

  • Knative Serving:ABP 应用的 scale-to-zero 与并发模型 🚀
    • 0. TL;DR 🧾
    • 1) 数据面 & 控制面 🧭
    • 2) 与 ABP(.NET)集成点 🧩
    • 3) 并发模型与扩缩判定 📈
    • 4) 冷启动与预热 ❄️🔥
    • 5) Knative Service 清单(ABP 订单服务)🧪
    • 6) 灰度与按路径路由 )🛣️
    • 7) 观测与告警 🔭
    • 8) 压测方法(k6 / hey)🧪⚙️
    • 9) 发布与回滚剧本 🧯
    • 10) ABP/.NET 落地代码片段(健康探针 / Kestrel / 限流)🧱
    • 11) 默认值与调参备忘 🧠
    • 12) FAQ ❓


0. TL;DR 🧾

  • 选择 KPA(Knative Pod Autoscaler)按 并发/RPS 伸缩,原生支持 scale-to-zero(全局开关)HPA 仅支持 CPU/内存,不支持 归零。
  • Activator0→1突发超过 TBC(Target Burst Capacity,默认 200) 时入链缓冲并触发扩容;queue-proxy 在每个 Pod 前实施 硬并发containerConcurrency)与排队并导出指标(仅当 硬并发>1 才会导出 revision_queue_depth)。
  • 冷启动治理:initial-scale(修订创建预热)+ activation-scale(from-zero 预热)+ scale-down-delay(延迟降容)+ stable-window(默认 60s)组合拳。
  • 路由/灰度:Serving 原生 按修订百分比按路径灰度 交给 Ingress/Gateway(Istio/Kong/Contour…)实现。

1) 数据面 & 控制面 🧭

ClientIngress/GatewayActivatorqueue-proxyABP App (user-container)HTTP/gRPC 请求1直达 Revision Pod2硬并发执法/必要时排队3响应4返回并上报指标5进入 Activator on-path6触发扩容并做缓冲7处理请求8响应9指标10返回;产能稳定后退出路径11alt[服务已就绪且产能足够(EBC-≥0,未触发TBC)][scale-from-zero 或 突发>TBC]ClientIngress/GatewayActivatorqueue-proxyABP App (user-container)

2) 与 ABP(.NET)集成点 🧩

  • 健康探针:区分 /healthz/ready(就绪)与 /healthz/live(存活),建议增加 startupProbe(JIT/预热慢时更稳)。
  • Kestrel/HTTP2 并发Http2.MaxStreamsPerConnection 默认 100;与 containerConcurrency 共同收敛端到端并发,避免线程耗尽。
  • 多租户 & 限流:.NET 8 RateLimiter 做租户/接口层限速/限并,叠加 queue-proxy 形成“双层背压”。

3) 并发模型与扩缩判定 📈

concurrency
rps
低于
高于
接近
queue-proxy 导出的
并发/RPS指标
KPA metric
concurrency or rps?
计算平均在途请求/Pod
计算平均RPS/Pod
处于 stable-window?
(默认60s)
是否超过 panic-threshold?
(默认 ≈ 200% of target)
进入 Panic 快速扩容
继续采样与平滑
与 target 比较
减容(受 scale-down-delay 约束)
加容
保持

关键参数

  • 软目标autoscaling.knative.dev/metric=concurrency|rps + .../target
  • 硬上限spec.template.spec.containerConcurrency(>0 启用排队;=0 不限)。
  • TBCautoscaling.knative.dev/target-burst-capacity 控制 Activator on-path(默认 200;0=仅 from-zero 入链,-1=总在链上)。
  • 惊慌窗口panic-window-percentage × window(默认 10% × 60s ≈ 6s)。

4) 冷启动与预热 ❄️🔥

true
true
true
Scale-to-zero
全局开关
initial-scale
新修订创建时拉起 N 个Pod(一次性)
activation-scale
仅在 from-zero 唤醒时拉起 N 个(一次性)
scale-down-delay
低负载保持一段时间再缩容
stable-window=60s
整段窗口无流量才可能归零

只在 KPA 下可用;切到 HPAclass=hpa.*)后最低副本≥1,无法归零。initial-scaleactivation-scale 的生效时机不同:前者→“修订创建”、后者→“从 0 唤醒”。


5) Knative Service 清单(ABP 订单服务)🧪

目标:软并发 5、硬并发 20、初始 1、上限 50;允许归零;显式 queue-proxy 资源;探针分离并加 startupProbegRPC/h2c 用端口名 h2c(不要用 networking 注解切 h2c)。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:name: abp-ordersannotations:serving.knative.dev/rollout-duration: "5m"  # 时间渐进切换;与自动伸缩无耦合
spec:template:metadata:annotations:# ---- Autoscaling (KPA) ----autoscaling.knative.dev/metric: "concurrency"autoscaling.knative.dev/target: "5"autoscaling.knative.dev/min-scale: "0"autoscaling.knative.dev/max-scale: "50"autoscaling.knative.dev/initial-scale: "1"     # 仅“修订创建”时生效autoscaling.knative.dev/activation-scale: "2"  # 仅“从0唤醒”时生效autoscaling.knative.dev/window: "60s"autoscaling.knative.dev/scale-down-delay: "30s"autoscaling.knative.dev/target-burst-capacity: "200"  # 默认 200# ---- queue-proxy 侧车资源(官方注解键名)----queue.sidecar.serving.knative.dev/cpu-resource-request: "50m"queue.sidecar.serving.knative.dev/cpu-resource-limit: "500m"queue.sidecar.serving.knative.dev/memory-resource-request: "64Mi"queue.sidecar.serving.knative.dev/memory-resource-limit: "256Mi"# 可选:queue.sidecar.serving.knative.dev/ephemeral-storage-resource-{request|limit}spec:containerConcurrency: 20containers:- image: ghcr.io/yourorg/abp-orders:1.2.3# 若为 gRPC/h2c,请把端口名设置为 h2cports:- name: h2ccontainerPort: 8080env:- name: ASPNETCORE_URLSvalue: http://0.0.0.0:8080resources:requests: { cpu: "200m", memory: "256Mi" }limits:   { cpu: "1",    memory: "512Mi" }readinessProbe:httpGet: { path: /healthz/ready, port: 8080 }periodSeconds: 5livenessProbe:httpGet: { path: /healthz/live, port: 8080 }periodSeconds: 10# 更稳的启动探针,避免JIT/预热导致反复重启startupProbe:httpGet: { path: /healthz/live, port: 8080 }failureThreshold: 30periodSeconds: 5

6) 灰度与按路径路由 )🛣️

abp-orders 流量按修订
/api/orders/*
/api/payments/*
stable 90%
canary 10%
Revision v1
Knative Service: abp-orders
Revision v2
Ingress/Gateway
Knative Service: abp-payments
  • 按修订百分比:Serving 原生支持;可加 rollout-duration 做时间渐进。
  • 按路径灰度:在 Ingress/Gateway(如 Istio VirtualService、Kong 路由)实现 path/header 区分,把不同路由打到不同 Service,各自再按修订百分比分流。

7) 观测与告警 🔭

核心指标拓扑:

Data Plane
route
direct
scale-to-zero 或 突发
metrics
p50/p95/p99
Knative Service
Ingress
queue-proxy
Pod 内 sidecar
Activator
Autoscaler/KPA
Prometheus/Grafana
* 注意:revision_queue_depth 仅在 containerConcurrency > 1 时导出

PromQL 示例(使用 container_name 选择 Activator,避免依赖 job 名):

# Activator 在途比例(近 5 分钟)
sum(rate(request_count{container_name="activator", revision_name="abp-orders"}[5m]))
/
sum(rate(revision_request_count{revision_name="abp-orders"}[5m]))# p95(queue-proxy 总时延)
histogram_quantile(0.95,sum by (le, revision_name) (rate(revision_request_latencies_bucket{revision_name="abp-orders"}[5m]))
)# 队列深度(仅当 containerConcurrency>1)
max by (revision_name) (revision_queue_depth{revision_name="abp-orders"})

💡 若启用 Service Mesh mTLS,需按发行版指引允许 Prometheus 抓取 Serving 组件指标(Activator/queue-proxy),否则面板会“空白”。


8) 压测方法(k6 / hey)🧪⚙️

目标场景

  1. 0→突发:空闲 2 分钟后 200 RPS 持续 5 分钟;
  2. 长尾低频:每分钟 3–5 个请求;
  3. 窄峰宽谷:10 分钟峰 + 20–30 分钟低频。

k6(RPS 精确控制)

// k6-burst.js
import http from 'k6/http'; import { sleep } from 'k6';
export const options = {scenarios: {burst_from_zero: { executor: 'constant-arrival-rate', rate: 200, timeUnit: '1s',duration: '5m', preAllocatedVUs: 50, maxVUs: 200 },long_tail: { executor: 'ramping-arrival-rate', startRate: 3, timeUnit: '1m',stages: [{ duration: '20m', target: 5 }] }}
};
export default () => { http.get(`${__ENV.URL}/api/orders/ping`); sleep(1); };

hey(-q 为“每 worker 的 QPS”,总 RPS ≈ q * c

# 约 200 RPS、持续 5 分钟:200 并发 * 1 qps/worker ≈ 200 rps
hey -z 5m -c 200 -q 1 -m GET "${URL}/api/orders/ping"
# 约 400 RPS:-q 2

评测输出建议:绘制 initial-scale=0/1/2 × containerConcurrency=10/20/50p95 / 冷启动命中率 / 成本 三曲线,挑选满足 SLO 的最低成本组合。


9) 发布与回滚剧本 🧯

  • 发布前检查enable-scale-to-zero=truestable-window=60starget-burst-capacity=200
  • 灰度策略:按修订百分比 1%→10%→25%→50%→100%,或用 serving.knative.dev/rollout-duration 做时间型平滑切换。
  • 快速回滚:把 traffic 切回稳定修订;必要时临时 min-scale=1/提升 activation-scale 抑制冷启动,再定位根因。

10) ABP/.NET 落地代码片段(健康探针 / Kestrel / 限流)🧱

健康探针(Program.cs)

using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;builder.Services.AddHealthChecks().AddCheck("db", () => HealthCheckResult.Healthy(), tags: new[] { "ready" });var app = builder.Build();app.MapHealthChecks("/healthz/ready",new HealthCheckOptions { Predicate = r => r.Tags.Contains("ready") });
app.MapHealthChecks("/healthz/live",new HealthCheckOptions { Predicate = _ => false });app.Run();

Kestrel/HTTP2 并发

builder.WebHost.ConfigureKestrel(o =>
{o.Limits.MaxConcurrentConnections = 1024;o.Limits.Http2.MaxStreamsPerConnection = 100; // 默认 100,可按需调
});

租户限流(.NET 8 RateLimiter)

using System.Threading.RateLimiting;builder.Services.AddRateLimiter(o =>
{o.AddPolicy("per-tenant", ctx =>RateLimitPartition.GetTokenBucketLimiter(ctx.Request.Headers["X-TenantId"].ToString() ?? "anon",_ => new TokenBucketRateLimiterOptions {TokenLimit = 50, TokensPerPeriod = 50,ReplenishmentPeriod = TimeSpan.FromSeconds(1),QueueLimit = 200, QueueProcessingOrder = QueueProcessingOrder.OldestFirst,AutoReplenishment = true}));
});
var app = builder.Build();
app.UseRateLimiter();

11) 默认值与调参备忘 🧠

  • container-concurrency-target-default = 100
  • requests-per-second-target-default = 200
  • target-burst-capacity = 200
  • stable-window = 60spanic-window-percentage = 10%(惊慌窗口≈6s)
  • activation-scale from-zero 生效;initial-scale 修订创建时生效
  • revision_queue_depth:仅当 containerConcurrency > 1 才会导出

12) FAQ ❓

  • 切到 HPA 为啥不能归零? → HPA 最低副本≥1;只有 KPA 支持 scale-to-zero。
  • containerConcurrency vs target → 前者是 硬上限(触发排队),后者是 软目标(指导扩缩)。
  • Activator 是否影响时延? → 看 Activator request_count/latencies 与服务侧 p95 的联动;必要时调高 activation-scale/TBC
  • revision_queue_depth 没数据? → 设置 containerConcurrency > 1 才会导出该指标。
  • gRPC/h2c 怎么启用? → 将容器端口 命名为 h2c(或配相应 appProtocol);不要用 networking 注解去切 h2c。
http://www.xdnf.cn/news/1474237.html

相关文章:

  • 【Python 】入门:安装教程+入门语法
  • 使用 C# .NETCore 实现MongoDB
  • OpenAI新论文:Why Language Models Hallucinate
  • 【黑客技术零基础入门】2W字零基础小白黑客学习路线,知识体系(附学习路线图)
  • 【C++】C++11的可变参数模板、emplace接口、类的新功能
  • 《云原生微服务治理进阶:隐性风险根除与全链路能力构建》
  • 旧电脑改造服务器1:启动盘制作
  • Element-Plus
  • Nestjs框架: 基于权限的精细化权限控制方案与 CASL 在 Node.js 中的应用实践
  • 【Mysql-installer-community-8.0.26.0】Mysql 社区版(8.0.26.0) 在Window 系统的默认安装配置
  • Nikto 漏洞扫描工具使用指南
  • 管家婆辉煌系列软件多仓库出库操作指南
  • Kubernetes (k8s)
  • MySQL连接字符串中的安全与性能参数详解
  • Monorepo 是什么?如何使用并写自己的第三方库
  • 聊聊OAuth2.0和OIDC
  • 音转文模型对比FunASR与Faster_whisper
  • 《sklearn机器学习——聚类性能指标》Contingency Matrix(列联表)详解
  • PlantSimulation 在汽车总装车间配送物流仿真中的应用
  • Fantasia3D:高质量文本到3D内容创建工具
  • 【基础-判断】架构设计时需要考虑“一次开发,多端部署”,这样可以节省跨设备UI开发工作量,同时提升应用部署的伸缩性。
  • 【基础-判断】Background状态在UIAbility实例销毁时触发,可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。
  • wpf之TextBlock
  • Altium Designer(AD24)切换工作界面为浅灰色的方法
  • 怎么用 tauri 创建一个桌面应用程序(Electron)
  • 新手SEO优化快速起步教程
  • C++ Lambda 表达式完整指南
  • Python 正则表达式实战:用 Match 对象轻松解析拼接数据流
  • SpringAMQP
  • EMS 抗扰度在边缘计算产品电路设计的基本问题