多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Serverless架构深度实践:从范式理解到生产环境落地

Serverless架构深度实践:从范式理解到生产环境落地 Serverless这个词这几年基本是架构群里的流量话题。聊它的人多真正把它落到生产环境、并且坚持用下来的团队却不算多。我自己最早接触Serverless是在一个被运维逼疯的创业项目里没人愿意半夜爬起来重启服务也没钱为只有早晚高峰流量的业务养一堆闲置机器。当时抱着试一试的心态把一个定时任务迁到函数计算上结果发现部署、扩缩容、日志、监控全部变成了云平台的事省心程度远超预期。从那时候起我陆陆续续把不少业务模块迁到了Serverless架构上也踩过不少坑。这篇就把我对Serverless架构模式的理解、选型思路、实操过程以及生产环境里遇到过的问题一次性写清楚。如果你是后端工程师、架构师或者团队正在评估要不要用Serverless这篇应该能省你不少调研时间。Serverless不是简单的“服务器不用管了”它背后是一整套事件驱动、按量计费、自动扩缩容的软件架构范式。它解决的是传统服务里最蛋疼的两个问题资源利用率低、运维成本高。同时它也带来了新的约束无状态、冷启动、超时限制、第三方服务强绑定。这篇文章会从范式本身讲起再到一个订单通知服务的完整落地过程最后把生产环境常见的坑和排查思路一个个拆开。适合想系统理解Serverless而不是只停留在“能跑一个函数”阶段的读者。1. 先想清楚Serverless到底改变了什么1.1 从“买服务器”到“交函数”谁来接住这个范式转变很多团队一开始接触Serverless以为只是换了个部署方式实际上它的变化是整个应用模型的传统部署是把一个应用包扔到服务器上你负责进程活着、端口开着、磁盘够用Serverless模式下你交出去的是一个函数Handler剩下的事情全由平台接管。我习惯用餐厅来类比传统架构是你包下整个后厨买菜、洗菜、炒菜、洗碗、灭蟑螂都是你的责任。Serverless则是你只负责写菜谱平台负责后厨的所有杂事而且客人什么时候来、来多少人平台自动加人炒菜没人来就熄火睡觉。你不用为“闲置的灶台”付钱因为这口灶台根本不存在。这个转变带来的第一个好处是交付节奏变快了。以前上线一个接口要走发布单、检查机器、重启进程现在改完函数、推代码、等流水线跑完一个接口就能用。第二个好处是弹性伸缩的粒度变细了一个函数就是一个可缩放的单元某个接口流量翻了十倍受影响的是它自己的函数实例不至于整个应用一起扛。但范式转变也意味着技能栈要重构。你不再关心操作系统的版本、JVM参数、连接池大小转而要关心事件结构、触发器语义、等幂设计、冷启动优化、可观察性。该学的知识一样没少只是重点变了。1.2 成本模型的真相Serverless不等于“省钱”而是“匹配”很多团队的决策逻辑是Serverless按量付费肯定省钱。这句话只说对了一半。在流量波动大、低频、短时执行的场景下Serverless的成本确实远低于包月的服务器但如果是全天候高并发、持续稳定流量按请求次数加执行时长的账单可能比租机器更贵。我算过一笔账。假设一个业务每天有100万次调用平均执行时间200ms配置512MB内存。按某主流云厂商的计费逻辑粗略估算请求次数费用加GB·s执行时长费用一天成本约在几元到几十元区间月成本几百元级别。听起来不贵但如果你这台服务器同时还承载其他业务或者这个函数本身需要大量数据处理、外网流量成本就会明显上升。更值得算的是运维人工成本。一台自建服务器要考虑监控、告警、故障转移、补丁升级、弹性扩容准备这些投入乘以团队人力时薪往往比Serverless账单高得多。所以我在评估一个场景适不适合Serverless时从来不算纯服务器成本而是算“服务器成本运维成本故障损失”的总账。一旦总账的波动性大于稳定性Serverless的方案往往更优。1.3 适用边界哪些场景适合哪些场景最好别碰我踩过不少坑之后总结了一张自己的适用清单。适合用Serverless的场景Web API尤其是低频或流量波动大的接口消息队列消费端比如把下单后的通知、积分、数据同步逻辑拆成独立函数对象存储触发类的数据处理比如图片上传后自动压缩、视频转码定时任务比如报表生成、慢SQL清理、数据归档IoT数据接入和轻量ETL管道。这类场景天然是事件驱动、无状态和Serverless的模型完全匹配。不适合的场景也明确长时间运行的任务比如几个小时的数据训练或者超大文件处理函数通常有超时上限超了就强制杀掉强低延迟实时交互冷启动兜底再好也不适合做核心交易链路上对延迟极度敏感的环节重度有状态应用比如需要长连接、内置缓存、分布式会话的服务强行迁到Serverless只会让自己活受罪对硬件有强需求的场景比如GPU训练、高IO本地磁盘服务也不合适。我把适合和不适合的简单标准列过一张表核心就一句变量越少、越事件化、越无状态越适合Serverless。反之如果你发现要花大量精力绕开平台限制那就说明场景本身选错了。判断维度适合Serverless不适合Serverless调用模式低频、突发、时段性流量全天候稳定高并发任务时长秒级到分钟级小时级长任务状态需求无状态状态外部化强状态、长连接延迟要求百毫秒到秒级可接受强实时、毫秒级响应团队能力能写事件驱动代码传统单体思维较强2. 架构组成拆解一个Serverless应用到底由什么构成2.1 最小构成事件从哪来、函数怎么写、状态存在哪一个完整的Serverless应用通常不是单独一个函数而是“函数计算触发器周边云服务”的组合体。代码本身只是其中一小块。我常用的搭建思路是触发器负责把外部事件转换成平台可识别的调用函数负责处理事件并返回结果状态和持久化数据放在对象存储、数据库或缓存里日志和监控单独接入。举个例子一个图片压缩服务的最小构成大概是用户上传图片到对象存储对象存储的上传事件触发函数函数拉取图片文件、压缩、写回存储、更新数据库记录。这个链路上函数不保存任何中间状态所有数据都在外部服务上平台可以在任何时刻创建、销毁实例而不影响业务正确性。这也是我在给团队做培训时反复强调的函数写的不是“一个应用”而是“一段处理逻辑”。你要习惯把“服务”思考成“动作”把一个应用拆成多个独立动作每个动作对应一类事件。2.2 事件驱动模式函数的世界里只有“响应”Serverless函数的执行模型是事件驱动。它不会像一个守护进程那样常驻而是被“喂”一个事件进来然后启动、执行、退出。这个模型对脑子的转换要求很大因为你要放弃“主线程轮询”的思路改成“被动响应事件”。常见的事件源有这几类API网关把HTTP请求转成函数事件这是最常见的对外接口模式消息队列消费函数作为消费者处理队列里的消息对象存储事件文件上传、删除、修改都会触发函数定时触发器类似Linux Crontab的用法数据库变更事件比如某些平台支持数据库的表变更触发函数。每种触发器对应的函数输入结构都不一样但核心逻辑是相似的函数拿到的是一个事件对象里面包含业务数据和元信息函数处理完要么返回结果要么抛出异常并依赖平台的错误处理机制。你需要清楚地掌握你用的平台的Event数据结构这是本地调试时最容易出问题的地方。2.3 无状态设计的硬约束别把状态留在函数里很多从传统后端转过来的开发者写的第一个生产级函数就翻车了原因往往是把状态留在了函数实例里。函数实例随时会被平台销毁也随时会多地并行创建任何写入函数本地内存的数据都不是可靠的。我见过一个很典型的反例有团队在函数全局变量里缓存了数据库连接池和登录Token测试环境一切正常一上生产发现部分请求打到新实例上就白屏。排查到最后发现是Token缓存只存在于某个旧实例的内存里新实例根本拿不到。解决方案也很简单所有需要共享的状态全部外置Token放Redis连接信息从环境变量读取数据库连接按请求动态创建或者用代理层复用。除了状态平台还有几个隐形约束临时磁盘空间有限不能当文件系统用单函数实例的并发处理数有限制函数执行时长有硬性上限。这些约束从Oracle到K8s时代都有人在突破但Serverless时代最好的策略是遵守它而不是对抗它。2.4 函数粒度怎么拆拆太细是灾难拆太粗是伪Serverless函数该拆多细是Serverless架构里最容易吵起来的话题。拆太细代码库变成一盒散沙每个函数都是孤岛部署和排查的成本翻倍拆太粗又等于把整盘业务塞进一个函数跟写单体应用没区别还白白牺牲了弹性。我个人的经验是按“事件源业务边界”来拆。还是以订单系统为例下单后发通知、支付回调后记流水、订单超时自动取消、退货申请时自动触发退款这四件事来自不同事件源、处理逻辑独立、变更频率分散就应该拆成四个函数。如果只是同一个事件源里的不同分支比如Webhook进来后既写日志又更新缓存又发通知那就在一个函数里处理不要硬拆。判断标准很简单如果两个逻辑共享同一个状态、必须串行执行或部署维度必须一致那就放在一个函数里。如果它们有一天各需要不同的资源配置、不同的扩缩容节奏或者故障应该彼此隔离那就拆开。3. 实操落地一个订单通知服务从零跑通3.1 场景定义订单消息如何通过Serverless链路完成通知为了讲透整个实操过程我拿一个最典型的业务场景来演示电商订单系统下单后需要给用户发送短信和邮件通知并且记录通知日志。传统做法是订单服务里直接调用短信服务、邮件服务耦合度高而且每次下单都阻塞在第三方网关响应上。Serverless方案是把通知逻辑独立成一个函数把订单服务放在生产者的位置往消息队列里扔一条订单消息函数订阅这个队列并异步完成通知。整条链路是这样的订单服务 → 消息队列事件源 → 通知函数消费者 → 短信网关/邮件服务 → 通知日志数据库。这个设计的好处有三个一是解耦订单服务完全不知道通知逻辑是怎么实现的二是削峰下单高峰时段消息先入队函数按消费能力平滑处理三是故障隔离短信网关挂了不影响订单主流程消息留在队列里重试。3.2 函数代码怎么写一个Python Handler的完整骨架我习惯用Python写事件处理类函数开发效率高、冷启动也较好。下面是一个通知函数的骨架这段代码我在生产环境跑过核心逻辑可以直接迁移。import json import logging import os import uuid from datetime import datetime logger logging.getLogger(__name__) logger.setLevel(logging.INFO) def handler(event, context): # 不同平台的事件结构不同但通常都会有记录列表 for record in event.get(Records, []): # 解析消息体这里假设消息是JSON字符串 message json.loads(record[body]) # 幂等检查同一订单ID的通知只处理一次 order_id message[order_id] if not check_duplicate(order_id): logger.warning(duplicated notification order_id%s, order_id) continue # 构建通知内容 text build_notification_text(message) # 调用外部网关注意设置超时和异常捕获 if message.get(channel) in (sms, both): sms_result send_sms(message[phone], text) record_log(order_id, sms, sms_result) if message.get(channel) in (email, both): email_result send_email(message[email], text) record_log(order_id, email, email_result) # 标记处理完成 mark_processed(order_id) logger.info(notification sent order_id%s, order_id) return {statusCode: 200, body: ok}这段代码最需要注意的是幂等检查这一步。消息队列的投递语义基本是至少一次函数处理超时或者崩溃后平台会自动重投订单通知如果发了两遍用户投诉是小事信任问题才是大事。我在下面的章节会专门展开幂等设计的细节。3.3 部署配置内存、超时、环境变量一个都不能少代码写完之后真正决定运行表现的是部署配置。内存直接影响计费和性能超时时间设置太长会拖住实例设置太短又会导致任务执行不完。我的经验是普通的HTTP请求处理函数内存配256MB到512MB就够超时设5到10秒涉及外部API调用和数据处理的任务内存512MB起超时按实际业务链路估算。这里有一个反直觉的经验内存配大一点有时反而更省钱。原因很简单平台的计费单位是“内存大小×执行时长”内存配得高一些如果带来了执行时间缩短总费用未必更高而用户体验反而更好。我曾经把一个128MB执行800ms的函数调到512MB执行时间降到200ms费用几乎持平接口速度快了一大截。环境变量也是踩坑重灾区。短信网关的API Key、邮件服务的连接串绝不要明文写在代码里也不要直接放在环境变量就完事。正确做法是把敏感配置放在密钥管理服务中函数启动时通过API动态读取然后注入到上下文。并确保日志系统不会把环境变量打出来。3.4 触发器配置与消息体约定先定契约再写代码函数的输入是事件所以“消息体长什么样”其实是函数与上游服务之间的接口契约。我建议在项目启动的第一天就定义好消息模板并且维护成文档。比如订单通知消息可以定义成如下结构{ order_id: 20250101001, phone: 13800138000, email: userexample.com, channel: sms_email, user_name: 张小明, send_time: 2025-01-01T10:00:00Z }消息队列的触发器配置也要仔细。我常用的参数是批量大小设为10代表一次函数调用最多消费10条消息最大重试次数根据下游网关的容忍度来设短信网关偶尔抖动重试3到5次是合理的。重试策略一定要和幂等设计配合好因为重试是必然发生的每次重试的消息内容其实相同函数必须有办法识别出“这是一条曾经处理过的消息”。4. 开发调试与发布流水线本地模拟和自动化部署4.1 本地开发怎么模拟触发器函数开发最烦人的问题之一就是本地环境和云端不一致。常见做法是使用云平台提供的本地模拟工具比如AWS SAM CLI、Serverless Framework的离线插件以及国内云厂商CLI自带的事件模拟模拟器。这些工具的核心价值是让你不用登录云端就能跑Handler并且能在本地模拟API网关、队列、对象存储的触发事件。我自己的开发流程是这样先用官方文档提供的样例事件结构作为基础改成自己业务的假数据用本地工具跑一遍Handler看逻辑和日志输出对不对。然后再把云端的测试事件拉下来放到本地执行一遍对比索引结构是否兼容。这样能避开“本地正常云端报错”的大部分坑。需要注意的一点是本地模拟器通常不会真正创建外部服务它只会把事件丢给你的函数。如果你想测试数据库连接、调用短信网关、权限验证这些真实依赖需要额外配置本地模拟的云服务访问权限。这一步很容易被忽视结果就是本地跑通了一上生产才发现Key不对、权限不足、网络不通。4.2 CI/CD流水线从代码提交到生产发布一次完成Serverless的CI/CD比传统服务器的部署要简单因为不涉及服务器编排和负载均衡器配置核心就是把代码打包、上传、更新函数版本。下面是一个典型的GitHub Actions流水线配置项目用Serverless Framework管理。name: Deploy Notification Function on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-pythonv5 with: python-version: 3.11 - run: pip install -r requirements.txt - run: pytest tests/ - run: npm install -g serverless - run: serverless deploy --stage prod这条流水线做的事情很基础拉代码、装依赖、跑测试、发布。但我要提醒一个关键点生产环境的版本管理。函数不是更新完就完事发布新版本之前要确认两点一是函数代码和配置是否经过测试二是更新动作本身是否可回滚。几乎所有云平台都支持函数版本和别名Alias代码更新到新版本时别名会指向新版本但如果出了故障需要马上切回旧版本。流水线里一定要把发布和回滚动作固化下来而不是靠人肉去控制台点。4.3 日志和链路追踪函数满天飞之后你怎么找问题传统单体应用排查问题一条日志就能从头追到尾。Serverless架构下一次用户请求可能横跨API网关、订单服务、消息队列、通知函数、数据库五六个环节如果没有链路追踪排查问题就像在一堆散落的纸片里找一张发票。我的经验是把traceId贯穿整个链路。入口处生成traceId通过HTTP头传递到下游服务消息队列消息体里也带上traceId函数日志按traceId结构化输出。这样一旦用户反馈通知没收到我就能用traceId在日志平台上把所有相关日志拉出来按时间线重建整个执行过程。各家云平台都有自己的日志服务和追踪产品也可以用开源方案接入但核心逻辑都一样跨服务传递唯一标识日志带上下文。5. 性能调优冷启动和并发限制绕不开5.1 冷启动的根源为什么会有怎么缓解冷启动是Serverless被吐槽最多的问题。函数实例第一次被调用或者长时间闲置后再次被调用时平台需要新开一个容器、拉取代码、初始化运行时这个过程可能需要几百毫秒甚至几秒。在Web API场景下这会直接体现在用户等待时间上。冷启动的根源在于“没有常驻进程”这件事本身。缓解手段从常用到有效排序依次是预留并发预置实例让平台提前创建好一些实例随时待命这是最有效但也是最花钱的方式减小代码包体积精简依赖大的依赖会让实例初始化多花时间延迟初始化把部分重逻辑从函数启动阶段挪到首次调用时选冷启动更友好的运行时Java和.NET的启动时间普遍慢于Node.js和Python。我之前做过一次横向对比同样一个简单HandlerPython冷启动平均在不到10秒范围内Java大约在几百毫秒到1秒多。如果业务对延迟敏感请优先考虑Python或Node.js。对低频的定时任务场景冷启动几乎无感但如果你的API是核心入口预留并发几乎逃不掉。5.2 并发限制平台不是无限扩缩容很多人以为Serverless等于无限并发这是个误解。每个账户和区域都有并发配额比如某平台默认并发上限是1000超出部分的请求会被限流或排队。另一个限制是单函数实例的并发数平台通常会让一个实例处理完当前请求后再接收新请求实例内部并发处理数有限。应对这个问题的设计思路是削峰填谷。对外接口层面用API网关的限流策略保护函数消息场景把流量先让进队列由函数按自己的消费速率处理数据库类调用控制函数的并发上限防止下游连接被压垮。我在生产配置时会给函数设定一个合理的并发上限宁可让少量请求排队也不能把数据库打爆。5.3 实例和连接池的博弈如何避免数据库被打挂函数实例被平台按需创建高并发时一堆实例同时存在每个实例都会建自己的数据库连接。传统应用是几十个连接池复用Serverless是几十个实例各自建池数据库的监听线程压力可能直接翻几十倍。我踩过一个真实案例一个查询函数平时只有几百并发数据库连接数始终正常某天大促流量上来函数瞬间创建上千个实例数据库连接数飙到几千直接触发了数据库保护机制整个服务不可用。那次事故之后我改了三个措施函数内使用连接代理让所有实例复用代理层维护的少量连接给函数设置合理的最大并发控制实例数量的上限数据库本身加连接数告警指标超过阈值就自动触发限流。这几个组合拳下来之后大促再也没出现过连接被打爆的情况。6. 生产环境的常见坑和排查记录6.1 超时、重试、幂等三者纠缠不清的经典事故我会先把我在生产环境里遇到的影响最大的问题复盘出来。那是一次订单通知重复发送的事故。用户的手机在晚上连续收到三条一模一样的订单通知短信原因是函数消费消息后在记录日志时卡顿超过了超时时间平台判定本次执行失败自动重试。函数再次执行时没有幂等检查又发了一次短信。第三次重试同理。排查的过程让我记忆深刻先看日志发现同一个order_id在消息队列的重试记录里出现了三次代码里确实没有对同一订单做去重。解决方案我用的方案是加一张通知记录表order_id作为唯一索引发送前先插入记录如果插入冲突说明已经处理过。这属于“幂等表”的模式配合消息自带消息ID就能稳稳接住重试风暴。6.2 数据库连接数被打爆实例多了不见得是好事上面提到的大促事故我再展开说一下排查思路。当时第一步是看函数并发监控发现确实短时间内从几十飙升到上千第二步是看数据库连接数监控发现从正常的50左右一路涨到几千第三步是看函数日志里的慢查询结果发现大量请求根本没走到查询阶段而是阻塞在获取连接上。这个问题的本质是连接池和函数实例生命周期之间的冲突。传统应用连接池跨请求复用函数实例从启动到销毁的整个生命周期里也会初始化连接池但实例本身就是临时性的而且并发一高实例数直接远超连接池设计容量。解决办法是做连接复用代理层函数只连代理代理统一管理真实数据库连接。代理层的作用类似食堂分餐窗口几百个学生排队食堂师傅后面只有三五口锅但能稳定供餐。6.3 密钥管理环境变量不是保险箱有一次排查线上异常我在日志里看到了AccessKey的明文当场冷汗就下来了。原因是前一个开发者图省事把密钥放在环境变量里又因为日志打印了全部环境变量等于把账号凭据直接暴露了。那次之后我定了一条铁律环境变量只放非敏感的配置密钥一律走密钥管理服务函数运行时通过API动态获取。6.4 灰度发布和快速回滚别让新版本带着大家一起翻车Serverless的发布非常快快到你甚至来不及犹豫。我曾经就吃过一次亏新代码里改了一个消息队列的表名没走灰度直接切到生产结果线上消息一进来调用数据库全部失败用户开始反馈通知功能瘫痪。虽然回滚很快但中间那段不可用时间已经造成了损失。正确的做法是把函数发布和流量调度拆开先发布版本然后灰度切流量比如先让10%的流量落到新版本观察日志和监控指标再逐步扩大到50%、100%。一旦误报率或者错误率超标立即把别名切回稳定版本。这个过程用云平台的控制台或者CLI都能实现关键是把它固化到发布流程中而不是临时手忙脚乱。7. 工具选型别急着写代码先把这几个工具搞清楚7.1 Serverless框架和工具怎么选很多新手一上来就问我用哪个工具我的建议是先别急着选框架先把平台自带的CLI用熟。平台CLI能让你完成最基本的创建、部署、调日志操作也帮你建立对底层资源的感知。当你发现平台CLI管理复杂项目比较吃力时再引入IaC或框架。工具适用场景优势注意点平台自带CLI单函数、快速验证最简单无额外依赖多环境管理能力弱Serverless Framework多云、中小型项目生态好、配置社区多抽象层增加排障难度AWS SAM深度绑定AWS生态本地调试体验好不强则不需要Terraform已有IaC体系、整体基建统一管理函数和基础设施一并管理学习曲线较陡我个人的选型经验团队已有Terraform管理云资源就继续用Terraform定义函数如果是多云环境或者快速原型用Serverless Framework会很顺手如果团队只有一两个函数要做事件处理直接用平台CLI别上框架省下的抽象层能减少很多困惑。7.2 Serverless和现有微服务如何共存把现有系统一次性全迁到Serverless基本不现实风险太高。我更推崇的演进方式是混合架构保留核心微服务不动把事件型、突发型、边缘型场景逐步抽离成函数。之前我做过一个项目原来的订单服务里有发短信、生成报表、清理数据这些杂活这些逻辑跟主流程无关流量又不均匀我把它们一个个拆出去变成独立函数主服务的代码量少了一半压力也小了很多。这里的架构关键是消息通道。订单主流程只管往队列里放消息其他函数的调度、重试、隔离都靠队列完成主服务不需要感知函数的任何细节。等这套模式跑顺了再慢慢把更多边界业务搬上去演进节奏就稳了。8. 架构演进路线图从简单场景到全面落地8.1 一个团队的典型演进路径我见过全流程踩坑式起步的也见过稳健式落地的总结下来的比较合理的演进路径大概是这样的第一阶段选一个不是核心链路的定时任务比如每天凌晨的数据清理迁到函数计算上这个阶段目标是感受部署、日志、监控的闭环第二阶段把一个消息消费端迁过去比如订单通知或事件同步这个阶段要掌握队列触发器、重试、幂等设计第三阶段对外API接入网关这个阶段会涉及冷启动优化、预留并发、限流策略第四阶段把可观测性做上去日志结构化、链路追踪铺开第五阶段沉淀治理规范函数命名、标签、权限、版本管理统一收口。每个阶段都有明确的验收标准不要试图跳过阶段。很多团队翻车就是因为前两个阶段还没跑顺就直接把核心交易链路上线了出了问题只能手足无措。8.2 技术之外组织协作方式也得跟着变Serverless落地的难点很大一部分不在技术而在组织协作方式。函数小而多代码库分散如果没有统一的代码规范、公共错误处理、日志输出标准很快每个函数都会长出属于自己的“方言”。等函数数量到了几十个光靠人肉记忆谁是谁肯定崩盘。我建议团队在应用Serverless第一天就定好三件事一是函数命名规则比如业务域-场景-动作的格式一眼看出它是干什么的二是标签规范强制给每个函数打上归属人、业务线、环境等级标签方便资源治理和成本分摊三是错误处理标准函数入口统一捕获异常、统一结构输出错误信息、统一判断是否需要重试。这三条规则看起来不起眼但能避免在函数规模扩大后陷入混乱。根据我在多个项目实操的经验Serverless不是银弹它更像一把锋利的手术刀。用好了能让系统更干净、更灵活、更省心用不好也会带来新的麻烦和账单。但它有一点让我很着迷它逼着你去思考事件、边界、状态、幂等这些架构的本质问题。就算你最终没有大面积使用Serverless把这些问题想清楚对任何架构都是加分项。如果你正在评估要不要选Serverless我的建议很朴素找一个非核心场景按前面说的方法跑三个月看账单、看稳定性、看团队心情答案自然就有了。
返回列表