做技术架构这些年,我越来越觉得它像一栋房子的地基和管线——住进去的人看不见,但下水道堵没堵、电路稳不稳、楼上楼下会不会串味,全看这一层。市面上聊架构的文章很多,天天有人讲微服务、讲分布式、讲云原生,但真正把“技术架构”当成一个独立命题来拆解的,反而不多。这篇文章我打算把第四章的第三部分展开细讲:技术架构到底是什么、它凭什么是整个系统的“稳底盘”、设计它的时候有哪些绕不开的原则和坑。无论你是刚接手系统设计的开发,还是已经在带团队做技术选型的负责人,这篇内容都应该能帮你把脑子里那些零散的经验串成体系。
1. 技术架构到底是什么——先把“底盘”这个概念讲清楚
1.1 技术架构不是一堆中间件的堆砌
很多刚入行的同事问我,技术架构是不是就是“选什么数据库、用不用消息队列、上不上Kubernetes”。我一般会反问一句:如果给你一堆最好的零件,你能保证组装出来的车一定跑得稳吗?
技术架构的本质,是对系统非功能性需求的结构性回答。它关心的不是某个订单接口怎么实现,而是整个系统在成千上万的请求打过来时,谁能扛住、谁能降级、谁能恢复、谁能被监控到。你选的每一款中间件、每一种部署方式、每一层网络分区,都是对这个核心问题的具体应答。
举个直白的例子:电商大促的时候,订单服务扛不住流量,技术架构要解决的不是“改代码重试”,而是提前在架构层面想清楚——流量入口哪里限流、订单数据如何分片、库存扣减怎么做幂等、消息积压了怎么预警。这些都是技术架构的范畴,它横跨基础设施、数据层、中间件、应用运行时,甚至包括运维制度和发布流程。
从这个角度看,技术架构更像是一套约束体系。它约束了你“能怎么做”和“不能怎么做”。技术架构定了,后续的业务开发、数据模型、部署方案都要在这个框架内活动。这也是为什么架构评审往往比代码评审更严肃——改一行代码影响一个函数,改一个架构决策影响整个系统未来两三年的走向。
1.2 技术架构在“三大分类”里的位置
标题里提到“架构三大分类”,这里先对齐一下语境。我习惯把架构分成三个维度看:业务架构解决“做什么”,数据架构解决“怎么管数据”,技术架构解决“靠什么稳定运行”。三者各有侧重,但技术架构天然是另外两个的底座——你可以把业务架构画得很美,但如果没有一个稳的技术架构兜底,业务逻辑再清晰也会被线上故障打回原形。
我在实际工作中经常遇到一种错位:业务团队催着上线新功能,技术团队却在讨论数据库连接池满了怎么办。这其实不是执行力问题,而是技术架构缺位导致的结果。业务架构决定了系统要提供哪些能力,数据架构决定了数据怎么流转,而技术架构决定了这些能力和数据在物理世界里能不能被可靠地承载。
技术架构还有个容易被忽略的特征:它是被动暴露问题的。业务架构设计错了,顶多功能不好用;数据架构设计错了,顶多报表对不上;技术架构设计错了,故障一来就是全军覆没,用户直接打不开页面。所以技术架构领域有一句老话:稳定是最高的优先级,功能可以后补,数据可以修复,但一个正在发生的故障面前,所有新需求都得让路。
2. 设计技术架构时要想清楚的几件底层事
2.1 先定约束,再谈选型——不要跳进工具的海洋
我见过太多次技术选型翻车,共同的毛病都是:先选了工具,再去找问题。听说Redis快,就把所有数据都塞进Redis;听说微服务潮流,就把一个单体硬拆成二十个服务。这不是在做技术架构,这是在追星。
真正靠谱的顺序是倒过来的:先列出这个系统的硬性约束,再让工具来适配约束。这些约束包括但不限于:
- 可用性目标:全年可用性要几个9?9意味着一年最多停机52分钟,99.99%意味着一年只能停52分钟,这是天壤之别。
- 性能指标:核心接口的TP99响应时间是多少?峰值QPS大概多少?数据量什么时候会到千万级、亿级?
- 数据一致性要求:订单库存这类数据能不能容忍一秒延迟?用户昵称这类数据能不能接受最终一致?
- 团队运维能力:团队里有几个人能扛住Kubernetes的运维?如果只有一个运维,上太复杂的中间件本身就是风险。
把上面这些约束写在一页纸上,再去比选技术方案,你会发现很多纠结根本不存在。比如一个日活几万的后台管理系统,硬上微服务加服务网格,除了增加运维负担没有任何收益。技术架构的意义不是“用最先进的技术”,而是“用最匹配的技术”。
注意:约束清单一定要让业务方签字确认。不是推卸责任,而是后面对话时有个共同基准。我就遇到过业务说“这个报表要实时”,结果真实业务场景是T+1就能满足,一句话的事,省掉了整个实时计算平台的搭建成本。
2.2 容量评估不是拍脑袋——量化才是技术架构的底气
技术架构里最容易吵起来的就是容量问题。开发说“这个接口以后流量会很大”,运维问“大是多大”,然后两边开始互相说服。要打破这种局面,必须把容量问题量化成数字。
核心就三类数:QPS、数据量、带宽。
拿QPS来举例。假设一个登录接口峰值每秒来1000个请求,一次完整的登录处理要查一次MySQL、写一次Redis、调一次风控服务。那这个接口的技术架构至少要做到:MySQL能扛住1000次读(如果走主库的话,要确认主库的QPS上限),Redis的读写延迟要在毫秒级,风控服务的超时时间要设置合理不至于拖垮主流程。把这些数字落到纸面上,技术架构的每一层该承担多少压力就一目了然了。
数据量的估算同样重要。一个业务表如果每天新增50万行,一年就是1.8亿行。你就要提前想清楚:什么时候该分表、按什么键分、分完怎么聚合查询。垃圾数据和历史数据要不要归档?归档后查询走什么通道?这些问题不在架构设计阶段想清楚,等数据撑爆磁盘的时候再处理,成本至少翻五倍。
带宽也是个容易被低估的项。日志采集、数据同步、文件传输,这些流量在生产环境里加起来比业务流量还猛。我有一次排查线上问题,最后发现罪魁祸首是某个服务的日志框架把debug级别的日志全部打了出来,一天产生了几百GB的日志,直接把磁盘和带宽都打满了。技术架构里对日志级别、日志采样、日志保留策略都要有明确的约定,而不是让开发随意发挥。
2.3 稳定不是靠运气——故障要“设计掉”而不是“祈祷不发生”
做技术架构最忌讳的心态就是“应该不会出事吧”。系统上线之后,出故障是必然的,不出故障才是偶然的。成熟的技术架构师会把故障当成一个必然事件来设计,在架构层面预留好各种“后手”。
这里我最常强调的三个词是:冗余、降级、幂等。
冗余解决的是“单点故障”问题。任何一台机器、任何一个中间件、任何一条网络链路,只要它是单点的,就一定是风险点。数据库要主从,缓存要哨兵,消息队列要集群,负载均衡要至少两台。冗余虽然会增加成本,但它是技术架构里最直接的“买保险”。
降级解决的是“局部故障影响全局”的问题。下游服务超时了,你是选择重试还是快速失败?缓存挂了,是选择直接查数据库还是干脆返回兜底数据?这些决策应该在架构设计阶段就定好,而不是等故障发生时才临场发挥。我做过最成功的降级设计,是一个推荐接口在依赖服务异常时自动返回热门榜数据,用户完全无感知,但系统成功率硬生生保住了三个九。
幂等解决的是“重复请求造成的数据混乱”。网络超时导致的重试、消息队列的重复投递、用户双击提交订单,这些都是常态。技术架构层面要求核心写接口必须支持幂等,通常靠唯一请求号加去重表实现。这件事看起来不起眼,但线上大多数脏数据都源于幂等没做好。
3. 一个技术架构方案是怎么从零长出来的——实操视角
3.1 第一步:把业务需求翻译成架构约束
假设我们现在要设计一个电商交易系统的技术架构。第一步不是画拓扑图,而是找业务方和产品经理聊清楚几个关键问题:预计峰值订单量是多少?大促时流量会翻几倍?商家后台的查询需求有多复杂?用户对价格和库存的实时性要求有多高?
把这些答案整理成一张约束表,然后才能开始架构设计。比如:
| 约束项 | 目标值 | 架构影响 |
|---|---|---|
| 核心下单接口TP99 | ≤ 300ms | 数据层和缓存层必须就近部署,避免跨地域调用 |
| 峰值QPS | 5000 | 应用层需要水平扩展能力,网关要提前设限流阈值 |
| 库存数据一致性 | 强一致 | 数据库不能随意分库,要使用分布式事务或锁方案 |
| 全年可用性 | 99.99% | 必须多可用区部署,数据库必须主从切换能力 |
| 订单表年增量 | 2亿行 | 订单表需要按时间分表,并规划冷热数据分离 |
这张表就是技术架构的“需求文档”。后面所有选型和设计,都要能回答“这个选择是为了满足哪一条约束”。如果某条约束变了,技术架构也要跟着调整。这就是技术架构能够保持“活”而不是“僵死”的关键。
3.2 第二步:基础设施层与部署形态的确定
约束清楚了,先定最底层的事:系统部署在哪里,以什么形态运行。
这个阶段要做的决策有三个。第一,用物理机还是云主机?如果是初创团队,云主机几乎是唯一选择,省去机房运维的精力。第二,用容器化还是传统虚拟机部署?容器化带来的好处是环境一致性和弹性伸缩,但前提是团队能驾驭Docker和编排系统。如果团队只有两三个人,Kubernetes的学习成本可能会拖慢业务迭代,这时候用docker-compose管理几台机器反而是更务实的选择。第三,要不要多可用区?多可用区部署是99.99%可用性的前提,但同样意味着网络延迟和成本上升,需要跟业务目标对齐。
我在这个环节从不追求“最好”的方案,只追求“团队在一年后依然能好好维护”的方案。技术架构是给团队用的,不是用来面试炫技的。一套运维不起来的高大上架构,最终只会变成一台精致的故障制造机。
3.3 第三步:数据层与核心中间件选型
基础设施定了,接下来就是数据层。这个环节我坚持一个原则:优先用成熟稳定的组件,新技术必须要有足够理由才引入。
关系型数据库仍然是一切的基石。MySQL稳坐头把交椅,开源、生态成熟、网上资料多,团队招人也好招。数据量大了先做读写分离,再不行就分库分表,这些都有非常成熟的方案。至于要不要上分布式数据库,我的判断标准很简单:单表数据量是否真的超过了千万级?写入并发是否真的突破了单库瓶颈?如果答案都是“否”,那就别给自己找麻烦。
Redis和消息队列几乎是现代业务系统的标配。缓存解决读压力,消息队列削峰填谷、解耦异步。但要特别注意,引入的中间件越多,出故障的概率和维护成本就越高。Redis的缓存穿透、消息队列的消息堆积、连接池耗尽,每一个都能让你大半夜爬起来。选型的时候多问问:这个中间件团队里有人真正用过吗?出问题的时候谁能修?
3.4 第四步:可观测性体系——没有监控的架构等于盲开
技术架构里最容易被砍掉、但最不该被砍掉的就是可观测性建设。很多团队上线前才想起来加监控,只加了一个“服务器CPU超过80%报警”,然后就觉得万事大吉。等到线上真的出事了,日志查不到、链路断掉、不知道是哪个服务拖慢了整个请求,那种感觉就像在黑屋里找一只黑猫。
我现在的标准配置是三件套:日志、指标、链路追踪。
- 日志要全量采集,但全量采集不等于全量存储。日志要分级别处理,info以上进实时检索,debug级别的采用采样存储,既能排查问题又不会打爆磁盘。
- 指标至少覆盖三大类:业务指标(订单量、支付成功率)、系统指标(CPU、内存、磁盘、网络)、中间件指标(Redis命中率、MQ积压量、数据库连接数)。
- 链路追踪用来串联一次请求经过的所有服务。没有链路追踪,微服务架构里排查问题基本靠猜,有了它,一眼就能看出慢在哪一跳。
可观测性建设投入的资源,换来的是故障从“小时级定位”变成“分钟级定位”。这笔账怎么算都不亏。
4. 技术架构的演进——没有一步到位的完美方案
4.1 从单体到分布式:演进的触发信号
技术架构最迷惑人的一点在于,它看起来有很多“标准答案”——微服务、云原生、Serverless,但真实世界里每个系统都是一步一步长出来的。我经历过单体架构运行了五年依然健康的系统,也见过上线三个月就急着拆微服务的项目被复杂度拖垮。
那到底什么时候该从单体走向分布式?我总结出三个信号:
- 团队规模信号:一个代码库几十个人同时开发,合并冲突变成家常便饭,发布排期互相牵制,这时候拆服务是解决协作问题,不是为了跟风。
- 性能瓶颈信号:某个模块的资源消耗明显跟其他模块冲突,比如定时任务把CPU打满导致在线接口响应变慢,这时候把重任务拆出去是合理的。
- 独立扩展信号:不同模块的扩展需求差异太大,比如订单模块需要在大促时疯狂加机器,而用户模块常年没什么流量,拆开后可以各自独立扩缩容。
如果这三个信号一个都不占,那继续维护单体不是丢人的事。反而,单体架构部署简单、排查方便、事务好做,是很多业务场景下最稳的方案。
4.2 微服务不是终点——分布式带来的新问题
很多团队拆了微服务之后,发现日子并没有变好,反而多了一堆新的烦恼。服务调用变成了网络调用,原本一个函数的事现在要经过负载均衡、序列化、网络传输;分布式事务从SQL就能解决变成需要各种中间件和补偿方案;原来一个日志文件看全局,现在要把几十个服务的日志拼起来才能还原一次请求。
技术架构演进的核心逻辑永远是用复杂度换能力。微服务换来了独立部署、独立扩展、技术异构的能力,代价就是上面这一串复杂度。架构师的任务不是“多拆”,而是“看清楚当前规模和业务阶段需要什么能力,值与不值”。
我见过一个从微服务退回单体的案例,原因很简单:系统总QPS不到100,团队五个人,微服务带来的好处完全用不上,但每天晚上光部署就要折腾一小时。有些人可能觉得这是退步,但在我看来,让团队回归轻松状态就是技术架构的正确调整方向。架构没有高低之分,只有匹配不匹配。
4.3 技术架构治理:标准化是长期稳定的前提
一个系统在线上的时间越长,技术架构就越容易“腐化”。今天这个服务用了一个新框架,明天那个服务换了一种消息序列化方式,后天有人直接把代码部署在了一台没有监控的机器上。这些事情单看都不致命,但累积起来,就是未来重大故障的温床。
所以技术架构不只是设计出来的,更是治理出来的。我常用的治理手段有三类:
一是技术栈统一。规定主流的语言版本、框架版本、中间件版本,新项目原则上必须使用标准技术栈,老项目逐步迁移。这样既能保证团队经验沉淀复用,也能避免大量“只有一个人会维护”的冷门技术栈。
二是架构评审机制。任何涉及系统拓扑变化的改动,都要走架构评审,哪怕最后结论是不改。评审的价值不在于审批,而在于让提出方案的人把思考过程完整呈现一遍,这个过程本身就能过滤掉很多拍脑袋的决策。
三是架构监控与度量。对关键架构指标持续监控,比如核心服务的健康状态、依赖关系的复杂度、实例利用率的分布。当指标恶化到一定阈值时,主动触发重构和优化,而不是等故障来敲门。
5. 实战中的常见问题与排查思路——都是踩过的坑
5.1 几个高频坑位与应对思路
| 现象 | 根因 | 排查思路与解法 |
|---|---|---|
| 数据库连接池被打满 | 应用层连接泄漏或峰值流量超预估 | 先查连接池监控确认是哪个服务占用,再查代码里是否有未关闭的连接;架构层面加连接池上限和排队策略,宁可快速失败也不要无限等待 |
| Redis缓存穿透导致数据库压力暴增 | 查询不存在的数据每次都落库 | 缓存空值并设置短过期时间;用布隆过滤器挡掉不存在的key;接口层加限流 |
| 消息队列堆积越来越深 | 消费能力跟不上生产速度 | 先扩容消费者实例数量;确认消费者是否有慢查询或外部调用阻塞;长期方案是削峰、批量消费、调整分区策略 |
| 接口超时但服务CPU不高 | 可能在下游服务或网络链路上 | 用链路追踪看每一跳的耗时;重点排查外部依赖服务的慢响应、网络抖动、线程池排队 |
| 大促期间系统假死 | 流量超过预估且没有限流 | 网关层加全局限流,核心链路优先保订单支付,非核心功能做强降级;复盘时校准容量预估模型 |
这张表我每次做架构分享都会贴出来,因为里面每一行都是我或者我的同行用真实故障换来的。技术架构这个领域没有“天才式的灵光一现”,都是一个个问题逼着你想清楚、改明白。
5.2 排查问题的几个习惯,关键时候救命
先说第一个习惯:永远保留现场。系统出故障的时候,很多人第一反应是赶紧重启,但重启之前一定要把该抓的信息抓下来——堆栈、线程状态、数据库当前连接数、JVM内存快照。这些信息等系统恢复之后再想补,就再也补不回来了。我在团队里立了一条规矩:没有保留现场之前,不允许直接重启。
第二个习惯:监控数据要比业务早一步。每次发布新功能,先看监控再问业务。监控指标异常往往早于用户投诉,等到用户来投诉的时候,问题的影响面可能已经很大了。我要求核心服务的监控看板常驻一个投屏,每天路过瞄一眼,很多隐患就是在这一眼里发现的。
第三个习惯:故障复盘不追责,只追根因。技术架构层面的问题,大多数都不是某个人“操作失误”,而是系统设计本身缺少防御机制。复盘的时候多问“为什么这个操作可以造成这么大的影响”,少问“这是谁干的”。前者能帮你补齐架构短板,后者只会让团队下次把问题藏起来。
写在最后的一个小体会
做了这么多年技术架构相关的工作,我最深的一个体会是:技术架构的好与坏,不是看它用了多少流行的技术,而是看它在团队手里能不能被稳定驾驭。一套再“先进”的架构,如果团队维护起来战战兢兢,那它就是负资产;一套看起来“土气”的方案,如果能稳稳支撑业务两三年,那它就是好架构。
如果你现在正在纠结下一个技术架构决策,我个人建议先把文章里那张约束表列出来,认真填一遍。你会发现,很多纠结其实来自目标不清晰,而不是选项不够多。技术架构这条路没有终点,它不是某个版本的交付物,而是一个需要持续投入、持续治理、持续演进的过程。稳底盘不是一天打成的,但每一次清醒的设计、每一次认真的复盘,都在让这个底盘更厚实一点。