别再死磕固定服务器了:用 Knative 把“来多少活干多少活”玩明白
一、先说一个运维人最头疼的问题:服务器到底该准备多少?
假设你维护一个图片处理平台。

平时:
每秒 2 个请求CPU:10%内存:1GB 到了晚上:
每秒 500 个请求CPU:95%内存:7GB 最传统的办法是什么?
提前准备 10 台服务器。
问题来了:
白天怎么办?
10 台服务器 ↓真正干活的 ↓可能只有 1 台 剩下 9 台:
这就是传统固定容量架构的尴尬。
于是很多团队开始搞 Kubernetes HPA:
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata:name: image-servicespec:minReplicas: 2maxReplicas: 20targetCPUUtilizationPercentage: 70 看起来不错。
但这里其实有一个很大的问题:
CPU 并不一定代表业务压力。
比如消息队列里面积压了 10 万条消息:
Kafka│├── 100000 条消息│↓Consumer│└── CPU 可能只有 20% 这时候你盯着 CPU:
结果业务已经开始排队。
所以真正应该关注的,有时候不是:
而是:
这就是 Event-driven 思路真正有价值的地方。
二、Knative 到底解决什么问题?
Knative 可以简单理解成:
它最核心的几个组件可以粗略理解成:
┌──────────────┐│ Kubernetes │└──────┬───────┘ │ ┌───────▼───────┐ │Knative│ └───────┬───────┘ │┌──────────────┼──────────────┐│││ Serving EventingAutoscaling│││ 服务部署 事件驱动 自动伸缩 其中:
Knative Serving 主要负责服务部署和弹性伸缩。
Knative Eventing 负责:
这两个东西结合起来,就能形成一个比较完整的事件驱动平台。
三、先搞明白一个核心思想:别让服务一直等活
传统服务通常是:
启动 Pod ↓一直运行 ↓等待请求 ↓处理请求 ↓继续等待 这其实挺浪费。
Knative 更希望变成:
没有请求↓0 个实例↓来了请求↓自动启动↓处理请求↓流量下降↓自动缩容 也就是说:
这就是 Knative 最让人上头的地方。
四、先玩 Knative Serving
假设我们有一个订单服务:
order-service 最简单可以定义一个 Knative Service。
apiVersion: serving.knative.dev/v1kind: Servicemetadata:name: order-servicespec:template:metadata:annotations:autoscaling.knative.dev/minScale: "0"autoscaling.knative.dev/maxScale: "20"spec:containers:- image: myregistry/order-service:v1ports:- containerPort: 8080 这里最值得关注的是:
minScale: "0"maxScale: "20" 意思很简单:
最少:0最多:20 也就是说:
没请求 ↓0 Pod请求来了 ↓1 Pod请求继续增加 ↓2 Pod继续增加 ↓5 Pod再增加 ↓10 Pod 当然,实际扩缩容还受到并发数、启动时间、资源等因素影响。
但思想就是这么简单。
五、真正有意思的地方:事件驱动
假设我们现在做一个电商系统。
用户下单以后,并不是所有事情都应该在一个 HTTP 请求里面完成。
比如:
用户下单 │ ├── 创建订单 │ ├── 扣库存 │ ├── 生成发片 │ ├── 发送信息 │ ├── 推荐系统 │ └── 数据分析 如果全部同步执行:
POST /order│├── 订单├── 库存├── 发片├── 信息├── 推荐└── 分析 用户可能等半天。
而事件驱动的思路是:
创建订单│▼OrderCreated│ ┌────────┼────────┐ ▼▼▼库存服务 信息服务 分析服务 订单创建成功以后:
至于:
这就是事件驱动架构最核心的思想之一。
六、Knative Eventing 就是干这个的
Knative Eventing 可以把各种事件连接起来。
例如:
Kafka│▼Event Source│▼Broker│▼Trigger│▼Knative Service 你可以把它理解成一个“事件中转站”。
比如:
Kafka │ │ OrderCreated ▼Broker │ ├──── Trigger ────> inventory-service │ ├──── Trigger ────> sms-service │ └──── Trigger ────> analytics-service 这时候服务之间就不需要互相强依赖。
七、Broker:事件世界里的“快递分拣中心”
在 Knative Eventing 体系里,Broker 是一个绕不开的关键概念。
例如:
apiVersion: eventing.knative.dev/v1kind: Brokermetadata:name: default 你可以把 Broker 理解成:
生产者把事件扔进来:
Producer │ ▼Broker 然后消费者订阅:
Broker │ ├── 库存服务 ├── 订单服务 ├── 消息服务 └── 数据分析服务 这样做有一个非常明显的好处:
生产者不需要知道消费者是谁。
这点非常重要。
因为系统一旦做大,最怕的就是:
A 调 BB 调 CC 调 DD 调 EE 又调 A 最后整个系统变成:
事件驱动的一个重要价值,就是尽可能降低这种耦合。
八、Trigger:告诉系统“什么事件给谁”
比如:
apiVersion: eventing.knative.dev/v1kind: Triggermetadata:name: order-triggerspec:broker: defaultfilter:attributes:type: com.example.order.createdsubscriber:ref:apiVersion: serving.knative.dev/v1kind: Servicename: order-service 这段配置其实很好理解。
它说的是:
于是:
OrderCreated │ ▼Broker │ ▼ Trigger │ ▼order-service 这就开始有点“事件总线”的味道了。
九、最爽的一点:事件来了,服务才启动
假设凌晨 3 点。
系统:
订单服务:0 Pod库存服务:0 Pod信息服务:0 Pod分析服务:0 Pod 这时候突然来了一个事件:
OrderCreated Knative 发现:
于是:
0 Pod ↓启动 ↓1 Pod ↓处理事件 如果突然来了 10000 个事件:
10000 Events │ ▼ Broker │ ▼Autoscaler │ ├── Pod 1 ├── Pod 2 ├── Pod 3 ├── ... └── Pod N 这才是真正意义上的:
十、但这里有一个坑:冷启动
很多人看到 Knative 的:
0 → 1 非常兴奋。
但运维人不能只看到“省钱”。
因为:
0 Pod ↓创建 Pod ↓拉镜像 ↓启动容器 ↓加载应用 ↓应用 Ready ↓开始处理请求 这一套是需要时间的。
如果你的应用启动需要:
8 秒 那么用户可能就会感受到:
这就是 Knative 的经典问题:
Cold Start,冷启动。
所以我的观点一直比较明确:
十一、解决冷启动,不要一上来就想着“全部 0 副本”
比如核心支付服务:
autoscaling.knative.dev/minScale: "1" 保证至少一个实例。
而一些非核心服务:
autoscaling.knative.dev/minScale: "0" 允许缩到 0。
于是:
核心服务 ↓至少 1 个低频服务 ↓允许 0 个 这其实比:
靠谱得多。
架构设计从来不是追求一个参数走天下。
十二、再来看一个完整架构
我们假设现在做一个订单事件平台:
用户 │ ▼┌─────────────┐│ API Gateway │└──────┬──────┘ │ ▼┌─────────────┐│ Order API │└──────┬──────┘ │ │ OrderCreated ▼┌─────────────┐│ Broker│└──────┬──────┘ │┌────────────┼────────────┐│││▼▼▼ Inventory SMS Service Analytics Service│││▼▼▼DB SMSData Lake 而每一个服务:
Knative Service │ ▼ Autoscaler │ ┌─────┼─────┐ ▼ ▼ ▼Pod Pod Pod 最终形成:
这才是比较完整的事件驱动平台思路。
十三、什么时候特别适合 Knative?
我个人认为,下面几类业务非常适合。
第一类:流量波动特别大
比如:
平时:10 QPS活动:10000 QPS 这种场景固定扩容特别浪费。
第二类:异步任务
例如:
图片处理视频转码PDF解析AI推理报表生成数据清洗 这些业务通常:
有任务 → 干活没任务 → 休息 跟 Knative 的思想非常匹配。
第三类:事件驱动系统
例如:
订单创建库存变化支付成功物流更新用户注册设备上线 这些天然就是 Event-driven。
十四、但不是所有系统都适合 Knative
这一点我特别想强调。
不要因为:
就把所有服务全部迁过去。
比如一个:
数据库连接池特别重启动需要 30 秒本地缓存几十 GB 的服务。
你让它:
0 → 1 → 0 → 1 → 0 可能直接把自己玩崩。
还有一些:
长连接WebSocket超低延迟强状态服务 也需要谨慎设计。
所以 Knative 最适合的是:
十五、运维人的思维也应该变一下
以前我们做运维,经常问:
现在应该逐渐开始问:
以前:
CPU > 80% ↓扩容 现在:
事件积压 ↓扩容 以前:
服务器 ↓24小时运行 现在:
事件 ↓服务 ↓实例 ↓处理完成 ↓缩容 这其实是一种非常明显的思维变化。
十六、最后聊聊我的一个观点
我一直觉得,Knative 真正有价值的地方,并不是:
这只是表面。
真正重要的是:
以前是:
先买资源 ↓等业务 现在逐渐变成:
业务来了 ↓需要资源 ↓自动创建 ↓业务结束 ↓自动释放 这才是云原生真正有意思的地方。
但也别把 Serverless 想得太美。
冷启动怎么处理、事件为什么会丢、消息重复如何兜底、幂等性怎么保证、可观测性是否到位、链路追踪能不能打通、事件顺序如何&维持、失败后怎样重试、死信队列又该怎么设计……
这些问题一个都不会因为用了 Knative 就自动消失。
相反,系统越弹性,运维越应该关注:
事件有没有丢?事件处理了几次?为什么重试?消费者为什么变慢?为什么突然扩容?为什么一直 Scale to Zero?为什么冷启动这么慢? 所以我更愿意把 Knative 看成一种架构思想的升级:
这句话,可能才是 Knative 最值得我们琢磨的地方。
写在最后
如果让我用一句最接地气的话总结 Knative:
Kubernetes 解决的是:
Knative 解决的是:
Eventing 解决的是:
三者组合起来:
Kubernetes Knative Serving Knative Eventing↓弹性事件驱动平台 而这可能也是未来云原生平台越来越重要的一条路线:
基础设施不应该一直等着业务,而应该随着业务一起“呼吸”。
这,才是我理解的 Event-driven。
