
最近在推进一个新项目的FDE试产整个团队都被一件看起来很矛盾的事折腾得够呛Demo阶段给客户演示的时候功能流畅、交互顺滑、稳定性看起来也没问题可到了上线前的小批量验证阶段各种问题像约好了一样集体爆发——偶发卡顿、通信超时、数据错乱甚至连之前测过几百遍的基本流程都能翻车。这不是我第一次遇到这种“Demo很美好上线见光死”的情况了。作为FDEFirst Design Engineer第一设计工程师主要负责把原型设计推向可量产、可上线状态我几乎每个项目都会和这种落差打一次交道。今天就把这些实战经验整理出来重点聊聊Demo和上线之间的那道鸿沟到底在哪以及踩过这么多坑之后我总结出的那套排查和验证方法。1. Demo的“好看”为什么是陷阱工程约束下的失真很多工程师其实没意识到Demo和上线系统本质上就是两套不同的东西。Demo追求的是“在有限条件下表现出它应该有的样子”而上线系统追求的是“在任何可能出现的条件下都不出问题”。这两者之间的差距恰恰是落地过程中绝大多数疑难杂症的病根。1.1 Demo环境的隐性红利不干净的数据、不真实的时序先说数据。Demo阶段最常用的数据来源就是mock数据或者是精心挑选过的“干净数据”。做演示的人都知道演示之前会把数据准备得漂漂亮亮的——字段完整、格式规范、没有脏数据。但上线之后面对的是真实业务数据什么情况都有字段为空、类型不匹配、字符串里有特殊字符、时间格式不统一、接口返回的结构和文档对不上这些问题在Demo阶段根本不会暴露。我自己印象最深的一次是在做设备联调的时候Demo程序跑得好好的一接到产线实际数据就崩溃。查了半天发现是因为真实数据里有一个字段的值超过了我们在Demo里约定的取值范围程序里做数组索引的时候直接越界了。这种问题在Demo阶段永远测不出来因为你在Demo里根本不会输入这种边界值。时序也是一样。Demo阶段的数据交互往往是理想化的请求发出去响应很快回来顺序也不会乱。但真实环境里网络延迟是不确定的消息可能会乱序超时重发可能会导致重复处理慢请求会堆积成队列。我见过太多在Demo里表现完美的模块一上线就变成“薛定谔的接口”——一会儿通一会儿不通就是因为没有提前把时序的不确定性考虑进去。1.2 Demo的硬件条件被忽略的运行环境差异如果是在嵌入式或者IoT领域做FDE这个感受会更明显。Demo阶段用的开发板、电源、网络环境和真正批量出货的设备完全是两回事。开发板用的是实验室电源电压稳定量产设备用的是电池或者普通适配器电压会波动。实验室的无线环境相对干净量产现场可能有几十上百台设备同时通信互相干扰。更现实的问题是硬件的一致性。Demo阶段你手上可能只有一两台样机每台样机都是手工调试过的天线位置、屏蔽罩、接地处理都处于比较理想的状态。但量产之后元器件存在离散性焊接工艺会有差异同样的软件在不同设备上的表现可能就是不一样。有的设备能跑通的通信链路换个设备可能就不稳定了。1.3 Demo的交互模型用户不会按剧本操作Demo演示通常是有“剧本”的先做什么、再做什么、展示什么效果心里都有数。但真实用户不会按剧本操作他们可能会快速点击按钮、可能会在某个页面反复进出、可能会在数据正在提交的时候退出应用、可能是多个人同时在操作同一个系统。我常用一个比喻来向团队解释这件事Demo就像让一个演员在舞台上按彩排过无数次的剧本表演而上线系统就像让这个演员直接面对观众即兴演出你根本不知道观众会抛出什么问题。FDE的很大一部分工作就是在上线之前把系统当成一个“即兴演员”来训练把各种突发情况都考虑到。2. 代码层面的“演示通过”与“上线崩溃”的距离很多人以为Demo能跑通代码就没有大问题。但以我做FDE落地项目的经验来看代码能不能在演示环境里跑通和代码能不能在真实环境里稳定运行这中间隔着的距离相当大。下面这几个问题是我在实际项目中反复踩过的每一类都值得在代码审查阶段专门拿出来过一遍。2.1 硬编码与假设驱动Demo里写死的那些雷Demo代码最常见的特征就是“硬编码多”。为了快速出效果很多人会把一些运行时的配置直接写死在代码里比如服务器地址、设备ID、超时时间、重试次数、文件路径甚至业务参数。Demo的时候无所谓反正这些值在当前环境下都是可用的但一旦上线环境和资源都变了这些写死的值就会变成定时炸弹。我之前接手过一个项目里面有一个地方直接硬编码了一个设备名称字符串用来做数据校验。Demo的时候这个设备名称刚好是存在的所以一切正常。上线之后换了一台设备名称对不上校验直接失败但程序又不会报错——因为代码里把校验结果放在一个告警级别而不是错误级别导致这个问题很隐蔽排查了很久才定位到是硬编码惹的祸。所以我在做代码审查的时候有一个固定动作搜索代码里的关键常量逐个确认它是不是“只能当前环境用”的值。如果是要么改成可配置项要么至少加个注释标注清楚上线前必须改。这个动作看起来很笨但真的能避免很多上线事故。2.2 状态管理的隐性风险Demo里不会被看到的“脏状态”Demo程序的生命周期短通常就是演示前启动、演示完关闭所以状态管理的粗糙之处不会被看到。但上线系统是7x24小时运行的状态会被持续累积和复用于是问题就来了。最常见的两个坑是真静态变量和单例模式。Demo里用静态变量存储临时数据很方便但上线之后静态变量的生命周期是整个进程如果某个请求把数据写进去、后面的请求还在读就会读到被污染的数据。我在一个项目里就遇到过这个问题Demo阶段只有一个客户端在访问静态数据没问题上线后多个客户端同时访问A客户端写入的状态被B客户端读到了导致数据错乱。另一个坑是全局状态没有清理逻辑。比如某个页面打开的时候设置了一个标志位关页面的时候忘了复位。Demo里每次都是重新启动程序所以标志位总是初始值但上线之后程序不重启这个标志位一直留着第二次打开的页面就走进了完全不同的逻辑分支。这类问题不是不能修而是很难查因为它和“时间”强相关——运行得越久越容易出现。2.3 错误处理路径Demo里走不到的分支上线后天天走这是我最想重点说的一点。Demo演示的时候输入是可控的环境是正常的所以主流程能走通就够了。但上线之后系统面对的是“有意或无意的异常输入”和“频繁发生的环境抖动”这时候真正决定系统稳定性的不是主流程写得多好而是异常处理路径写得多完善。举几个常见的例子网络超时后重试逻辑没有做幂等处理导致同一笔操作被重复执行文件不存在、目录无权限这类异常没有捕获程序直接崩溃某一项数据为null但代码里直接调用它的方法抛NullPointerException返回码判断不完整把非0的错误码当成成功来处理我在做FDE落地的时候都会专门做一轮“异常注入测试”就是在代码里人为制造各种异常条件看系统能不能正确处理。做法很简单在关键接口前面加一个配置文件模拟超时、返回错误、返回异常数据、返回null逐个验证系统的行为是否符合预期。这个测试做完上线之后的应急工单数量会明显下降。2.4 资源生命周期管理泄漏是累积型的上线崩盘资源泄漏这个问题在Demo里几乎不会暴露因为演示时间短、操作次数少就算漏一点点资源也不会影响运行。但上线后系统长时间运行每次操作泄漏一点时间一长就会累积成灾难。文件句柄没关、数据库连接没释放、定时任务没有取消、监听器注册了没有注销、内存缓存只放不清理这些都是常见泄漏源。我实测过一个系统每进行一次文件解析操作就会泄漏一个句柄演示阶段完全正常上线运行几个小时后句柄数暴涨最终导致无法创建新文件。内存泄漏也一样。我在一个Java项目里见过一个很隐蔽的内存泄漏把每个请求的数据都放到一个静态List里做缓存但一直没清理。演示的时候数据量小没人注意到上线一个月之后这个List越来越大最终触发OOM。排查的时候用内存分析工具一看发现几乎所有的内存都被一个List占着这才定位到根因。所以我的建议是上线前不要只看功能是否正常还要做长时间运行的压力测试观察内存、句柄、连接数等资源指标是否随时间增长。如果曲线是单调上升的哪怕现在还没爆也已经埋下了上线事故的隐患。3. 从Demo到上线真正的成本在“边界条件补全”我经常和团队说一句话Demo是在理想条件下展示功能上线是在各种极端条件下被考验。FDE的工作本质就是补全Demo和上线系统之间的所有边界条件。这中间的工作量往往比开发Demo本身还要大而且更容易被忽视。3.1 回到桌面查Bug环境变量与机器命名的“鬼打墙”在FDE的排查工作里有一类问题特别气人——代码写得没错逻辑也完全对但上线之后就是表现异常。我遇到过几次“鬼打墙”式的排查经历最后发现根因都特别基础但特别容易被忽略。有一次是桌面端软件上线后在某几台设备上表现正常另外几台设备上表现异常而且没有任何规律。折腾了两天最后发现异常设备都有一个共同点机器名里带着一个下划线。代码里有一个地方用机器名拼接生成一个标识符这个标识符在某些协议里不允许包含下划线所以直接导致通信失败。还有一次是运行环境变量的问题。开发机上的PATH设置了某个工具链的路径所以代码里调用的一个外部命令能找到但上线机器上没有这个环境变量外部命令找不到程序也不报错只是没有执行任何操作表现得就像什么都没发生一样。这种问题在Demo阶段绝对不会被发现因为开发就是在这个环境里做的。我现在的做法是所有关键依赖外部命令、动态库、环境变量都形成一份清单上线前逐一确认目标环境的配置。所谓“上线前倒排期检查环境”不是走个过场而是真的逐项去比对才能避免这类低级但又致命的坑。3.2 排查链路的四个对齐环境、数据、压力、异常为了让Demo成功上线我总结了一套排查链路核心就是四个对齐环境对齐、数据对齐、压力对齐、异常对齐。先说环境对齐。这一步的目标是让演示环境和线上环境的差异尽可能缩小。包括操作系统版本、运行时版本、依赖库版本、环境变量、网络拓扑、资源配置这些通通要对齐。我见过很多项目的开发环境和线上环境差了好几个版本这会导致很多“在我机器上是好的到你机器上就坏了”的问题。环境对齐不是说非要完全一致但至少要做到“已知差异”并且让团队每个人都清楚这些差异可能带来什么影响。然后是数据对齐。这一步是用真实数据来跑测试而不是用精心准备的干净数据。真实数据包括脏数据、缺失值、异常值、超长字符串、特殊字符、边界值。我在对数据对齐的时候会专门从生产环境导出脱敏数据导入测试环境然后用这些数据跑全流程回归。实测下来这一步至少能发现三成以上的“上线后才会暴露的问题”。再是压力对齐。这一步是验证系统的负载能力。核心指标包括并发用户数、每秒请求数、数据量级、持续运行时间。我的做法是给系统施加上线后预期的两倍负载连续跑24小时观察资源占用、响应时间和错误率。这样做的好处是既验证了常规负载下的稳定性也暴露了系统在压力升高时可能出现的性能瓶颈。最后是异常对齐。前面提到的异常注入测试就是这个环节的核心内容。除了注入异常之外我也会针对每个接口、每个流程主动思考“它可能会怎么失败”然后逐个加入异常处理逻辑。这个环节最考验工程经验因为异常处理不是写try-catch那么容易而是要理解每段代码“可能怎么挂”以及“挂了之后应该怎么恢复”。3.3 一键部署与可回滚机制让上线不再是“开盲盒”Demo阶段通常不需要考虑部署因为代码在本地跑就行。但上线必须考虑部署的可靠性和可回滚性。我见过太多项目上线就是把代码拖上去靠命令行手动启动服务出了问题再手忙脚乱地回滚。这种操作方式在上线时特别容易出错而且出了问题很难定位。我的建议是上线前至少要做到自动化部署。我常用的是Docker加容器编排把应用打成镜像一条命令就能部署到目标环境。这样做的好处是环境一致性有了保障镜像里已经把所有的依赖都打进去了部署过程也变成了可重复的行为不会出现“上次用手动步骤能启动这次某个命令敲错导致失败”的问题。同时一定要预留回滚机制。我见过很多系统上线前没有准备回滚方案上线后出了问题才临时想办法结果越救越糟。合理的做法是每次部署都保留上一版本如果上线后发现问题能一键切回旧版本。对于依赖数据库的应用回滚也意味着数据库的兼容处理这个要提前评估而不是出了问题再去救。3.4 设计评审不是走过场从Demo思维切到上线思维最后一项是设计评审。FDE在工作中很重要的一件事就是在设计评审阶段从“能不能做出来”切换到“上线后会不会出问题”。我参加过很多次设计评审大家的关注点通常都在功能实现上——这个需求怎么实现、用什么技术栈、界面怎么交互。但很少有人在评审的时候主动挑战一个问题如果这个功能上线了可能会因为什么而失败我每次评审都会问几个固定的问题数据来源是什么数据质量有没有保障接口依赖的下游系统有没有SLA下游挂了怎么办这个功能是同步调用还是异步处理异步处理失败怎么感知本地缓存和远端数据的一致性怎么保证日志记录是否足够支撑线上问题排查。这些问题不一定每次都有答案但只要有一个人提出来团队就会开始重视而不是等上线之后才亡羊补牢。4. 数据一致性Demo里永远不会测出来的魔鬼细节数据一致性这个话题在Demo阶段几乎不会有人关注但在上线之后却是最常见的“事故源头”。Demo里数据是预先准备好的操作流程是单线的不会出现并发和冲突所以一致性问题完全暴露不出来。但真实系统上线后并发访问、重复提交、部分失败这些问题每天都会发生一旦处理不当就会导致数据错乱引发用户投诉。4.1 幂等设计从“处理一次”到“处理任意次都行”Demo里一个操作通常只执行一次所以不会意识到幂等的重要性。但上线之后网络超时、客户端重试、消息队列重投都会导致同一个操作被执行多次。如果接口没有做幂等设计数据就会重复插入、重复扣款、重复发送消息。我在一个项目里就吃过这个亏Demo阶段的订单提交流程一切正常上线后出现了重复下单的情况。查下来发现客户端在提交订单时因为网络超时自动重试服务端收到了两次请求每次都生成了订单结果用户被扣了两次款。修复的方案是在订单提交接口加了一个幂等键客户端生成一个唯一请求ID服务端拿到请求ID先去查一下是否处理过处理过就直接返回上次的结果。幂等设计其实不复杂核心就是要求每个写操作都带上一个全局唯一的业务键服务端通过这个键来判断是否已经处理过。但这个设计需要在开发早期就考虑进去而不是等问题发生了再补。因为一旦上线之后历史数据已经积累了再补幂等逻辑就比较痛苦了。4.2 缓存与数据库的一致性问题数据漂移是怎么开始的只要有缓存就一定会遇到缓存和数据库一致性的问题。Demo阶段数据量小缓存和数据库的差异不容易被发现。但上线之后数据更新频繁缓存和数据库的同步时机一旦设计不好就会导致用户读到过期数据。我见过最典型的场景是一个配置项在管理后台更新了但前端展示的还是旧值因为缓存没有失效。排查的时候发现更新数据库的操作和清理缓存的操作不是一个事务更新数据库成功之后清理缓存的操作失败了导致缓存里的旧数据一直存在。解决这个问题的思路有很多旁路缓存、双删、订阅变更消息、设置合理的过期时间各有优缺点。我的经验是不要追求某种方案“绝对正确”而是要结合业务场景选择可接受的一致性模型。如果业务允许短暂的不一致设置合理过期时间就够了如果业务要求强一致就得在更新数据库的同时确保缓存失效并且处理失效失败的情况。4.3 数据库事务边界太粗导致锁冲突太细导致数据损坏事务边界的把握是上线后数据库性能和安全的核心。事务太粗会导致大量的锁冲突和并发性能下降事务太细又可能导致数据在更新中途出现不一致。我做过一个库存扣减的模块Demo阶段一切正常上线后在高并发下出现库存负数。排查后发现问题出在事务边界上代码在读取库存之后执行了一些耗时的操作然后再更新库存。在高并发下多个请求同时读到同一个库存值各自扣减各自的扣完之后写回最后的结果就错了。修复的方式是压缩事务粒度把“读取-判断-扣减”做成一个原子操作同时用乐观锁或者悲观锁来保证并发安全。这里我比较推荐乐观锁就是给库存表加一个版本号字段更新的时候带上版本号如果版本号变了就说明数据已经被别人改过需要重试。这个方案在并发量不是特别夸张的场景下都很稳定实现也简单。4.4 异步处理的失败补偿消息发出去之后世界就不是代码的样子了异步处理在Demo阶段通常也是“看起来没问题”因为流程走到发送消息那一步演示就结束了。但上线后消息发出去之后消费者可能消费失败、可能重复消费、可能长时间不消费这些情况都必须有对应的处理机制。我的做法是所有异步任务都必须有重试机制和死信队列。重试机制就是消费失败后过一段时间重新投递死信队列就是重试多次仍然失败的消息投递到一个专门的队列里由人工或者专门的程序来处理。同时所有异步处理的日志必须带上业务唯一ID这样出问题的时候才能通过这个ID追踪到完整的处理链路。我还在异步处理里加入了一个更实用的设计状态机。每个业务实体都维护一个状态字段每个异步操作把字段从一个状态迁移到另一个状态。这样即使中间过程出问题也可以通过看字段的当前状态来了解业务进行到哪一步然后手动介入补偿。这个设计在排查问题时帮了我很多次强烈推荐在涉及异步场景的项目里用起来。5. 性能与并发演示流畅不等于生产扛得住性能问题是“Demo看着没问题、上线就出问题”的重灾区。原因很简单Demo时系统没有并发只有一个人在操作而且数据集很小所以响应速度很快。但上线之后并发用户多了数据量上来了各种性能瓶颈就会逐一暴露出来。5.1 从“单人操作”到“多人同时操作”数据库连接池和线程池先扛不住Demo阶段一个应用只需要少量数据库连接就够了连接池的默认配置也可以满足。但上线之后并发量上来数据库连接池里的连接可能就不够用了请求会在获取连接的环节排队表现就是响应时间显著变长甚至出现连接池耗尽导致的报错。线程池也一样。有些代码里用线程池做异步处理但线程池的核心线程数和最大线程数是写死的Demo阶段异步任务少线程池绰绰有余上线之后异步任务增多任务队列堆积响应也会变得非常慢。我的建议是在上线前做一次并发配置审查逐个检查数据库连接池、线程池、HTTP客户端连接池的参数设置确认它们匹配上线后的预期流量。同时所有的池化资源都要设置合理的超时时间和拒绝策略不能让请求无限期等待。5.2 数据库慢查询数据量一上来索引失效、全表扫描全来了Demo阶段数据量小一条查询即使没有索引也能秒回。但上线后数据量增长到几十万几百万行之后没有索引的查询就是灾难。这个问题通常在上线初期不明显等数据积累到一定程度后才会爆发。我见过一个典型的案例一套管理后台的列表页Demo阶段任何查询都是毫秒级返回。上线一个月后有一个列表页的响应时间变成了十几秒用户反馈炸了。排查后发现列表页的查询条件里有一个字段没有建索引导致每次查询都是全表扫描。补上索引之后响应时间立刻降到了毫秒级。所以我的建议是上线前一定要用“接近生产数据量”的数据集做一次慢查询检测。做法也很简单导一批足够大的数据到测试环境把日志里开启慢查询日志然后跑一遍核心的业务流程看有没有查询超过预期时间。这个测试做下来能发现大部分数据库层面的隐患。5.3 接口响应时间忽略第三方调用的延迟一切设计都是纸上谈兵Demo阶段第三方接口的mock服务通常都是秒回所以你不会觉得慢。但真实环境里第三方接口的响应时间可能几十毫秒也可能几秒钟甚至更慢。如果你的主流程是串行调用第三方接口的那总耗时就会线性叠加。我在一个项目里就踩过这个坑流程里要依次调用三个外部服务Demo阶段每个服务都是毫秒级返回整个流程很流畅。上线后其中有一个服务经常需要1到2秒才返回导致整个流程的用户体验急剧下降。解决方案有两个方向一是并行调用把没有依赖关系的第三方请求并发发出减少总耗时二是引入缓存把那些不经常变化的外部数据缓存到本地减少外部调用次数。这两个方案各有利弊需要根据业务场景做取舍但都是上线前就应该提前做好的设计而不是等到线上出问题才考虑。5.4 前端资源性能包体积和渲染性能网络不好的时候全部现原形如果这个项目有前端页面那性能问题里还有一个特别容易在Demo里被忽视的维度前端资源性能。Demo阶段通常在局域网里访问网络好资源加载快没人会注意到包体积和渲染性能的问题。但上线之后用户可能是在弱网环境下访问的如果包体积大、加载慢首屏体验就会非常差。前端性能优化的常用手段包括代码分割把一个大包拆成多个按需加载的小包、静态资源压缩、图片懒加载、合理利用浏览器缓存、减少不必要的DOM操作。这些优化在Demo阶段可能看不出明显效果但对于弱网环境下的用户体验来说差异巨大。我做前端性能排查的时候习惯用浏览器的Performance面板录制一段用户操作看每个步骤的耗时分布找出耗时最长的节点。同时用Lighthouse跑一次性能评分看哪些指标不合格。这些工具和思路都是上线前应该跑一遍的例行检查而不是等到用户抱怨的时候再回头来优化。6. 安全与合规上线后才暴露的隐性风险安全问题的特点在于Demo阶段几乎不会有人攻击你的系统所以安全性看起来不重要。但一旦上线系统暴露在公网环境中各种扫描、攻击、异常流量随时都会出现。如果Demo阶段没有做足够的安全加固上线后轻则数据泄露重则系统被攻破而且往往是在你还没意识到的时候就已经发生了。6.1 认证与授权Demo里最容易被忽略的一环Demo阶段为了演示方便我们经常会把认证和授权关掉或者用一套固定的测试账号。但上线之后认证和授权是系统的第一道防线如果做得不严任何人都能访问系统的功能都能操作系统中的数据后果不堪设想。我遇到过的一个真实案例是一个系统上线后有人发现通过修改请求参数可以直接访问到其他用户的数据。原因是后端接口只校验了用户是否登录没有校验用户是否有权限访问这个数据。这在Demo阶段完全不会被发现因为演示的时候只有一个测试账号也没有人去刻意修改参数。所以说上线前一定要把权限校验加到每一个接口上而且要用真实的权限模型去测而不是用一个超级管理员账号走一遍流程就完事。至少需要准备三个角色各不相同的测试账号分别验证他们能访问什么、不能访问什么确保越权访问的路径被堵死。6.2 敏感数据的加密与保护等泄露了再补救就晚了Demo阶段数据通常是虚假的所以没人关心数据加密的问题。但上线后系统里存的是用户的真实数据包括手机号、身份证号、地址、支付信息等敏感内容。这些数据如果明文存储一旦数据库泄露后果就不是技术问题而是法律和声誉问题了。我的建议是上线前至少要做四件事一是敏感字段加密存储数据库里不要出现明文密码和明文个人信息二是传输层启用加密不要用明文协议传输数据三是密码存储必须用加盐哈希不能直接存密码原文四是日志里不能打印敏感信息尤其是密码和token。也许有人会觉得又不是每个系统都被攻击没必要这么紧张。但以我的经验安全问题就像买保险你没出事的时候觉得每年交保费很亏等出了事才发现当初该买的都应该买。上线前的安全加固正是在为数不多能买“保险”的时候做的投资。6.3 线上到线下的安全闭环从部署到运维的完整检查清单安全不只是写代码的时候考虑的事部署和运维阶段同样重要。我常用一个完整的安全检查清单来逐项确认这里分享几个重点服务器访问权限是否最小化是否所有人都能SSH登录生产环境数据库连接信息是否通过环境变量或配置中心管理是否直接硬编码在代码里有没有开启基础的安全防护比如防火墙、入侵检测、访问控制关键操作有没有审计日志出了问题能不能追溯操作者备份策略是否完善数据丢失时能否恢复恢复流程是否演练过这些问题看起来都很基础但实际项目中能全部做到的系统真不多。我个人的体会是安全问题不是一个“知识点”而是一种“习惯”。只有把这些检查变成上线流程里的固定动作才能避免在真正遇到攻击的时候手忙脚乱。7. 上线之后的持续治理Demo思维的最后一课就算你前面所有的事情都做好了上线之后的持续治理也是必不可少的。因为上线不等于结束而是新的开始——你面对的不再是你熟悉的Demo环境而是时刻在变化的生产环境。7.1 建立上线后的监控体系日志、指标、链路三位一体上线之后最重要的事情就是能实时感知系统是否健康。我的做法是搭建一套“日志、指标、链路”三位一体的可观测体系。日志方面关键业务流程必须打日志日志里必须包含业务唯一ID以便问题出现时能快速关联到一次完整的业务操作。打日志的级别也要控制好生产和测试用不同的级别避免日志量太大导致性能下降。指标方面至少要监控这几项CPU使用率、内存使用率、磁盘IO、网络带宽、数据库连接数、线程池活跃数、接口响应时间、错误率。这些指标异常时一定要有告警通知而不是等用户来投诉。链路方面如果一个请求要经过多个服务最好用分布式链路追踪工具把整个调用链串起来。这样当一次请求响应慢的时候你一眼就能看到瓶颈在哪个环节而不是靠猜。7.2 建立上线后的应急响应机制让“出问题”不再是灾难上线后出问题不可怕可怕的是出问题之后没有一套完整的应急响应机制大家在恐慌中各自为战结果越搞越乱。我的经验是事先定好应急响应流程谁负责通知、谁负责排查、谁负责决策都清晰落地。一个简单实用的流程是这样的监控告警发现异常后第一时间确认是否影响用户如果影响立即启动应急预案运维同学先确认服务是否可用不可用就先恢复服务再排查根因研发同学同时拉取日志和指标定位问题修复后要写一份事故复盘说明原因、处理过程、后续改进项。这套流程不一定每次都能快速解决问题但至少能让整个团队在上线出问题的时候不慌乱有章法地推进。很多人觉得这只是在管理层面上的事情但实际上它对于上线后的稳定运行来说和写代码一样重要。7.3 Demo思维的最后告别从“让它跑起来”到“让它一直跑得好”做FDE这些年我最大的感受是Demo思维和上线思维是两种完全不同的工作方式。Demo思维关心的是“能不能跑起来”上线思维关心的是“能不能一直跑得好”。这两种思维方式没有绝对的对错但如果你要做的是上线系统就必须在上线前完成一次思维的切换。对团队来说这个切换不只是一个技术问题更是一个流程问题。我每次做FDE项目的时候都会在开发流程里强制加入Demo阶段没有的那些环节环境一致性验证、真实数据回归、压力测试、异常注入、安全加固、监控告警配置、应急演练。这些环节确实会耗费时间和精力但和上线出问题之后的救火成本相比这些投入非常划算。最后再分享一个小技巧在做完所有上线前的检查之后我习惯让团队里的每个人把“如果这个系统明天上线我最担心什么问题”写下来然后整理成一张清单逐条去验证。你会发现很多你自己想不到的问题会在同事的担心清单里被提出来。这张清单往往是上线前最后一轮最有价值的“查缺补漏”。