微服务架构解析:从单体到分布式

如果你已经用 SpringBoot 开发过几个项目,一定会遇到这样的场景:项目越来越大,一个工程里有几十个模块,几百个接口,每次打包要花好几分钟,改一行代码需要重启整个应用。

这就是单体应用走到尽头时的典型症状。

微服务,就是解决这个问题的思路。它不是一门新技术,而是一套架构思想------把一个大而全的系统,拆分成多个小而独立的服务。

这篇文章用最通俗的方式,讲清楚微服务是什么、解决了什么问题、以及带来了哪些新挑战。


一、一个餐厅的比喻

想象你要开一家餐厅。

单体模式

一开始,你一个人包揽所有活:点菜、炒菜、收银、洗碗、端盘子。

这就是单体应用。一个人做所有事,简单直接。

生意越来越好,你忙不过来了。于是你招了厨师、收银员、服务员。但他们还是在一个小店里,共用同一个厨房、同一台收银机。炒菜和洗碗抢水池,点菜和收银挤在一起。

这就是单体应用变大后的样子。看似有了分工,实际上还是耦合在一起,一个人卡住,全店瘫痪。

微服务模式

你把餐厅拆成了独立的"部门":

  • 点菜服务:专门负责接待、点菜

  • 后厨服务:专门负责做菜

  • 收银服务:专门负责结账

  • 洗碗服务:专门负责洗碗

每个部门有自己的小厨房、自己的收银机、自己的服务员。部门之间通过"传菜窗口"和"对讲机"沟通。

这就是微服务。每个服务独立运行、独立部署、独立扩展。生意火爆时,后厨忙不过来就多开几个灶台,点菜慢了就多招几个迎宾,互不影响。


二、什么是微服务

微服务是一种架构风格,把一个大型应用拆分成一组小型的、独立的服务。

每个服务都有这样几个特征:

  • 单一职责:一个服务只做一件事。订单服务只管订单,用户服务只管用户。

  • 独立部署:改订单服务的代码,只需要重启订单服务,其他服务不受影响。

  • 独立数据:每个服务有自己的数据库,不跟别人共用。

  • 技术异构:订单服务用 Java,用户服务用 Go,完全可以。


三、从单体到微服务的演进

第一阶段:单体应用

所有功能写在一个项目里,一个数据库,一个部署包。

优点:开发简单、部署方便、调用快(都在内存里)。

缺点:改一行代码要测整个系统,一个小问题可能让整个应用崩溃,团队协作困难(十几个人改同一个仓库)。

第二阶段:集群单体

还是同一个应用,但部署了三份,前面加一个负载均衡。

优点:提升了并发能力,一台挂了还有别的。

缺点:数据库还是单点,代码还是耦合在一起,改一行代码还是要全部重新部署。

第三阶段:微服务

把大应用拆成小服务:用户服务、订单服务、商品服务、支付服务......

每个服务独立部署,独立数据库,服务之间通过网络调用。

优点:每个服务可以独立开发、独立部署、独立扩展。团队可以各自负责一个服务,互不干扰。

缺点:复杂度飙升。原来在一个进程里调个方法就行的事,现在变成了网络请求。


四、微服务带来的新问题

拆分容易,拆分后怎么管理才是难点。微服务带来了几个必须解决的问题:

4.1 服务发现

以前在单体里,A 调用 B 直接 new 一个对象就行。现在 B 在哪台机器上?IP 是多少?B 挂了吗?B 扩容了怎么办?

解决方案是引入注册中心。所有服务启动时都去注册中心"报到",告诉别人自己叫什么、在哪。调用方去注册中心问"谁叫订单服务",拿到地址后再去调用。Spring Cloud 中的 Eureka、Nacos、Consul 都是干这个活的。

4.2 配置管理

以前配置写在 application.yml 里,每个环境一份。现在几十个服务,每个服务都有配置文件,改一个配置要改几十处。

解决方案是配置中心。所有配置集中管理,服务启动时从配置中心拉取配置,配置变更时还能动态刷新,不用重启服务。

4.3 网关路由

以前前端请求直接打到单体应用。现在几十个服务,前端应该调用谁?总不能把几十个地址都写在前端吧。

解决方案是网关。所有请求先到网关,网关根据请求路径判断应该转发给哪个服务。网关还负责认证、限流、日志等公共功能。

4.4 服务间通信

服务 A 调用服务 B,怎么调?

同步调用常用 HTTP + JSON 或 gRPC。异步调用常用消息队列(RabbitMQ、Kafka)。

同步调用简单直观,但会形成调用链依赖。异步调用解耦更好,但复杂度更高。

4.5 分布式事务

单体里的事务很简单:一个方法里操作多张表,加个 @Transactional 就行。

微服务里,创建订单可能同时要调用订单服务、库存服务、优惠券服务、积分服务。如果库存扣减成功,但积分增加失败,怎么办?

这就是分布式事务问题。没有完美解,常见的方案有:最终一致性(先做完再说,后面慢慢对账)、TCC 事务(Try-Confirm-Cancel)、Saga 模式。

4.6 链路追踪

一个请求可能经过:网关 → 订单服务 → 库存服务 → 优惠券服务 → 用户服务。其中某一个慢了,怎么知道是哪个?

解决方案是链路追踪。每个请求经过每个服务时,都带上同一个 Trace ID,把经过的路径和耗时记录下来。这样就可以清晰看到请求在哪个环节慢了。常见的工具有 SkyWalking、Zipkin、Jaeger。

4.7 熔断与降级

服务 A 调用服务 B,服务 B 挂了怎么办?没有保护的话,服务 A 的线程全卡在等 B 响应,慢慢把 A 也拖垮,然后连锁反应把整个系统拖垮。

解决方案是熔断器。当 B 连续失败达到阈值,熔断器打开,后续请求直接失败,不再调用 B。过一段时间放行几个请求试探,如果 B 好了就关闭熔断器。

降级则是熔断后的兜底方案,比如返回缓存数据、返回默认值、提示稍后重试。


五、微服务与 SpringBoot 的关系

很多人搞不清 SpringBoot 和 Spring Cloud 的区别。

SpringBoot 是快速开发单体应用的框架。它让你能快速写出一个独立运行的 Java 服务。

Spring Cloud 是一套微服务解决方案。它提供了一系列工具,帮你解决上面提到的服务发现、配置管理、网关、熔断等问题。

两者的关系:SpringBoot 用来写每个微服务本身,Spring Cloud 用来把这些微服务组织成一个系统。

打个比方:SpringBoot 是造车的技术,Spring Cloud 是修高速公路、建交通信号灯、设立交桥的技术。你用车可以跑任何路,但有了高速公路和交通系统,多辆车才能高效协同。


六、微服务不是银弹

说了这么多微服务的好处,但它不是万能的。

什么时候不该用微服务:

  • 团队只有三五个人,维护几十个服务会把人累死

  • 业务逻辑简单,用户量不大

  • 项目刚起步,业务方向还不确定

什么时候可以考虑微服务:

  • 团队有几十人,改一个模块要等半天

  • 不同模块的流量差异巨大(有的要扛高并发,有的几乎没流量)

  • 需要多语言开发(不同服务用不同技术栈)

一个务实的建议:先做单体,等痛点出现了再拆分。不要为了微服务而微服务。一个结构清晰的单体,比一个拆得乱七八糟的微服务要好得多。


七、总结

微服务是一种把大系统拆成小服务的架构思想。

维度 单体应用 微服务
部署 一个包 几十个包
扩展 整体扩展 按需扩展
开发 一个仓库 多个仓库
故障影响 整个系统 单个服务
复杂度

微服务解决的问题是"大团队协作、高并发场景下的灵活扩展",但它带来的复杂度也不容忽视。

回到餐厅的比喻:开个煎饼摊子,一个人就够了,没必要搞微服务。开个五星级酒店,有中餐厅、西餐厅、宴会厅、客房服务,那每个部门独立运作、独立管理,就是自然而然的选择。

你的项目处在什么阶段,就选什么架构。没有最好的架构,只有最合适的架构。

相关推荐
小江的记录本2 小时前
【分布式】分布式核心组件——分布式锁:Redis/ZooKeeper/etcd 实现方案(附全方位对比表)、优缺点、Redlock、时钟回拨问题
java·网络·redis·分布式·后端·zookeeper·架构
小江的记录本2 小时前
【分布式】分布式核心组件——分布式ID生成:雪花算法、号段模式、美团Leaf、百度UidGenerator、时钟回拨解决方案
分布式·后端·算法·缓存·性能优化·架构·系统架构
GetcharZp8 小时前
拒绝低效!这款神器,让你的终端效率起飞 | 深度解析 fzf 终极指南
后端
自珍JAVA9 小时前
高效处理Long列表与集合运算:基于RoaringBitmap的工具类解析与应用场景
后端
小码哥_常9 小时前
Spring Boot项目上线秘籍:日志、监控、异常处理全攻略
后端
GreenTea10 小时前
AI 时代,工程师的不可替代性在哪里
前端·人工智能·后端
朦胧之10 小时前
AI 编程开发思维
前端·后端·ai编程
独自归家的兔11 小时前
OCPP 1.6 协议详解:StatusNotification 状态通知指令
开发语言·数据库·spring boot·物联网
希望永不加班11 小时前
Spring AOP 代理模式:CGLIB 与 JDK 动态代理区别
java·开发语言·后端·spring·代理模式