最近在写训练营的后端项目,CloudWeGo 官方是在 b 站提供了一个新手教程作为项目的基础功能演示,跟着写下来发现它的架构有些奇特。
前后端架构的演进
-
前后端不分离架构:
- 前端编写静态页面,然后交由后端处理。
- 后端不仅负责数据查询,还要负责最终的页面渲染,整体功能由后端端到端处理。
-
前后端分离架构(单体) :
-
前端负责编写静态页面和界面交互,数据查询通过 JS 调用后端 API。
-
后端接收请求后,会执行参数校验、参数绑定等预处理,再进入业务逻辑层,最后返回响应数据。
-
但这个项目比较特别,是一种前后端半分离的微服务架构:前后端都用 Go 实现,客户端界面采用 Go 的模板渲染,它结合了服务端渲染和分层 API 设计。由于它本身是由 Go 编写,那么它不仅负责编写和渲染页面,还分担了一部分传统后端的职责,比如参数获取、绑定、校验等,让真正后端的微服务可以更专注于业务逻辑的处理。
前后端半分离
特点
- 前端服务的后端化: 前端部分使用 Go 编写,因此它能够像传统后端一样进行参数绑定和校验。这种设计让前端服务承担了部分 API 请求的预处理责任;同时通过前端调用后端微服务的客户端,充当了网关的职责。前端服务在某种程度上就像一个
微型网关 + 微型后端,负责聚合 API 数据、处理请求参数、数据校验并承担网关的服务发现功能。 - 后端微服务专注业务逻辑: 由于前端服务已经完成了参数校验和数据预处理,让后端微服务更加内聚和纯粹,更专注于核心业务逻辑和数据处理。
一条请求的链路大概是这样的:
再看看正常的微服务架构的请求链路:
看起来好像链路变短了,但它的前端服务自身承担了部分 API 请求的逻辑, 对于某些业务可能需要跨服务调取多个数据源时,链路管理难度增加。如果数据源中的一个出了问题,排查会比较复杂,那么就需要引入全面的日志和监控、清晰的错误码以及错误信息;同时可能影响整体页面加载,就还需要在前端实现一定的容错机制,比如超时、重试等策略。
并且由于前端服务还需负责页面渲染,涉及 HTML 输出,这在常规微服务架构中通常是前端职责,而服务端渲染可能会带来更多的状态管理和缓存问题,例如请求用户数据并渲染后,可能需要实现一定的缓存机制以减少多层请求带来的延迟和性能损耗。相比纯粹的 API 请求与响应,这种架构在请求链路上的复杂性更高。
而对于正常的微服务架构来说,链路上的每个节点的职责是单一的、错误处理可以集中在网关层,而不是全部汇集到前端去集中处理。
适用场景
虽然上面提到了这种架构的诸多可能存在的隐患,但它在直接渲染界面上是优于其他架构的,也让它更适合 快速响应、高度集成和 SEO 需求较高的项目,但要确保前端服务的安全性足够高,特别是在缓存管理、敏感数据保护和权限控制方面。
对于直接渲染界面更快的可能原因,有以下几个方面:
-
减少了客户端的请求:
- 使用 “服务端” 渲染时,由于在该部分已经做了多个数据源的整合,那么对于渲染是一次性的事,不需要发出多个请求获取数据逐个渲染
-
前端处理速度快:
- 由于 Go 在并发处理方面优势,相比 JavaScript 的单线程执行,Go 可以在前端快速并行处理多个请求、聚合数据并生成 HTML 界面。这让页面渲染的过程更快更高效,尤其是在高并发环境下,Go 的性能优势更加明显
-
减少渲染延迟:
- 服务端生成的 HTML 是完整的页面结构,浏览器只需渲染成页面,而不必等待 JavaScript 加载、执行和动态更新 DOM。这减少了前端渲染的时间,使用户能更快看到页面内容