Administrator
发布于 2026-03-01 / 406 阅读
9

构建可演进的系统:八年技术选型复盘

入行第八年,我把这八年做过的选型列了张表

2026 年 3 月,我入行整八年。过年期间我把这些年参与过的重大技术选型整理了一遍,一共 34 项,标上当时的决策理由、实际结果、以及现在的回头看评价。

结果有点难堪:34 项里,现在看是正确决策的 19 项,过早的 6 项,过晚的 5 项,纯错的 4 项。也就是说我有 26% 的选型是明确失败的,还有 18% 是时机不对

这篇是把这张表里的教训抽出来。不写成功案例,成功的选型往往运气成分大,失败的才有信息量。

四类错误

先给个总览,34 项按错误类型分类:

错误类型数量典型例子平均代价
过早追新62019 年上 Service Mesh、2021 年上 Serverless Java3.5 人月沉没
过晚跟进52023 年才上容器化、2024 年才建可观测体系长期效率损失
被非技术因素绑架4为「简历好看」选的技术栈2 人月 + 团队分裂
忽略了可逆性4一次性的大爆炸式重构6 人月 + 两次 P2

过早追新:Service Mesh 那一年的账

2019 年,我们在 200 个服务上推 Istio。当时的理由是「服务治理下沉,业务代码零侵入」,PPT 做得非常漂亮。实际结果:

  • Sidecar 带来的延迟:P99 从 48ms 涨到 73ms,多跳服务涨到 120ms;
  • Envoy 配置排错极难,我们有三次故障是 Envoy 的路由配置写错,排查时间都在 4 小时以上;
  • 运维复杂度:从管 200 个服务变成管 200 个服务 + 200 个 Sidecar + 一套控制平面;
  • 团队学习成本:6 个人专门学了两个月,最后只有 2 个人真正能处理线上问题。

撑了 14 个月,我们拆掉了,回到 Spring Cloud 的 SDK 模式。沉没成本大概是 26 人月,这还不包括那 14 个月里的两次 P2 故障。

回头看,失败的根源不是 Istio 不好,是我们当时根本没有那个规模的问题。200 个服务、多语言只有 Java 和 Go 两种,SDK 模式完全够用。Service Mesh 解决的是「几十种语言、几千个服务、跨团队协作」的问题,我们一个都没碰到。

我当时的判断逻辑是「这个技术很先进,早上有先发优势」。正确的判断逻辑应该是「我现在有什么问题是它解决的,不解决会怎样」。前者是追新,后者是解题。

过晚跟进:可观测体系建得太迟

这个是反面。我们直到 2024 年才有完整的链路追踪和指标体系统一,之前是各团队各搞各的。

代价很难量化,但有两件事我记得很清楚。2022 年一次跨 7 个服务的性能问题,我们 4 个人查了整整三天,最后发现是其中一个服务的连接池配置错了。如果有链路追踪,这个问题 15 分钟就能定位。

另一件事是容量规划。没有统一指标,我们只能靠「感觉」分配资源,导致整体资源利用率长期在 12% 左右。2024 年上了监控之后做了一轮治理,利用率提到 31%,一年省了大概 180 万的机器成本。

为什么拖了那么久?因为它「不紧急」。可观测性这东西,没有的时候大家也能干活,只是慢;出了事也能查,只是久。它的价值是隐性的,所以永远排不进优先级。

我现在的原则:属于「基础设施」性质的东西,不能等业务驱动,必须主动排期。判断标准很简单——如果缺了它,问题能被解决只是更慢,那它就是基础设施,就要提前建。

被非技术因素绑架:那次「为了简历」的选型

2021 年我们做了一个数据同步平台,选型时我在两个方案里犹豫:Kafka Connect 和一个当时刚出的新锐流处理框架。客观评估 Kafka Connect 更合适——生态成熟、运维简单、团队熟悉。但我选了后者,理由是我和另外一个同事都想借此深入学习这个框架。

结果:框架在生产上暴露了 4 个 bug,我们自己改了源码、维护了一个 fork 分支,前前后后 8 个月。最后还是换回了 Kafka Connect,8 个月白干。

这件事我记到现在,因为它揭示了一个我一直不愿意承认的事实:技术选型时,个人成长诉求会伪装成技术判断。当时我给自己找的理由是「Kafka Connect 太重」「新框架性能更好」,这些理由不是完全站不住,但如果我诚实地打分,客观因素里 Kafka Connect 赢 7 项,新框架赢 2 项。

现在的规矩:重要选型必须写 RFC,RFC 里要有打分矩阵,每一项权重和分数都要写出来。这个形式主义很有用——它逼着我把主观偏好暴露在纸面上,当着团队的面,我就不好意思把「我想学」包装成「性能更好」了。

忽略可逆性:那次大爆炸式重构

2022 年我们把一个 12 万行的单体订单系统拆成微服务。方案是「一次性拆完,切流量时全量切换」。

结果:原计划 3 个月,实际 7 个月;上线后连续 5 天每天都有 P2/P3 故障;回滚预案形同虚设,因为数据已经按新模型写过一遍了,回滚要写补偿脚本。

核心错误是不可逆。一次性切换意味着没有中间状态,没有灰度,没有「先切 5% 流量看看」的机会。所有的验证都发生在上线前,而上线前的验证永远覆盖不了生产的复杂度。

对比一下我们在 2025 年做 RAG 引擎替换时的做法,同样是大的架构调整,代价小得多:

维度2022 订单拆分(不可逆)2025 RAG 引擎替换(可逆)
切换方式一次性全量按租户灰度,1% → 5% → 20% → 100%
数据模型新模型直接写双写,旧模型保留 3 个月
回滚需要写补偿脚本改一个配置开关,30 秒
验证周期上线后 5 天救火灰度期 6 周,每周调整
总耗时7 个月3 个月(含 6 周灰度)
P2 及以上故障5 次0 次

关键的设计差异就一条:新旧并行,随时可切回。为了做到这一点,我们多写了大概 15% 的代码(双写、开关、对比校验),但换来的是「试错的权利」。

我现在的决策方法论

八年下来,我形成了一套固定的流程。不复杂,但每一条都是代价换来的。

一、先问「不换会怎样」,再问「换了会怎样」

大多数选型的驱动力不是痛点,而是焦虑。我会强迫团队先回答一个问题:如果我们什么都不做,半年后会发生什么?

如果答案是「系统会挂」「成本撑不住」「业务做不了」,那是真痛点,值得动。如果答案是「可能有点慢」「不够先进」「别人都在用」,那就先别动。

2024 年我们评估要不要上 GraalVM 原生镜像,用这个问题一问就清楚了:不上会怎样?答:启动慢 2.4 秒,在长驻服务里无所谓。那就只在 Serverless 场景上用,普通服务不动。这个判断帮我们省了至少两个月。

二、给每项技术标一个「成熟度坐标」

我用一个两维坐标:技术成熟度(0~10)和 我们的适配度(0~10)。

适配度 10 |  观察区        |  立即采用
          |               |
        5 |  放弃          |  试点
          |               |
        0 |_______________|______________
           0             5            10
                    技术成熟度

观察区(成熟度低+适配高):值得跟,但只做 POC,不进生产
试点(都高):小范围生产验证,设明确的评估期
立即采用(都高且成熟):直接用
放弃(适配低):再火也不用

举例:2026 年初的 Spring AI 2.0 里程碑版本,我的打分是技术成熟度 4(还在 M 版本,API 会变)、我们的适配度 9(我们要的就是它的 Advisor 重构)。落在观察区偏右,所以结论是「跟,但只用在新服务上做 POC,存量不动」。这个判断到今天没出问题。

反过来,Agent Skills 这类 2026 年才出现的新规范,成熟度 2、适配度 7,明确在观察区,我们只派一个人做了两周调研,没有投入工程资源。

三、可逆性优先于最优性

这条我放在最高优先级。一个 80 分但可回滚的方案,永远优于 95 分但不可逆的方案。

具体做法有三条:

  1. 能加层就不要改现有层。加一个适配层,比改 50 个调用点安全得多。我们在接入第三个 LLM 供应商时,加了一层 ModelGateway 接口,业务代码零改动;
  2. 数据迁移一律双写。新旧存储同时写,用对账任务校验差异,差异率连续 7 天为 0 才切读;
  3. 所有切换必须有一个能在 5 分钟内生效的开关。可以是配置中心的开关,可以是 Feature Flag,可以是网关路由权重,但必须有。

第三条我们执行得最严格。现在我们的代码评审里有一条硬规则:任何超过 200 行的改动,如果没法通过开关回退,就不批。

四、给「退出」留预算

这是最近两年才加上的一条。任何选型,在决定采用的时候,就要想清楚「如果要换掉它,代价是多少」,并且把这个数字写进 RFC。

比如我们选向量数据库时,三个候选的退出成本:候选 A 用了私有协议,迁出要重写全部索引代码(约 20 人日);候选 B 支持标准 SQL 接口(约 5 人日);候选 C 是云厂商托管,迁出要重新买资源+数据导出(约 12 人日 + 迁移费用)。最后选了 B,虽然它在性能上比 A 差 8%。

退出成本高的技术,等于给自己上了一道枷锁。 锁定期越长,被供应商和过时技术绑架的风险越大。

五、两年之约

每上线一项重大技术,我会在 RFC 里写一句「两年后我们回头评估」。到时间了就真的评估,不管有没有出问题。

这条听起来像形式主义,但它解决了「沉没成本不愿承认」的问题。因为评估时间点是在采用之前就定好的,到时候做「换掉」的决定,心理负担小得多——这不是承认错误,这是按计划执行。

我们用这个方法在 2025 年主动下线了两套系统:一套自研的任务调度(换成 XXL-JOB),一套早期的特征平台(合并到新的数据平台)。两次都是「没出问题但维护成本高」的情况,如果没有两年之约,大概会一直拖下去。

关于追新

最后说说「追新」这件事。我现在的观点比八年前保守得多,但不是反对新技术。

我的做法是把「追新」和「生产采用」彻底分开:团队里必须有人持续追新,这部分时间我给预算(大概每人每月 2 天),产出是 POC 和技术雷达;但生产采用走另一套严格流程,追新的人没有决策权。

这样既不会因为保守而错过真正的变革(比如 2023 年虚拟线程,我们的 POC 做得早,正式采用时很从容),也不会因为激进把团队拖进坑里。

还有一个个人体会:真正的变革性技术,给你留的窗口期通常比你以为的长。虚拟线程从预览到转正三年,Spring Boot 从 2.x 到 3.x 给了两年过渡期,容器化的窗口更长。那些「不上车就晚了」的焦虑,回头看基本都是幻觉。而那些真的晚了的技术(比如我们的可观测体系),往往是因为没意识到它是基础设施,不是因为错过窗口。

小结

整理这张表的时候,我最强烈的感受是:八年前我以为技术选型是比谁懂得多,现在我知道它是比谁更能准确估计自己的问题

那 34 项里失败的 9 项,没有一项是因为我对技术本身理解不够。失败的原因是:高估了问题的严重程度(过早追新)、低估了问题的严重程度(过晚跟进)、把个人诉求当成了技术判断、以及低估了一次性决策的风险。

所以我现在的决策流程里,花在「理解技术」上的时间大概只占 30%,剩下 70% 花在「理解我们自己的问题」和「设计退路」上。这个比例,是我这八年最贵的一条经验。

参考