Serverless 解耦的代价:当基础设施黑盒化,我们失去了什么?
写在前面
- 博文不是反对
Serverless,而是讨论它在黑盒化之后的真实代价 - 重点从
控制权让渡、底层性能优化失效、排障困难、厂商锁定和成本边界几个角度展开 - 最后给出三类折中方案:
Serverless 容器、自托管 Serverless、场景专用平台 - 理解不足小伙伴帮忙指正 😃,生活加油
Serverless 让业务与基础设施解耦,也同时让控制权、可观测性和底层优化空间一起被黑盒化。
持续分享技术干货,感兴趣小伙伴可以关注下 _
解耦,是Serverless的灵魂,也是枷锁
Serverless 无疑是过去十年云原生领域最具革命性的架构之一。它彻底重构了应用的研发与交付模式,让研发人员无需再关注服务器采购、环境配置、容量规划、运维监控等底层工作,实现了业务编码与基础设施的极致解耦——你只需要写好核心业务代码,剩下的服务器调度、扩容、容错、运维全交给云厂商,代码不运行时甚至一分钱都不用花。
这种极致的解耦,让无数小型业务、事件驱动型应用摆脱了基础设施的枷锁,极大提升了研发效率。但软件工程的核心定律永远生效:没有银弹,只有Trade-off。极致的解耦,必然带来极致的黑盒化;极致的免运维,必然带来极致的控制权让渡。
当我们欢呼着把基础设施全交给云厂商时,很少有人认真思考:这种黑盒化,到底让我们付出了什么代价?那些我们赖以提升系统性能、保障稳定性的内核级、硬件级优化,在Serverless的黑盒中,又该何去何从?
一、解耦的本质:是效率的提升,更是控制权的全面让渡
要理解Serverless的代价,首先要认清它解耦的本质。
传统的开发模式中,业务代码与基础设施是深度耦合的:你既要写业务逻辑,也要管服务器的操作系统、内核参数、网络配置、CPU调度,甚至要应对服务器宕机、容量不足等问题。你的业务优化,往往是与基础设施的优化深度绑定的。
而Serverless的解耦,本质是把基础设施的全生命周期管理权,完全让渡给了云厂商。它给你划定了一个清晰的权限边界:你只拥有**用户态业务代码的执行权限**,除此之外,从虚拟化层、Guest 内核、宿主机操作系统,到物理服务器的CPU、内存、网卡,所有底层基础设施的控制权,全部被云厂商锁死。
这就像你开一家餐厅,传统模式是你既要研发菜品,也要自己租店面、装修厨房、采购设备、管控后厨;而Serverless模式,你只需要把菜品配方(业务代码)交给中央厨房,所有的后厨、设备、人员、运维全由对方负责。你确实不用再管厨房的琐事,但同时也彻底失去了对厨房的控制权——你没法调整炉灶的火力,没法定制厨具的规格,甚至没法知道你的菜品是在哪个厨房、用什么设备做出来的。
而这种控制权的全面让渡,正是Serverless所有核心痛点的根源。
二、黑盒化的致命伤:底层性能优化的全面失效
对于高性能、低延迟的生产级应用而言,内核级、硬件级的深度优化,是保障系统性能的核心手段。但在标准的公有云Serverless环境中,这些优化几乎全部失效,甚至连对应的性能瓶颈都无法定位。
2.1 网络层内核级优化:完全没有落地空间
在高频交易、大数据传输、AI 推理等场景中,网络性能往往是系统的核心瓶颈。我们常用的优化手段——控制包大小不超MTU避免拆包、内核零拷贝减少二次拷贝、调整TCP参数优化传输效率、eBPF/XDP绕过内核栈等,在Serverless环境中全链路受限。
以最基础的MTU优化为例:我们通常会将MTU调整为9000字节巨帧,减少TCP拆包次数,降低内核网络栈的中断与二次拷贝开销,这是提升网络吞吐量、降低延迟的基础操作。但在Serverless环境中,从宿主机内核、VPC虚拟网关到MicroVM的虚拟网卡,全链路的MTU、TCP拥塞控制算法、滑动窗口大小等内核参数,都是云厂商为多租户场景统一固化的。你既没有root权限修改MicroVM的Guest 内核参数,更无法触及宿主机与网关的网络配置,所有针对网络栈的内核级优化,完全没有落地空间。
更不用说零拷贝、DPDK、XDP这类高性能网络技术:它们要么需要定制内核开启对应的模块,要么需要独占网卡与root权限。而以AWS Lambda为代表的Serverless平台,底层基于Firecracker MicroVM实现多租户隔离,Guest 内核是云厂商极致裁剪后的极简版本,只保留了Serverless场景必需的内核特性,不仅没有开启相关模块,甚至不允许加载任何自定义内核模块。你连内核网络栈的运行状态都看不到,更别说做针对性的优化。
2.2 CPU/内存硬件级优化:彻底不可控
对于高性能计算、AI 推理、低延迟业务而言,CPU与内存的深度优化,是拉开性能差距的核心。你提到的缓存行预读、指令填充、避免伪共享的数据对齐、CPU 亲和性、内存带宽配置等优化手段,在Serverless环境中,不仅效果无法保证,甚至可能完全失效。
首先是**CPU 亲和性与NUMA优化的彻底失效**。在低延迟场景中,我们会通过CPU 亲和性绑定,将业务进程固定到特定的物理CPU核心,避免进程上下文切换带来的延迟;通过NUMA节点优化,避免进程跨节点访问内存,降低内存访问延迟。但在Serverless环境中,函数实例的生命周期是临时的,每次冷启动都会被调度系统分配到不同的宿主机、不同的vCPU上,甚至vCPU本身就是跨NUMA节点超分的。你不仅无法获知vCPU与宿主机物理核心的映射关系,更无法修改内核的调度策略,哪怕你在代码中实现了CPU绑定逻辑,在黑盒的虚拟化层也会完全失效,精心设计的优化最终毫无意义。
其次是**缓存行与伪共享优化的效果归零**。你在代码中做了64 字节缓存行对齐、避免伪共享、数据预读优化,本质是为了充分利用CPU的L1/L2 缓存,提升内存访问效率。但Serverless的多租户模型中,你的vCPU是和其他租户共享物理核心的——你精心优化到缓存里的数据,随时可能被其他租户的代码冲刷干净,优化效果直接归零,甚至可能因为对齐占用了更多缓存空间,反而导致性能下降。
更不用说指令级优化、CPU 频率锁定、内存带宽限流等更深层的优化:云厂商的物理CPU集群往往是异构的,你的函数这次调度到支持AVX-512指令集的CPU上能正常运行,下次调度到不支持的CPU上就直接报错;CPU的睿频、性能模式、内存带宽上限,全由厂商统一控制,你连瓶颈是不是内存带宽不足都查不出来——因为Serverless环境的/proc文件系统是阉割的,perf、bcc等性能分析工具根本无法运行,你看不到任何内核态、硬件层的性能指标。
三、连锁反应:黑盒化给应用侧带来的系统性风险
基础设施的黑盒化,带来的不仅仅是底层优化的失效,更会给应用侧带来一系列连锁的系统性风险,甚至直接决定了业务架构的上限。
3.1 性能排障与根因定位完全无解
Serverless环境中,你能拿到的只有「运行时长、错误率、内存使用率」这类表层业务指标。一旦出现延迟飙升、吞吐量上不去、偶发超时等问题,你根本无法定位根因:你没法用perf抓内核态火焰图,没法用tcpdump抓包分析网络链路,没法用bcc追踪系统调用,连进程的CPU调度状态、内存缺页情况都看不到。
你不知道是宿主机超分导致CPU被限流,还是网络栈拥塞导致延迟,还是内核态软中断过高,还是其他租户的「吵闹邻居」影响了你的实例。最终只能靠瞎猜、换配置、找厂商技术支持,排障效率从小时级拉长到天级,甚至根本找不到根因。我曾见过某电商团队,大促期间Serverless函数出现大面积超时,延迟从100ms飙升到2s以上,花了3 天才定位到是宿主机超分导致的资源争抢,而在此期间,业务已经造成了不可挽回的损失。
3.2 厂商强锁定,架构迁移成本极高
很多人以为Serverless实现了业务与基础设施的解耦,但实际上,它只是把业务和通用服务器解耦了,却和特定云厂商的Serverless平台做了深度强绑定。
你的代码会深度依赖厂商的触发体系、权限模型、运行时、配套服务(比如Lambda对接S3、DynamoDB),一旦要从AWS换到阿里云、从公有云换到私有部署,代码要大改甚至完全重写。每个厂商的黑盒能力、限制规则完全不同:Lambda最长运行15 分钟、内存最大10GB,而部分厂商的函数最长只能运行3 分钟、内存最大4GB,你为了适配厂商的限制,必须修改业务架构,完全失去了技术自主权。
3.3 冷启动硬伤完全不可控,架构适配成本极高
Serverless「用完即毁」的模型,带来了天生的冷启动问题,而这个问题你几乎无法通过技术优化解决,只能被动接受厂商的规则。
哪怕Firecracker把MicroVM的冷启动做到了百毫秒级,空闲实例被销毁后的冷启动延迟,还是会严重影响用户体验。你没法让实例常驻、没法自己做预热,只能花钱买厂商的「预留并发」,不仅成本飙升,还是只能在厂商给的规则里折腾。更关键的是,冷启动的时长完全不可控,这次100ms,下次可能1s,你不知道厂商的集群资源水位、调度策略,没法做针对性的优化,只能被动适配。
3.4 有状态、长连接场景天生不兼容
Serverless的无状态、临时实例模型,和有状态、长连接场景天生冲突。你没法在内存里做热点数据缓存,没法维持数据库连接池、WebSocket长连接,因为实例随时会被销毁,你做的池化优化、长连接复用,下次冷启动就全部失效,反而增加了建连开销。哪怕用厂商的配套服务做状态管理,也会被进一步锁定,同时增加链路延迟和架构复杂度。
3.5 规模增长后极易成本失控
Serverless按需付费的模式,对小体量应用非常友好,但一旦业务规模上去,成本极易失控,而且你几乎没有降本空间。
当函数调用量达到千万级、亿级时,按需付费的成本,往往是常驻服务器的3-10 倍。而你能做的降本手段,只有优化代码运行时长,没法通过底层优化(比如CPU绑核、网络调优)进一步提升资源利用率,因为底层完全是黑盒。更不用说厂商的计费规则完全不透明,网络流量、存储、调用次数、跨可用区访问都有隐藏费用,你很难精准预估成本,很容易出现账单超支的情况。
四、一个适合 Serverless 的实战案例:对象存储图片处理链路
讲了这么多 Serverless 的边界,并不意味着它“不该用”。恰恰相反,只要场景选对,Serverless 依然是非常高效的工程工具。一个非常典型、也非常适合落地的例子,就是对象存储上传后的图片异步处理链路。
比如一个电商或内容平台,用户上传原图之后,后端往往还要做几件事:
- 生成
缩略图 - 转换成
WebP/AVIF - 提取图片宽高、大小、
EXIF等元数据 - 写回数据库或
消息队列,通知后续业务系统
这种链路非常适合 Serverless,原因很直接:
- 它是典型的**
事件驱动** - 单次任务执行时间通常较短
- 天然
无状态,处理完即可退出 - 流量波动大,但没有必要长期保留一组常驻机器
一个非常常见的落地架构是:
- 用户上传图片到对象存储桶
- 对象存储事件触发
Serverless函数 - 函数拉取原图并完成压缩、缩略图生成、格式转换
- 处理结果重新写回对象存储
- 同时把元数据写入数据库,或者推送到
消息队列
如果用 AWS 的术语,这条链路通常就是:
S3负责存原图和处理后的图片Lambda负责执行图片处理逻辑DynamoDB/RDS/SQS/EventBridge负责存储结果或衔接后续流程
下面给一个简化版的 Python 示例,演示“上传图片后自动生成缩略图并回写”的核心逻辑:
import io
import os
import boto3
from PIL import Image
s3 = boto3.client("s3")
THUMBNAIL_SIZE = (320, 320)
TARGET_PREFIX = os.environ.get("TARGET_PREFIX", "thumb/")
def handler(event, context):
record = event["Records"][0]
bucket = record["s3"]["bucket"]["name"]
key = record["s3"]["object"]["key"]
if key.startswith(TARGET_PREFIX):
return {"message": "skip generated file"}
response = s3.get_object(Bucket=bucket, Key=key)
image_bytes = response["Body"].read()
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
image.thumbnail(THUMBNAIL_SIZE)
output = io.BytesIO()
image.save(output, format="WEBP", quality=80)
output.seek(0)
target_key = f"{TARGET_PREFIX}{key.rsplit('.', 1)[0]}.webp"
s3.put_object(
Bucket=bucket,
Key=target_key,
Body=output,
ContentType="image/webp",
)
return {
"source": key,
"thumbnail": target_key,
"status": "ok",
}
这个例子里,Serverless 的优势非常明显:
- 没有流量时几乎零成本,不需要为“偶发上传”养一台常驻图片处理机
- 峰值弹性很好,活动期间上传量暴涨时,函数实例可以快速
横向扩展 - 链路天然解耦,上传、处理、回写、通知可以拆成多个
事件节点 - 工程复杂度低,团队不用自己维护一套图片处理
Worker集群
但这个例子也恰好能说明本文的核心观点:Serverless 不是万能的,它适合的是“短时、无状态、事件驱动”的任务。
如果你把它拿去做下面这些事情,就会立刻踩到边界:
- 长时间运行的
视频转码 高并发、低延迟的在线图像推理- 需要
本地缓存、连接池、热数据常驻的处理服务 - 对
CPU指令集、内存带宽、文件系统吞吐有强要求的任务
一旦任务开始依赖底层资源的稳定性、可观测性和深度调优能力,Serverless 的黑盒化问题就会迅速放大。也就是说,这个图片处理案例不是为了证明 Serverless 无所不能,而是为了说明:它在自己擅长的边界内,确实很好用。
五、破局之路:在解耦与控制权之间找到平衡
我们批判Serverless的黑盒化,并不是否定它的价值——它依然是无状态业务、事件驱动任务的最优架构之一。我们真正要做的,是在「解耦带来的研发效率」和「控制权带来的优化空间」之间,找到适合自己业务的平衡点。
这里有三个成熟的折中方案,覆盖了绝大多数场景的需求:
方案1:Serverless 容器——平衡免运维与控制权的最优解
如果你想要Serverless的免运维、弹性能力,同时需要一定的底层定制能力,优先选择**Serverless 容器服务**(AWS Fargate、阿里云 ECI、Azure Container Instances)。
这类服务保留了按需付费、免节点运维的核心特性,同时给了你完整的容器root权限:你可以自由调整内核参数、配置CPU 亲和性、加载必要的内核模块,支持绝大多数用户态的性能优化,只是无法控制宿主机底层。它既保留了Serverless的效率优势,又给了你足够的定制空间,是绝大多数业务的平衡之选。
方案2:自托管 Serverless 框架——完全控制权 + Serverless 体验
如果你需要完全的基础设施控制权,同时想要Serverless的弹性伸缩、事件驱动研发体验,可以选择**自托管 Serverless 框架**(Knative、OpenFaaS、KubeEdge)。
这类框架基于Kubernetes构建,你可以完全控制底层的服务器、内核、网络配置,同时保留了Serverless的自动扩缩容、版本管理、事件触发等核心能力。代价是需要自己运维Kubernetes集群,失去了完全免运维的优势,适合有一定运维能力、对数据合规与控制权有强要求的团队。
方案3:场景专用 Serverless 平台——垂直场景的定制化能力
如果你是AI 推理、高性能计算等特定场景的用户,可以选择**场景专用的 Serverless 平台**(Modal、RunPod、TensorDock)。
这类平台针对高性能场景做了深度优化,开放了CPU/GPU型号锁定、内核参数调整、持久化实例、实例预热等能力,给了极大的底层定制空间,同时保留了Serverless的极简研发体验,是AI 推理、高性能计算等垂直场景的最优选择。
六、Serverless不是银弹,认清边界才是核心
说到底,Serverless从来都不是「万能架构」,而是一款「针对性工具」。
它的核心价值,是为那些不需要深度底层优化的无状态业务、事件驱动任务,提供极致的研发效率与成本优势;而对于那些需要内核级、硬件级深度优化的高性能、低延迟场景,它的黑盒化天生就不适合。
软件工程的核心,从来都不是追逐最时髦的架构,而是为自己的业务选择最合适的架构。我们在享受Serverless解耦带来的效率提升时,也要清醒地认识到它所带来的控制权让渡与能力边界。
只有认清了这一点,我们才能真正用好Serverless,而不是被Serverless绑架。
© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)
更多推荐
所有评论(0)