ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Web架构选型:单体分层与前后端分离为何仍是主流

Web架构选型:单体分层与前后端分离为何仍是主流 做Web开发这些年我经常被问到同一个问题现在最流行的架构是不是微服务是不是不上K8s就不够现代每次我都要花挺长时间解释——真正被最多团队、最多产品、最多业务方使用着的Web应用架构往往不是那套宣传稿里闪闪发光的东西而是那套看起来有点“土”、但极其皮实耐用的方案。这个认知不是我从文档里读出来的是在一个个真实项目的验收、重构、救火和交接里攒出来的。这篇内容我想基于“使用最广泛的Web应用架构”这个命题把那些真正跑在生产线上的架构形态拆开讲清楚它们为什么能成为主流选型时该看哪些硬指标以及那些教程里不会明说的权衡和代价。适合刚入行的新人建立全局观也适合已经写了几年业务代码、想搞清楚“我们这套系统到底属于什么架构”的同学。1. 最广泛使用的架构往往是你“瞧不上”的那一种很多人对架构有个误解觉得架构就等于微服务、等于高并发、等于复杂的分布式系统。但实际上“使用最广泛”和“技术上最先进”是两个完全不同的概念。一个架构被广泛使用通常是因为它在绝大多数普通场景下都能稳定工作、成本可控、团队容易上手而不是因为它能扛住双十一的峰值流量。1.1 为什么“最广泛”不等于“最先进”技术扩散的规律往往是滞后的。一个新架构从提出到成熟到被主流团队接受再到成为行业默认通常需要五到十年。这期间大量存量系统还在用老架构稳定运行着。你可以去翻一翻身边能接触到的业务系统——企业内部的管理后台、中小公司的官网和CRM、传统行业的订单系统、甚至不少日活几百万的产品——它们的骨架大概率不是你想象中那种服务满天飞的形态而是一个部署单元搞定大部分事情的单体应用。我见过不少团队在技术选型时踩进同一个坑业务规模明明就是一个中等复杂度的管理系统非要拆成十几个微服务最后服务之间互相调用的链路比业务逻辑本身还复杂。这不是架构先进这是给自己制造工作量。真正负责任的做法是先认清自己的业务量级和目标再决定要不要为那些“先进”付出额外的运维和学习成本。1.2 单体分层架构的真实分布从全球范围看一直到今天单体应用Monolith加分层设计依然是部署数量最多、使用范围最广的Web应用形态。Java领域有Spring Boot搭出来的经典分层工程Python领域有Django或Flask驱动的内容型应用PHP领域有Laravel、ThinkPHP支撑的大量站点甚至Node.js生态里也有Express、NestJS构建的完整业务系统。这些技术栈五花八门但架构骨架高度相似一个进程同时处理HTTP请求、业务规则、数据读写和页面渲染。这种架构能够长期占据主导原因很朴素它符合大多数业务团队的组织方式。一个小团队三五个人一个应用仓库一条部署流水线出了问题从入口到数据库逐层排查链路短、定位快、上下文容易保持。对于“把业务需求稳定地变成线上功能”这个核心目标来说单体分层架构是路径最短、意外最少的选择。2. 分层架构Web应用地基中的绝对主力如果给“使用最广泛的Web应用架构”一个更具体的画像那就是三层或多层单体架构。它几乎是所有后端开发者的第一课也是无数生产系统的真实骨架。理解它比追着新架构跑更有长期价值。2.1 三层架构的边界到底切在哪标准的三层划分是表现层Controller、业务逻辑层Service、数据访问层Repository/Mapper。表现层负责接收用户请求、校验基础参数、把响应转换成合适的格式业务逻辑层负责处理业务规则、事务边界、状态流转数据访问层负责与数据库打交道执行查询和持久化。我衡量一个团队的分层是否健康有个很实用的标准随机打开一个请求的调用链看它是不是按“Controller → Service → Repository”的顺序稳定地往下走有没有出现跳过Service直接在Controller里写SQL、或者在Repository里堆业务判断的情况。凡是频繁出现越层的代码大概率已经开始腐烂了。以Spring Boot项目为例一个典型的企业级工程目录会是这样com.company.project ├── controller // 表现层接收请求、参数校验、响应封装 ├── service // 业务层事务、规则、编排 ├── repository // 数据层数据库操作 ├── entity // 数据实体映射 └── config // 配置与基础设施这个结构看起来简单但每层都有它的职责红线。守住这条线项目维护起来会舒服很多守不住改一个需求可能要从数据库一路改到接口层牵扯面越来越大。2.2 控制层为什么必须“瘦”业务逻辑不该放这里我在Code Review里最常见的毛病之一就是Controller里塞业务逻辑。有人觉得这样写起来省事一个方法从头写到尾不用来回跳文件。但代价是同样的业务规则无法被复用、单元测试难以编写、事务边界十分模糊。我曾经接手过一个老项目一个订单接口的Controller方法里有六百多行代码中间还嵌了三次数据库操作。那不是一个“控制层”那是一个违章建筑。控制层应该只做三件事取参数、调Service、封装返回。任何涉及判断、计算、数据变更的东西都应该下沉到Service层。这不仅是职责清晰的问题还直接关系到事务控制。Spring的声明式事务是基于代理机制实现的只有跨过Service层的方法调用事务注解才能生效。如果你在Controller里直接调用Repository事务要么失效要么边界错乱数据一致性就埋雷了。2.3 数据访问层的两个流派ORM与手写SQL数据访问层的实现方式大体上分成两派一类是偏ORM的比如Hibernate、JPA、Django ORM让开发者用对象操作替代SQL另一类是偏SQL控制的比如MyBatis、JOOQ把SQL写在自己的掌控范围内。这两个流派都有海量生产实践谈不上谁取代谁关键是匹配团队习惯。如果团队里大部分人对SQL不敏感、业务以标准CRUD为主用JPA这类全自动ORM能大幅提升效率如果业务涉及大量复杂查询、报表统计、多表关联我建议用偏SQL控制的方案因为复杂的动态SQL靠ORM拼接反而更痛苦而且生成的SQL执行计划未必最优。没有最好的框架只有最不容易出错的组织方式。提示数据访问层还有个被低估的细节——连接池和事务时间。很多系统瓶颈不在业务代码而是连接池参数没调、事务范围包了太多无关操作。一个事务方法里尽量只做与本次数据变更强相关的操作别把外部调用、消息发送、文件处理都塞进同一个事务里。3. 前后端分离当前谈论技术栈时默认的前提如果说分层架构是Web应用的地基那么前后端分离就是最近这七八年里普及程度最高的架构形态。现在你问十个人你们项目前端的形态是什么至少九个会说是SPA单页应用或者独立前端工程和传统JSP、服务端模板渲染那一代相比这已经是默认选项了。3.1 为什么分离成为主流从渲染职责到团队协作前后端分离不是某个人拍脑袋设计的而是被逼出来的。早期Web开发中页面是后端渲染的一个HTML页面里的数据占位和业务逻辑耦合在一起前端改了样式后端可能要重新部署后端改了数据结构前端页面可能直接崩掉。两边的工作互相牵制发布节奏被绑死。分离之后前端负责页面结构、交互和调用接口后端只负责提供数据接口和处理业务。两者通过HTTP/JSON通信各自的发布周期不再互相阻塞。前端团队可以专心打磨交互体验后端团队可以专心稳定接口服务。对一个公司来说这不仅仅是技术变化还是组织协作方式的重新分工——配合得好迭代速度能明显上一个台阶。3.2 接口设计决定前后端协作质量分离架构下前后端唯一的契约就是接口。接口设计得好不好直接决定了协作是顺滑还是灾难。我总结了几个吃过亏之后的硬性要求版本管理接口从上线第一天就要有版本意识。路径里带版本号如/api/v1/orders或者至少保证兼容性策略明确。不要等到调用方多了之后再提“我要改字段名”。统一响应结构一个项目中定义统一的响应包装包含业务状态码、消息、数据体和请求追踪ID。否则每个接口返回结构都不一样前端要写一堆适配逻辑。错误信息要有可读性直接抛一堆异常堆栈给前端没有任何意义。对用户可读的错误码、对开发者有用的提示两者都要有。另外还有个容易忽略的点接口文档的维护。现在用OpenAPISwagger规范把接口定义管理起来已经很成熟生成文档、生成客户端SDK都方便。谁要是还在靠口头沟通“接口返回再加个字段”那项目迟早要出乱子。3.3 Session、JWT与权限校验在分离架构下的取舍前后端分离之后最容易被讨论的细节就是用户状态怎么存。传统单体应用里用Session很自然服务端存一个会话浏览器带一个Cookie。但当前端是独立部署的SPA、或者还有App端的时候基于Cookie的Session方案就不那么方便了。于是JWTJSON Web Token成了这个场景下的主流选择。服务端签发一个自包含的Token前端拿到之后放在Authorization头里每次请求带上。服务的节点不依赖共享会话存储水平扩展更轻松。但JWT不是没有代价Token一旦签发在过期之前很难主动吊销。如果用户改了密码、被封禁、或者权限被调整老的Token在过期之前依然可能有效。我的建议是对大多数业务系统来说不要把Session和JWT做成非此即彼的选择题。中小型单体应用用Session往往更省事服务端可以随时让一个会话失效需要跨端、跨域共享登录态的场景用JWT但一定要设置合理的过期时间并配合刷新机制和必要时拉黑名单的方案。每个方案都有它最合适的土壤硬套反而会把自己绊倒。提示不管用哪种方案对用户密码的处理都必须做哈希加盐不要用明文或者弱哈希。登录接口一定要有防暴力破解的手段比如限流和失败次数锁定。这属于Web安全里的基本功但现实中很多接口就是这么裸奔着上线的。4. 单体、分布式与微服务从“广泛”到“热门”的断层聊到这一步很多人会追问那微服务呢它是不是现在“最广泛”的架构答案要看你怎么定义“广泛”。从社区热度、招聘要求、技术文章数量来看微服务确实是当红话题但从实际部署的业务系统数量来看它远没有达到“最广泛”的程度。这里有个明显的断层。4.1 单体架构被低估的地方大厂的“大单体”很多大厂内部的核心系统表面上是微服务实际上是一个个“大单体”在承担核心链路。这不是我乱说而是分布式改造过程中一个真实的中间态服务拆分没那么彻底某些核心模块仍然作为一个大进程运行独立部署、独立伸缩。这种状态持续很久甚至长期是常态。单体架构被低估的原因在于它可以用最简单的方式保证强一致性和事务完整性。一个本地数据库事务、一段同步的业务流程不需要处理分布式事务、不需要补偿机制、不需要最终一致性的各种脑力劳动。对绝大多数业务来说这恰恰是最稳妥的。维护一个几万行的单体应用比维护一个拆成二十个服务的分布式系统简单得多——只要团队纪律良好、分层清晰、模块边界维持得住。4.2 微服务的真实成本团队、运维与认知负荷微服务的成本经常被低估。拆服务很容易写一份拆分方案很快但拆完之后要面对的是服务间调用变成网络通信需要考虑超时、重试、熔断、降级分布式事务从“不用想”变成“必须想”要引入事务消息、Saga、或者接受最终一致性发布和回滚从“一条流水线”变成“几十条流水线”上线窗口从半小时变成半天排查问题从“看一个系统日志”变成“从调用链里拼接多个服务日志”。这些成本在团队只有二三十人、业务复杂度并不爆炸的时候往往是净负担。我以前见过一个团队为了微服务而微服务每个服务就两三个接口光维护服务间的认证、配置中心和部署脚本就花了大量时间回头业务迭代的节奏反而慢了。微服务是解决组织复杂度和扩展性问题的工具不是解决所有问题的银弹。4.3 演进式架构比一步到位更现实针对这个话题我一直向团队传递的理念是架构应该演进而不是一步到位。先以单体分层架构把业务跑通、把市场验证了当出现真实的性能瓶颈、独立的伸缩需求、或团队规模扩大到必须独立发布某个模块时再对那一小块领域进行服务化拆分。这不是保守是基于成本的理性选择。实际落地时可以先把单体内部的模块边界划清楚——比如订单模块、用户模块、商品模块在代码层面分开、数据库层面解耦但暂时还是部署在一起。这样既享受了单体运维简单的红利又给未来拆分留好了切口。等到要拆的时候切一个模块出去远比从一盘乱麻里硬拉一条线出来容易得多。5. 架构选型不靠感觉一套可落地的判断框架讲了这么多最后落到实操如果你现在正在做一个新项目或者准备重构一个老系统到底该怎么选架构我提供一个自己反复使用、也验证过多次的判断框架。5.1 团队规模与技术栈熟悉度优先选架构第一个要考虑的不是“什么最流行”而是“团队现有的人能不能驾驭”。一个只有三个后端开发、以前全写Django的团队突然上一个Spring Cloud全家桶光学习成本和运维踩坑就能拖垮迭代节奏。反过来一个全是Java老兵、熟悉Spring生态的团队用Java技术栈搭分层单体就是最顺手的。架构的复杂度必须和团队规模匹配三五个人一个单体应用加一个数据库就能撑起很多业务十几个人的研发团队可以考虑前后端分离加上清晰的分层模块几十个人、多条业务线并行的规模才值得去设计服务化治理方案。5.2 业务复杂度与部署调性第二个维度是业务本身的形态。内容型产品、营销活动页、管理后台这类以CRUD和展示为主的场景单体分层加成熟的Web框架就是最优解。业务流程强、状态多、外部系统集成多的场景设计上要重点考虑领域模型的边界和事件机制。部署调性同样重要。如果客户需要私有化部署、需要在离线环境运行、需要一双皮鞋就能运维那单体应用的优势极其明显——打一个包、部署到一个目录、启动一个进程就完事了。微服务在这种场景下就是给自己上刑光编排那一堆服务就够运维喝一壶的。5.3 从运维角度反推架构选择我建议你在选型时做一道反向题想象一下线上出了故障你这个架构下最快多久能定位并恢复单体应用通常是看日志、查接口、回滚版本链路明确微服务则要看链路追踪、逐层排查依赖关系、可能要回滚多个服务。很多团队在选型时只想着功能实现把运维难度放到了一边真到半夜被叫起来处理故障时才后悔。因此我会把“可运维性”作为一个和功能、性能同等重要的架构指标。一个新架构引入之前先问问监控、日志、告警、备份恢复、版本回滚这五件事它能不能做到和现有架构同等水平如果答案是“先上线再说”那这个选型风险就很高。综合来看我的结论一直很稳定对大多数团队、大多数业务、大多数阶段来说单体分层架构配合成熟Web框架就是最广泛也最合理的选择。前后端分离是当前的主流形态分层设计是永不过时的基本功微服务则是工具而非目标。先把地基打稳再去追逐那些听起来很酷的东西这既是对业务负责也是对自己负责。最后分享一个我坚持了很多年的习惯每次接手一个新系统我不会急着看它用了什么高级组件而是先摸清它的分层是否清晰、模块边界是否合理、依赖方向是否统一。这三件事没问题这个架构就算朴素也能扛得住业务快速变化的冲击这三件事乱了再花哨的架构图谱也救不了它。架构的真相从来不在概念里就在每一行代码和每一次发布的选择里。
返回列表