月结:架构演进、云技术排障与前端优化的实战复盘

📅 发布时间:2026/10/12 15:33:15
月结:架构演进、云技术排障与前端优化的实战复盘
又到月底了这篇月结写得我有点纠结——开心的事有踩的坑也不少所以标题直接写成了“含泪总结.. 憋泪分享”。我是栋这个“月结”栏目照例做定期更新今天这篇是第二回合。还是老规矩把自己这一个月里围绕架构、云技术、算法、后端、前端折腾的内容整理一遍顺带把收听/收看、英文、书籍、影视、好歌、新奇这些输入侧的东西也一起归档不藏着掖着有什么说什么。这个月结适合几类人看正在做服务端和前端开发、对系统架构演进和线上运维感兴趣的朋友以及想找一些靠谱输入资源书、播客、影视、音乐打发碎片时间的人。写作风格还是老样子像朋友聊天一样把过程说清楚把“为什么这么选”也交代明白。毕竟月结这事的价值不在于罗列做了什么而在于把做事的逻辑链重新捋一遍——很多事情当时觉得理所当然回头一看全是问题。1. 项目动态两条旧线收尾一条新线踩进泥里1.1 一个内部小工具终于没有“推倒重来”月初第一件事就是处理一个内部管理工具的升级问题。这个工具本身不复杂就是一个定时抓取数据、汇总后推送通知的小服务线上跑了一年多中间修修补补代码已经有点难看。我原计划是重写一遍把逻辑理干净但真正动手前先盘了一下调用方有六个内部系统在调它的接口有的还依赖了一些不太规范的返回字段。这时候重写就等于给自己挖坑。所有调用方都得跟着改回归测试成本直接起飞。于是我改了方案保留旧版本接口新增一套 v2 接口把内部实现重构成清晰的管道模式然后做一层兼容适配。旧接口继续服务老调用方新系统逐步切到 v2。这事的核心教训是技术债再难看也不能为“好看”而重写。重写前先量化影响面能用兼容层过渡就先过渡等所有消费方都迁移完再下线旧代码。后来实测下来这个决策是对的——虽然改造周期比原计划多了一周但线上零投诉发布当晚我居然能安稳睡觉。1.2 全新服务的第一版从单体文件变成模块化结构月中旬接了一个新的数据聚合服务需求比较清晰从多个数据源拉取信息做清洗、标准化、合并再对外提供查询接口。设计的时候我在“一个大文件写完”和“模块化拆分”之间纠结了一阵最后选了后者。拆分的粒度没有走极端没有一上来就搞微服务而是保持一个可独立部署的模块化单体摄取模块、清洗模块、标准化模块、存储模块、API 模块各占一个包模块之间只通过明确的数据结构通信。这样做的原因是团队规模不大微服务带来的运维开销远大于收益而一个大文件写完虽然快但后面维护的人会骂娘。我列过一个对比表最后选的方案大体是这样的方案优点缺点结论单文件快速实现开发最快适合一次性脚本不可维护无法单元测试扩展必炸放弃完整微服务拆分独立伸缩、独立部署基础设施要求高排障链路长暂时不做模块化单体边界清晰、部署简单、易测试模块间耦合需要靠纪律维持采用现在跑了两周模块化单体的优势已经体现出来了某个数据源的格式调整只改了清洗模块其他模块完全没动。等以后并发量真上来再把摄取和 API 模块单独拆出去也不迟。1.3 关于“定期更新”这件事我找到的节奏有人问我月结栏目的素材是怎么攒的说自己也想过整理但总是月底发现忘光了。我现在的流程很固定分享一下每天随时记手机上开一个备忘录遇到问题、看完某篇文章的感想、听到的好歌先丢进去不用整理格式。每周整理一次周五下午花半小时把一周的记录按标签归类顺手补充背景。月底汇总成文回顾这个月的分类记录挑出值得写的事按时间线或主题串联。这个节奏执行下来月底写月结的压力小了很多不用靠回忆硬编。也正因为这种“随手记”的习惯才让这篇月结能写出那么多细节。记录这件事本质上是在给未来的自己留线索。2. 架构设计里最痛的三个决定自研、白嫖然后返工这个月在架构上吃了不少苦最有代表性的是三个决定全部经历了“先觉得没问题、后来发现有问题、最后改了”的过程。2.1 第一个决定什么时候不该把一个服务拆出去项目在进行中遇到一个问题某个核心服务的鉴权逻辑越来越重有人提议把鉴权独立成单独的服务理由是解耦。我一开始也倾向这个方案觉得独立鉴权服务以后多个系统都能复用多好。但动手拆的时候才发现这个鉴权模块和当前系统的会话状态、用户角色缓存、审计日志都有深度耦合。如果硬拆出去每次请求都要走一次远程调用延迟增加不说一旦鉴权服务抖动所有业务全部瘫痪。而且鉴权服务的复用需求在当前阶段并不明确属于“为未来设计”的过度设计。最后的结果是拆了一半又重新收回继续保留为模块但把对外接口定义得更清晰。这个反复的过程浪费了大概三天时间但让我明白了一个判断标准要不要拆服务不看模块职责的大小而看它依赖边界的清晰程度和真正独立的部署收益。职责单一不等于需要独立部署独立部署意味着网络开销和无状态设计都要一起跟上。2.2 第二个决定自研、白嫖然后返工第二个教训来自一个配置同步的需求。要把一批配置项推送到多台机器并保证一致性。我当时觉得市场上现成方案太重不如自己写一个小工具监听配置变更、拉取、分发、校验听起来也就几百行代码的事。写了两天后发现情况不对自己写的版本只处理了最简单的“推下去”逻辑真正难的在于失败重试、版本冲突、节点间一致性、灰度发布这些机制。任何一个生产环境都会遇到这些问题而开源方案已经把这些边界条件处理了十几年。于是返工老老实实引入成熟方案把自写工具丢掉。这波“白嫖”然后返工的过程让我记住一句话基础组件不做“玩具轮子”能用成熟的就用成熟的。自研的唯一理由是业务有无法满足的特殊需求而不是“代码量不大自己能写”。如果回归到个人时间成本自己写加维护的时间远超直接集成。说多了都是泪但踩过这一脚后面就记住了。2.3 第三个决定异步比同步更稳但代价不是零第三个架构决定是数据流向问题。某个通知业务刚开始用的是同步调用用户触发动作后端立刻发送通知。结果大促那几天流量一上来通知服务响应变慢连带主流程的接口耗时直接翻倍。排查后确定要改成异步主流程只把通知任务写入消息队列消费者按自己的速度处理两者互不阻塞。这个改动方向是对的但实现过程中也容易忽略一些细节——比如消息的延迟问题、重复投递问题、消费失败后的重试策略。我们当时没有充分想清楚重试是否会打乱顺序结果出现过几条通知乱序的 bug又花了两天修补。架构上的异步化不是“把同步改成队列”就完事了它只是把即时性换成了吞吐性和稳定性引入的复杂度一个不少。现在回头看核心经验是不要为了异步而异步先确认瓶颈真的在同步等待上再决定要不要引入消息中间件。一旦引入就要把监控、重试、顺序策略一起设计进去。3. 云技术排障实录计费账单、权限策略和半夜的告警3.1 账单异常排查这个月成本多了三成问题不在服务器云技术方面的第一个故事从账单开始。月末我习惯看一眼账单结果发现这个月的费用比上个月多了大概三成第一反应是有人忘了关实例。于是打开了资源列表逐台排查实例数量没啥变化网络流量曲线也没有明显异常。后来去翻用量明细发现增长点不在计算资源而在存储——有一类备份文件本月产生了大量的跨区复制流量。继续追查才知道是那个备份脚本在本月初更新时把归档策略从“本地冷存储”改成了“复制到另一个区域的高频存储”原本是为了多一重保障结果存储单价更高、跨区流量也要钱成本就这么上去了。这个排查过程走下来我给自己的检查清单是先看账单的分项趋势定位费用增长最多的服务类别再看资源配置变化比如实例规格、存储类别、备份策略是否有改动最后查自动化任务很多成本问题源于脚本参数被“顺手”调整成本问题很少是玄学绝大多数都能通过账单明细和变更记录对应上。关键是每个月都要看一眼账单别等爆了才追责。3.2 权限策略从“都能访问”改成最小权限起因是一次误操作权限问题的起因是某个测试环境里存放对象存储的目录被清掉了一部分。排查后发现原因是有人拿到了一把权限过大的临时密钥又在执行清理脚本时写错了前缀把符合条件的一批对象删掉了。好在是测试环境没波及生产但这件事直接把全账号的权限复核提上了日程。我采用的最小权限策略思路很简单读写权限分离日常业务只授予只读权限写操作走专门的发布流程删除权限单独管控只有紧急操作才临时申请用完即回收每个密钥指定可操作的范围不授权全部空间所有高危操作强制开启二次确认权限这东西平时没人觉得有用出一次事就长记性。设定最小权限原则之后日常开发虽然多了一些申请步骤但安全感立刻不一样了。3.3 半夜告警日志采集器堆叠把内存吃干净了第三个云技术故事发生在某个周三凌晨告警机器人连续推送了两条消息某台实例的内存使用率超过 90%持续五分钟。睡眼惺忪打开电脑第一件事是查监控面板看到 CPU 不高、但内存缓慢上升。登到机器上发现问题出在日志采集器——由于部署时配置重复多个实例各自起了一个采集进程并且都配置了较高的内存缓冲大量日志被加载到内存里等待发送。几个进程一叠加内存自然就上去了。处理过程不复杂把重复的采集进程杀掉调整缓冲上限加上日志轮转让单日日志不无限膨胀。这次夜醒让我总结经验告警阈值不是越高越好而是要根据业务的基线来设定。内存这类指标要设置环比变化的告警比如“内存在两小时内增长超过 30% 就提醒”而不是只等绝对值爆了再报警。事后我又给采集配置加了去重校验避免同类事件再次发生。4. 算法与后端缓存一致性、降级方案和“差一点就清了数据”4.1 一个排序特征不一致的问题离线算的和在线取的不一样算法侧这个月有个印象深刻的排查经历。某排序服务在实验室评估效果很好上线后却表现一般大家第一反应是数据分布变了翻来覆去查最后定位到一个特征:特征在离线训练时用的是当天的统计值而在线上请求时取的是前一天缓存的旧值。这种“特征口径不一致”的问题在算法工程里很常见但排查起来非常隐蔽。离线阶段数据是批量的按天计算没问题线上阶段为了降低延迟特征通常会优先取缓存缓存过期时间却设成了前一天零点更新。两边的时间口径差了一天,模型看到的特征自然对不上。修复方式不复杂统一特征的口径定义离线生成和线上服务都改同一套计算逻辑并加了一个一致性校验任务定期对比离线和线上特征的差异率。这个案例给算法的同学提了个醒模型上线不只看效果指标特征链路的一致性同样重要不然再好的模型也跑不出应有水平。4.2 缓存一致性的实际方案先更新数据库再删缓存后端侧这个月处理了几次缓存相关的线上问题。最常见的是数据改了但界面没变典型的缓存一致性问题。我们最终采用的方案是更新数据库之后先删除缓存再异步补建热点数据的缓存。为什么不直接更新缓存因为“更新缓存”和“写入数据库”是两个独立操作一旦中间失败就会造成数据不一致而“删除缓存”则简单直接下次请求时从数据库拉最新值肯定是对的。唯一要注意的是删除操作失败的情况所以后面加了一个重试队列删除失败会自动补偿一次。当然这个方案也牺牲了一小段时间的冷启动延迟但一致性优先于性能。对于读多写少的热点数据还会叠加本地缓存做二级兜底把数据库压力控制在合理范围。能看到这个方案解决的问题比记住十种缓存策略都有效。4.3 差点清了数据任何批量操作都要先统计、再备份、再执行这个月最惊险的一次操作发生在联调环境。原本是清理一张日志表里三个月前的过期数据写了个删除脚本第一版没加数量限制直接运行结果因为条件判断写错删掉了当天数据的一大半还好在联调环境恢复起来很快。这次事故之后我给自己定了一条铁律所有批量删除类脚本必须分成三步走。第一步先跑统计语句确认要删的数据量符合预期第二步做一次备份把受影响的数据导出到临时表第三步才真正执行删除并且分批次提交每批几千条给中途叫停的机会。这三步看起来麻烦但真的能救命。后来我把这三步的检查点也写成了统一的脚本模板凡是走数据清理的需求都套用这个模板。尤其是生产环境宁可多加一道备份也不要拿数据去赌。5. 前端体验优化的几件小事体积、骨架屏和真机调试5.1 首屏体积从“一大包”变成“小包”立竿见影前端这个月没有做大的功能迭代重点放在了体验优化上。最直观的成果就是首屏资源的体积下降。之前整个打包文件都挤在一起首屏请求一个大的 JS 文件加载体验很拖沓。这个月做了三件事按路由拆分代码访问哪个页面才加载对应的模块第三方依赖单独打包合理利用长缓存避免业务代码频繁变更导致第三方库也失效重新下载图片资源全部走压缩图标改用矢量图标减少字体文件和位图请求实测下来首屏体积从原本的 900 多 KB 降到了 260 KB 左右加载时间直观感受是快了很多。体积优化从来不是什么高深算法就是老老实实做代码分割、压缩资源和缓存策略但收益非常稳定值得每个项目都过一遍。5.2 骨架屏比转圈 loading 更“聪明”的方案加载体验优化时对比了两种方案传统的转圈 loading 和骨架屏。转圈指示器的问题在于它只是一个“等待符号”用户不知道页面是什么结构心理等待时间会被拉长骨架屏则是提前把页面的轮廓画出来让用户看到内容框架正在填充感知上会更流畅。实现思路并不复杂先用静态结构画出每个模块占位符等数据返回后替换成真实内容。我在实现时给每个卡片组件加了统一的骨架模板通过一个条件标识控制显示骨架还是内容。这里有个小细节——骨架屏的动画不要做得太快闪烁频率太急会反而让人焦虑平缓的渐变效果更舒服。实际体验下来骨架屏能显著降低用户跳出率。虽然它不能减少真实的数据加载时间但它缓解了等待焦虑这在体验设计里同样是实打实的价值。5.3 真机调试发现的问题低版本内核的显示与语法坑优化视觉细节时我在模拟器上看着很完美但在一台较旧的真机上测试问题就来了圆角边框在某些低版本内核里变成了直角部分新语法直接报错导致页面白屏。这个月之后我养成了习惯任何上线功能之前至少在一台旧设备、一台新设备、一个主流浏览器上各跑一遍真机测试。模拟器的引擎内核通常比较新和用户实际设备的差异还是很大的。同时代码构建时把兼容目标调低一格新语法交给编译器转换而不是直接原样输出。真机调试配合浏览器的远程调试功能使用用数据线连接后可以直接在电脑上查看手机页面的 DOM 结构和控制台报错效率比在手机上瞎点高得多。前端开发越到后期越拼细节这些小工具和习惯往往是体验好坏的分水岭。6. 输入也是生产力播客、英文、书籍、影视与歌单6.1 收听/收看理解“演进式架构”的一次补课这个月收听方面最有收获的是几期讲架构演进的中文播客讲的不是某个具体框架而是系统如何从单体走向微服务再走向更务实的混合形态。配合我这个月自己的架构决策很多困惑一下子通了。收看方面看了一部慢热型的悬疑短剧。节奏不快但剧本结构很结实每集都能留下一个细节钩子让人忍不住往下看。里面有个情节设计的技巧让观众知道一个角色不知道的关键信息然后看着他在错误方向上运行。回来想了一下这和我们调试程序时的“预测偏差”其实是一个原理——信息不完整导致的错误推理总是要比“没有信息”更隐蔽、更危险。6.2 英文学习用阅读和听力代替死背单词确实有效英文方面的输入这个月以两件事为主。一是订阅了一份英文技术周刊每周一期每期只挑三到四篇文章速读我不要求自己逐词看懂只要求能提炼出每篇文章的核心观点并把不认识的术语记下来。坚持几周后发现专业词汇的积累速度比背单词表快很多因为每个词都挂在具体的上下文里。二是一本讲数据系统设计的英文大部头。说实话读得不算快这个月只啃完前两章但内容密度相当高。它把很多后端概念缓存、索引、复制重新从原理层面解释了一遍让我意识到很多“会用”却“没吃透”的知识其实都有更深的设计根源。英文阅读不用追求量保持每天固定读一小节长期积累的效果远好过突击。6.3 中文书籍缓存设计独立思考以及一本讲时间的书中文书部分这个月读了一本关于缓存设计的实践书正好和我前面处理的缓存一致性问题对上了。它系统梳理了缓存穿透、击穿、雪崩的成因和解法很多内容我做项目时都在用但没想到背后有这么清晰的定义和应对顺序。另一本非技术类的书是讲如何使用时间的。平时技术书读得多这种书一般我不太爱看但这次有一个点打动了我它把时间管理和项目排期做了类比认为我们最缺的不是管理工具而是明确“哪件事做完之后其他事会变得简单”。这个判断标准的思路和工作中优先级排序本质上是相通的。写月结时回味这本书确实能把“含泪”的素材变成“也没那么糟”的经验。6.4 好歌、新奇写月结时的循环歌单和一个小工具好歌方面这个月循环最多的是一首后摇没有歌词只有层层推进的吉他音墙。写月结和复盘的时候特别适合放这种音乐它不会抢占注意力但又像给思考加了一层氛围垫能让人更容易沉浸。如果你和我一样经常需要写复盘、写方案建议试试在曲库里存几首纯音乐或氛围音乐工作感受会不一样。新奇事物方面发现了一个能在终端里看天气的小工具直接在命令行输入城市名就能显示温度、湿度和未来几天的趋势。本来是一个很简单的功能但做成了彩色的字符画界面非常赏心悦目。这种小工具没什么技术含量但能给人一种“科技在细节处发光”的感觉。顺手也把周报模板改得更简练了——受它启发简单直接也是一种美。月结这个事对我来说最像一次“自我审计”。不是说做完要夸自己多厉害而是把“当时为什么这么选”“这个坑是怎么掉进去的”如实记录下来。下个月回头看能少踩一半的坑。下一篇月结更新的时候希望我能少点“含泪”多点“憋笑”——毕竟踩坑踩多了多少也长点记性。下月底见。