找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4233

积分

0

好友

586

主题
发表于 3 天前 | 查看: 16| 回复: 0

今天,我们来聊聊微服务架构是如何一步一步演变而来的。我会用一个网上超市应用的例子,来说明一个系统是如何从一个简单的单体应用,逐渐演进成复杂的微服务架构,以及在这个过程中会遇到哪些问题、又该如何解决。本文侧重于勾勒微服务架构的全局图景,因此不会深入具体组件的使用细节。

要理解微服务,我们得先看看它的对立面——单体应用。所谓单体应用,就是把所有功能都打包在一个独立的程序单元里。从单体到微服务的转变,并非一蹴而就,而是一个充满挑战的渐进式过程。

微服务架构演进思维导图

01 最初的需求

几年前,小明和小皮创业做网上超市。互联网方兴未艾,网上超市还是蓝海。他们的需求非常简单:

  • 一个对公网开放的网站,用户能浏览商品、下单购买。
  • 一个管理后台,用于管理商品、用户和订单数据。

功能清单整理如下:

网站功能

  • 用户注册、登录
  • 商品展示
  • 下单

管理后台功能

  • 用户管理
  • 商品管理
  • 订单管理

需求简单,小明三下五除二就把网站和管理后台(出于安全考虑分开部署)都开发好了。架构非常清晰:

初期单体架构图

部署上线后,网站运行顺畅,深受用户喜爱。

02 随着业务发展……

好景不长,竞争者纷纷出现。为了应对冲击,团队决定采取一系列营销手段:

  • 开展各类促销活动(如节假日打折、优惠券)。
  • 拓展渠道,开发移动端APP、微信小程序。
  • 利用用户数据进行精准营销。

开发任务紧迫,新成员小红加入,负责数据分析和移动端。由于时间紧张,他们没有好好规划架构,拍脑袋决定:促销管理和数据分析功能塞进管理后台,微信和移动端APP另起炉灶。几天通宵后,新系统上线,架构变成了这样:

业务扩张后的混乱架构

这个阶段的架构存在诸多问题:

  1. 代码重复:网站、移动端有很多相同的业务逻辑代码。
  2. 接口混乱:数据共享方式不一,有时走数据库,有时走接口,调用关系杂乱。
  3. 边界模糊:单个应用为了提供接口,包含了大量非核心逻辑,功能归属混乱。
  4. 性能瓶颈:管理后台加入重逻辑功能后性能下降,影响其他应用。
  5. 数据库压力:所有应用共用一个数据库,表结构难以优化,特别是跑数据分析时,数据库性能急剧下降。
  6. 维护困难:任何小改动都需要全应用发布,常发生在凌晨,测试和验证成本极高。
  7. 团队协作问题:公用功能归属争论不休,容易导致重复建设或无人维护。

尽管问题重重,但这一阶段快速响应了业务变化。不过,紧迫的任务容易让人做出短视的妥协决策。长期如此,系统将越来越难以维护,甚至陷入推倒重来的循环。

03 是时候做出改变了

意识到问题后,小明和小红开始着手改造。改造的前提是,你必须能从业务需求的压力中争取到额外的精力和资源。

改造的核心是抽象。他们梳理业务,抽象出几个公共服务:

  • 用户服务
  • 商品服务
  • 促销服务
  • 订单服务
  • 数据分析服务

各个应用后台只需从这些服务获取数据,自身只保留轻薄的控制层和前端。架构演进如下:

服务拆分初期架构

此时,服务虽然拆分了,但数据库仍是共用的,所以仍然存在单点故障、数据管理混乱、表结构难以调整等问题。

为了彻底解耦,他们一鼓作气,将数据库也拆分了,每个服务负责自己的持久化层。同时,引入消息队列提高系统实时性。架构最终变为:

完全拆分后的微服务架构

完全拆分后,各服务可以采用异构技术,例如数据分析服务用数据仓库,高频访问的服务引入 Redis 等缓存机制。

数据库拆分会带来跨库查询、数据颗粒度等挑战,但可通过设计解决,总体利大于弊。微服务架构还有一个额外好处:使系统分工和责任更加清晰,避免了公共功能在单体架构中无人负责或“能者多劳”式背锅的窘境。这也意味着,微服务改造往往需要团队组织结构的相应调整。

改造完成,一切看似完美。然而……

04 没有银弹

购物节来临,流量暴增,系统突然挂了。在微服务架构下,定位故障点非常困难。小明花了十几分钟,才找到原因是促销服务因请求量过大而宕机,并引发了雪崩效应。

尽管事先做过容量评估,但问题出在商品服务的某个BUG导致对促销服务发起大量无效请求。虽经紧急扩容和修复解决了问题,但损失已造成。

这次故障暴露了微服务架构引入的新问题:

  • 故障定位困难:应用分散,排查需要跨多个服务。
  • 稳定性下降:服务增多,单个服务故障概率增大,且容易引发链式反应。
  • 运维复杂度高:服务数量多,部署、管理工作量激增。
  • 开发和测试变复杂:功能涉及多个服务,协同开发和集成测试难度加大。

小明和小红意识到,必须系统地解决这些问题。故障处理通常从两方面入手:减少故障发生概率,以及降低故障影响。

故障处理策略示意图

05 监控 - 发现故障的征兆

在高并发分布式系统中,故障常如雪崩般瞬间爆发。因此,必须建立完善的监控体系,以期提前发现征兆。

微服务组件众多,监控指标各异(如 Redis 看内存、MySQL 看连接数、业务服务看错误率等)。常见的做法是:

  1. 各组件提供标准化的 metrics 接口。
  2. 部署指标采集器(如 Prometheus)定时拉取并存储数据。
  3. 通过UI(如 Grafana)查询指标、绘制图表、配置告警。

小明采用 Prometheus + Grafana,并利用 RedisExporter、MySQLExporter 及自定义的业务指标接口,搭建了如下监控系统:

微服务监控系统架构图

06 定位问题 - 链路跟踪

单个用户请求在微服务内部可能涉及多次服务调用。链路跟踪就是为了记录每次请求的完整调用链及其关系,方便快速定位问题。

下图展示了一个用户请求的调用链路追踪视图(示例来自Istio):

Zipkin链路跟踪界面截图

可以看到,productpage 服务调用了 detailsreviews,而 reviews 又调用了 ratings。整个链路如同一棵树:

链路跟踪树状结构示意图

实现链路跟踪,需要在每次服务调用的HTTP HEADERS中记录至少四项数据:traceId(链路标识)、spanId(调用节点ID)、parentId(父节点ID)、requestTime & responseTime(请求响应时间)。此外,还需要日志收集存储和展示UI。

链路跟踪基础组件示意图

小明选择了 Zipkin(Google Dapper的开源实现),通过HTTP拦截器注入跟踪数据并异步上报。链路跟踪能定位到出问题的服务,但要查看具体错误,还需要日志分析

07 分析问题 - 日志分析

当应用规模变大,日志文件巨大且分散在多台服务器上时,传统查看方式效率极低。我们需要一个日志 “搜索引擎”

典型的日志分析架构包括日志采集、存储索引和查询展示:

ELK日志分析架构图

小明采用了经典的 ELK 栈:

  • Elasticsearch:搜索引擎,负责日志存储和索引。
  • Logstash:日志采集器,进行预处理后输出到ES。
  • Kibana:UI组件,用于查询和展示数据。

为了避免修改业务代码,小明没有让应用直接调用Logstash,而是在每台服务器上部署一个Agent(如Filebeat)来扫描日志文件并发送给Logstash。

08 网关 - 权限控制,服务治理

服务拆分后,接口数量剧增,调用关系容易混乱。网关 充当了“把关人”的角色,进行统一的权限校验、流量路由,并可以作为API文档平台。

网关的粒度有多种选择:整个系统一个网关(外部访问走网关,内部直连)、所有调用都经网关、或按业务域分区使用。小明根据当前服务数量,采用了最粗粒度的方案:

网关在架构中的位置

09 服务注册与发现 - 动态扩容

冗余是应对故障的常用策略。但服务的实例数量需要随流量动态调整。手动管理这些实例的注册(如更新负载均衡器IP列表)是场噩梦。

服务注册与发现 实现了自动化:

  1. 部署一个服务发现中心(如 ZookeeperEurekaConsulEtcd)。
  2. 服务启动时自动注册自己,并定期从发现中心同步其他服务的地址列表。
  3. 服务发现中心定期做健康检查,剔除不健康实例。

这样,扩容时只需启动新实例,缩容时直接关闭即可。

服务注册与发现流程

服务发现常与客户端负载均衡配合使用。客户端本地有服务地址列表,可以自行决定负载策略,甚至结合服务元数据(版本等)实现A/B测试、蓝绿发布等高级功能。

10 熔断、服务降级、限流

熔断
当调用某个服务多次失败后,应快速熔断,直接返回错误,避免整个链路资源被长时间占用。待该服务恢复后,再重试连接。

熔断器工作原理示意图

服务降级
当下游非核心服务故障时,上游应降级处理,保证核心流程不受影响。例如推荐服务挂了,下单流程应能绕过推荐继续执行。

限流
服务必须具备自我保护能力,即限流。当单位时间内请求过多时,可丢弃多余请求。更精细的做法是分区限流,例如只限制来自异常客户端的流量。

服务间限流示意图

11 测试

微服务下的测试分为三层,形成一个测试金字塔:

微服务测试金字塔

  • 单元测试:最容易实施,效率高,但保证范围有限。
  • 服务测试:针对服务接口测试,难点在于处理服务依赖,可通过 Mock Server 解决。
  • 端到端测试:覆盖全系统,信心最足,但实施费时费力,一般只用于核心流程。

通常,端到端测试失败后,应将其拆解,编写对应的单元测试来覆盖该场景,以便未来能快速捕获同类错误。

Mock Server在测试中的应用

12 微服务框架

指标上报、链路跟踪、服务注册、熔断限流等通用功能,如果每个服务都自己实现,成本太高。基于DRY原则,可以开发一套统一的微服务框架,将这些公共能力沉淀其中。

统一框架能实现深度定制,但带来一个严重问题:框架升级成本极高,需要所有应用服务协同升级,在服务众多时协调非常困难,需要完善的版本和管理规范。

13 另一条路 - Service Mesh

另一种抽象公共逻辑的思路是Sidecar模式。为每个服务实例部署一个轻量级网络代理(Sidecar),所有出入流量都经由它处理,实现服务发现、路由、熔断、观测等功能。

Service Mesh 数据平面

Sidecar只负责网络通信(数据平面),还需要一个控制平面来统一管理和下发所有Sidecar的配置。数据平面与控制平面共同构成了 Service Mesh

Service Mesh 控制平面与数据平面

Service Mesh 的优势在于对业务代码无侵入,升级和维护更便捷。代价是引入额外的资源开销(内存拷贝)和可能存在的性能损耗。

14 结束,也是开始

微服务架构的演进远未结束。一方面,技术向着更细粒度的 ServerlessFaaS 方向发展;另一方面,业界也在反思微服务的复杂度,出现了“分久必合”的思潮,重新审视经过现代化改造的单体架构的适用场景。

技术的选择没有银弹,只有是否适合当下的业务规模、团队能力和运维体系。无论是微服务、单体,还是 Service Mesh,其核心目标始终是构建稳定、高效、可维护的软件系统。如果你想深入了解这些话题,欢迎到 云栈社区 与更多开发者一起交流探讨。




上一篇:微服务架构设计深度解析:从面试到实战的完整指南
下一篇:Docker核心原理深度剖析:架构、工作流程与传统虚拟化对比
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-10 11:39 , Processed in 0.545234 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表