
写这篇手记时我刚把一台跑了两年的服务器做了一次彻底清理。看着控制台上那几行熟悉的进程名心里生出一股很复杂的感受技术迭代快得让人喘不过气但真正陪着你扛住线上流量的其实还是那几个老伙计外加一两个偶尔加入的新面孔。有人喜欢追新把框架版本号当成炫耀的资本有人坚守旧物视迁移为洪水猛兽。但后端工程这行当纯粹的浪漫主义者和极端的保守派都走不远。技术选型的本质是对风险、成本与团队习惯的三角妥协。今天不聊宏大的架构理论就想掰开揉碎了聊聊这些年我真正在用的、用出感情的东西以及那些踩过的坑和做过的最务实的决定。Web框架从重甲到轻骑的进化我入行那会儿Spring Boot 正处于如日中天的地位。它的生态太齐全了只要引入依赖一个自带内嵌Tomcat的JAR包就能跑起来仿佛拥有了整个工业标准。那时候项目里密密麻麻的Autowired和 XML配置是安全感的来源到处都是标准的欧洲宫殿式建筑体面可靠但重。后来接触到 Go 语言那种体验像是从重型装甲车换成了一辆改装的越野吉普。Gin 框架的简洁让我震撼没有继承体系没有反射带来的那些说不清的诡异行为一个c.JSON(200, obj)就能撑起业务半边天。它带来的不仅是性能数字上的飙升更是心智负担的骤降——当你的团队只有三五个人时这种极简主义能让你把精力全部放在数据模型和业务逻辑上。但现在回过头去看我发现自己最终保留下来的习惯是混合模式。对内的低并发管理后台我依然会选用那些重框架因为后台需要的是权限管理、代码生成器和丰富的模板支持这能极大压缩搭建成本而对外的核心API网关和流量入口我坚定地转向轻量级框架。因为那个承载着业务最高QPS的节点其对内存的占用要求苛刻到以MB为单位这里容不下半点花哨。关系型数据库别把神器当成锤子必须得承认MySQL依然是这个星球上最普适的关系型数据库。这些年我花了大量时间在调优它的慢查询上。早期的项目里由于缺乏对索引的敬畏一条三表 JOIN 的SQL能把数据库拖垮在凌晨四点。后来我养成了一个固执的习惯代码里禁止出现复杂的 JOIN哪怕只是两表关联。你要是问我为什么我会说这是在为未来的分库分表提前赎罪。业务初期看似优雅的JOIN在数据量达到千万级时就是一场灾难。你会发现把关联查询拆解成两次简单查询在服务层用内存去拼装数据性能反而能快上一个数量级。我也用过 PostgreSQL 一段时间。它的 JSONB 类型确实是处理半结构化数据的利器。不过在国内的大环境下MySQL周边工具链的成熟度依然是最优解比如基于Binlog的Canal组件来做数据异构是很顺滑的。最好的技术不是最强的技术而是容错率最高的技术。当你深夜三点被告警震醒最希望的往往是那个有着最多社区讨论、最多踩坑资料的数据库而不是一个需要你费力搜索英文文档的冷门神器。缓存与队列流量的双重护城河Redis 是每个后端工程师的基本盘。我几乎把它用到了极致分布式锁、热点数据缓存、排行榜、甚至还有简单的消息中转。直到有一次我在缓存里存了一个巨大的聚合结构导致内存碎片化严重最终触发OOM我才意识到过度的依赖缓存本质上是用复杂度换性能而这笔账迟早要还的。后来我给自己定了个规矩能用数据库原生功能解决的小并发场景就绝不动用 Redis一旦动用 Redis就必须考虑缓存穿透、击穿和雪崩的应对方案。缓存不是挡箭牌而是显微镜它会无限放大你底层逻辑的缺陷。说到队列我从初期的 RabbitMQ 用到了现在的 RocketMQ 或 Kafka。RocketMQ 在金融级别的消息可靠性方面表现得很好支持事务消息对于核心支付的异步化处理它是定心丸。但我特别想强调的一点是队列架构最忌讳“为了用而用”。如果你的业务量每天才几千次操作那种在单机事务里就能保证一致性的操作就不要硬塞进消息队列里去制造分布式事务的难题。大部分团队死在了架构设计过度上这不是工具的错是我们对工具的滥用。注册中心与配置管理微服务化的浪潮曾经席卷而过我们这批人也跟风拆过服务。拆完之后发现最棘手的并不是业务逻辑的切分而是服务之间的发现与协调。Consul 和 etcd 我都用得很熟。就个人体验而言etcd 的分布式一致性协议和键值模型在存储集群元数据时极其顺手而且其 watch 机制反应极为灵敏。它像一个记忆力超群的传令兵能够极快地将配置变更同步给每个节点。但用久了你会发现配置中心最核心的不是强一致性而是可用性与版本管理。你绝对不希望因为配置中心的抖动导致线上服务集体断连重启。所以我在生产环境搭建配置中心时会特意设计降级策略客户端本地快照即便在配置中心宕机时也能维持运行。这是经验之谈永远要为最坏的情况设计1%的幸存概率因为那1%的意外往往决定着你是否能保住当月的年终奖。容器化编排如果在2023年之前我可能还会写“Kubernetes是趋势”。但现在它已经成了我们的默认操作系统。基于Docker镜像的开发流程让“本地跑得起来”和“线上能跑起来”变得毫无差异。我记得刚推行容器化时团队里抵触情绪最重的是一位老DBA他无法忍受数据库也要容器化。后来我们达成了共识数据库这种有状态服务依然使用物理机或者云盘挂载但应用层包括像Nginx这类的接入层全部容器化。所谓的Kubernetes原教旨主义在现实业务面前一文不值把无状态服务管好就已经吃掉流程里80%的效率红利。服务的可观测性年轻时写代码只管功能上线现在写代码心里挂念的是另外三件事日志、指标、链路追踪。以前排查问题是登录到服务器上tail -f看日志充斥着暴力破解美的原始感。但现在不行了服务一多实例一多你必须依赖集中式日志平台。我极其推崇链路追踪的普及。它像一个跨系统的时空透视镜能让你一眼看穿用户请求在几十个微服务之间的真实路径。用上了它以后你的排错时间至少能缩短一半。甚至为了降低耗点成本我们采用采样策略保留关键入口的100%采样。没有可观测性地做微服务约等于蒙着眼在全速行驶的高速上换轮胎出事只是时间问题。工具链上的老朋友除了那些重量级框架还有一批小工具始终在默默支撑着日常开发。比如HTTP客户端中的curl从入门到进阶以及现代化终端下的jq命令。不要小看这些命令行小工具当你流利地在终端里清洗 JSON 数据而旁边的小朋友还在手忙脚乱地翻看 Postman 的历史记录时那种效率的优越感带来的爽快是很提神的。还有 API 文档工具。我们在全力推行OpenAPI 规范。代码能生成文档文档也能生成代码。这点很多人没意识到后端程序员最值钱的能力不一定是算法有多叼而是定义好边界与契约的能力。用make或Taskfile来维护项目构建指令这是极其明智的。它可以让新人免于在繁杂的构建命令和漫长的环境配置中沉沦。把复杂的构建流程变成一个简单的make build是对团队后来者的最大善意。关于新技术的审慎最后聊聊 Rust 和 WebAssembly。以前看见写Rust的人总觉得他们像苦行僧现在却会敬佩那份对资源掌控的极致追求。我用 Rust 重写过一个小型的数据上报模块内存占用直接砍掉了60%那体验确实爽。但这并不意味着我们要把所有系统都推翻重写。优秀的后端工程师往往对新奇的技术充满克制。成熟的技术栈意味着你的坏境是可预知的你同事的脑回路是可沟通的。你引入一个新框架不只是引入一段代码而是引入了一整套认知负担和潜在的人才招聘门槛。所以我的手记里那些被频繁标记的五角星大多不是最时髦的框架而是最稳定的社区、最少的坑、最顺滑的 CI/CD 流程、以及那些能将人从繁琐中解放出来的自动化工具。技术的终点是业务跑得稳团队活得久。结构远比功能重要习惯远比技术重要审慎远比激情重要。最后谈谈运维与云原生如果说框架是手里的剑那云原生理念就是我脚下的地图。以前自己搭建 ES 集群调 JVM 参数调到怀疑人生遇到 GC 瓶颈只能抓耳挠腮。现在直接托管云厂商的托管版虽然贵但能让我们把精力花在业务数据治理上。不过云服务也有让人头疼的地方。贵是绝大部分云原生产品最大的缺点但它依然比人力成本便宜得多。因为在Kubernetes集群里折腾过的人都知道那种深夜里因为网络插件或者存储卷故障而导致的雪崩往往是最无能为力的。所以我现在的策略是基础服务走云托管业务应用走容器化这是目前阶段性价比最高的平衡点。每过一段时间我都会回看旧项目里依赖的框架版本。那种感觉就像翻看自己五年前写的日记一边为当年的幼稚发笑一边又为当初的勇敢而庆幸。技术的迭代从来不是推翻重来而是一层又一层的覆盖与沉淀。那些被我淘汰的工具不应该被称作垃圾它们是我们走向更高处的垫脚石。而未来我会继续持有着这种对技术复杂度的敬畏和对业务本身的理解去迎接下一个阶段的挑战。手里的家伙事儿会变但作为后端工程师的那份追求确定性的耐心永远不会变。