第12章:微服务架构(纯小白版)
是Java后端开发领域中非常现代和主流的一个主题。它是在我们之前学习的JUC并发包、中间件等知识之上,进行的一种更宏观的、关于系统“ архитектура(architecture)”设计的探讨。
第四部分:分布式与微服务
第12章:微服务架构
12.1 微服务理论与设计原则
1. 核心概念:微服务是什么?
在了解微服务之前,我们先要明白它所相对的“单体架构”。
第一步:理解“单体架构” (Monolithic Architecture)
好比说:单体架构就像一个巨大的、无所不包的超级商场。
-
在这个商场里,服装部、电器部、餐饮部、电影院等所有功能,都被建设在同一栋大楼里,由同一个管理团队运营。
-
在软件世界里:这意味着你所有的功能代码——用户管理、商品管理、订单管理、支付功能等等——都被打包在同一个Java项目里(比如一个巨大的
.war包)。
第二步:单体架构有什么问题?
当商场规模还很小时,这种模式很简单。但随着业务越来越大,问题就来了:
-
牵一发而动全身:餐饮部的收银机坏了,可能导致整个商场的电路短路,服装部和电影院也得跟着停业整顿。(一个模块的Bug可能导致整个应用崩溃)。
-
开发效率低下:无论你是想给电影院换个灯泡,还是给服装部换个地毯,都需要整个商场停业装修、整体测试、再重新开业。(任何微小的修改都需要对整个项目进行重新编译、测试和部署,非常缓慢)。
-
扩展性差:周末电影院人满为患,你想单独扩建电影院,却发现做不到。你唯一的办法,就是在城市另一边再盖一个一模一样的、包含所有部门的超级商场。(无法对单一功能进行独立扩容)。
第三步:理解“微服务架构”
微服务架构就是为了解决上述问题而生的。
好比说:它不再是建一个超级商场,而是打造一个现代化的“商业广场”。
-
这个广场由许多独立的、小而精的专卖店组成:一家咖啡店、一家电影院、一家书店...
-
在软件世界里:这意味着我们将一个庞大的系统,按照业务边界,拆分成一个个独立的、可以独立开发、独立部署、独立运行的小型服务。例如,“用户服务”、“商品服务”、“订单服务”。
第四步:微服务架构的优点
-
故障隔离:电影院(订单服务)的放映机坏了,完全不影响隔壁的咖啡店(用户服务)和书店(商品服务)正常营业。
-
独立部署与开发:咖啡店的团队可以随时更新菜单、升级咖啡机,而无需通知电影院。小团队可以快速迭代。
-
独立扩展:咖啡店火了,你可以轻松地在广场上再开两家分店,而电影院和书店不受任何影响。
-
技术异构性:咖啡店可以用Java技术栈,电影院可以用Python,书店可以用Go。每个服务都可以选择最适合自己的技术。
第五步:微服务的设计原则(商业广场的运营规则)
-
单一职责:每个专卖店(微服务)只做好一件事。咖啡店就专心做咖啡。
-
去中心化:每个店铺都有自己的“店长”和“员工”(独立的团队),负责自己店铺的一切。数据也一样,每个店铺都有自己独立的“小账本”(独立的数据库)。
-
通过API通信:店铺之间不共享后厨。咖啡店需要书店的书,只能通过打电话(API调用)的方式正式下单,由书店送货上门。
12.2 Spring Cloud & Spring Cloud Alibaba
1. 核心概念:它们是做什么的?
微服务架构虽然优点众多,但也带来了新的复杂问题:
-
这么多专卖店,它们之间如何找到对方的电话号码?(服务发现)
-
顾客来了,应该先去哪个门?如何保证安全?(API网关)
-
如果广场管理处要发布统一的打折活动,如何快速通知到所有店铺?(配置中心)
-
如果一家店铺突然着火了,如何防止火势蔓延到整个广场?(服务熔断)
Spring Cloud 就是为了解决这些微服务治理问题而诞生的一整套“商业广场管理工具集”。而 Spring Cloud Alibaba 则是这个工具集中,由阿里巴巴贡献并开源的一套非常流行、稳定且功能强大的实现方案。
12.2.1 服务注册与发现 (Nacos)
1. 核心问题
在商业广场里,店铺的电话号码(服务的IP和端口)可能会因为装修、搬迁等原因随时变化。订单服务不能把商品服务的电话号码写死在自己的通讯录里。
2. 解决方案:服务注册与发现
好比说:我们需要在广场中心设立一个“问询处 (Information Desk)”。
第一步:Nacos服务
首先,我们在Linux系统上独立部署一个Nacos服务器。这个Nacos,就是我们的“问询处”。
第二步:服务注册
-
过程:每一个专卖店(比如“商品服务”)开门营业时,第一件事就是跑到“问询处”去登记自己的信息:“你好,我是商品服务,我的电话是192.168.1.10:8081”。这个过程就叫服务注册。
-
在代码中:我们只需要在Spring Boot应用中加入Nacos的客户端依赖,它就会在启动时自动把自己注册到Nacos服务器。
第三步:服务发现
-
过程:现在,“订单服务”需要联系“商品服务”。它不会去翻自己的小本子,而是直接去问“问询处”:“你好,请问商品服务的电话是多少?” 问询处会查询登记表,然后把最新的电话号码告诉它。这个过程就叫服务发现。
第四步:健康检查
“问询处”会定期给所有登记过的店铺打电话(发送心跳),确认它们是否还在正常营业。如果一个店铺连续几次电话都打不通,问询处就会认为它已经关门了,就会从登记表上把它划掉,以免把一个无效的电话号码告诉别人。
12.2.2 声明式服务调用 (OpenFeign)
1. 核心问题
“订单服务”通过Nacos拿到了“商品服务”的电话号码后,如何去打这个电话(发起网络请求)呢?传统方式需要自己组装HTTP请求,写很多模板代码,非常繁琐。
2. 解决方案:OpenFeign
OpenFeign让远程服务调用变得像调用本地方法一样简单。
好比说:
-
传统方式:你需要写一封正式的信:“尊敬的商品服务经理,我司现需查询商品信息,商品ID为123,请……”
-
OpenFeign方式:你只需要在Java代码里写一个接口,这个接口看起来就像是你自己的一个普通工具。
第一步:在“订单服务”中定义一个Feign接口
Java
// @FeignClient告诉Spring,这是个远程调用客户端,目标服务名叫"product-service"
@FeignClient(name = "product-service")
public interface ProductClient {
// 这个方法定义看起来和本地方法一模一样
// @GetMapping告诉Feign,这个调用要发一个GET请求到目标服务的 /products/{id} 路径
@GetMapping("/products/{id}")
Product findById(@PathVariable("id") Long id);
}
第二步:在业务代码中直接“注入”并使用
Java
@Service
public class OrderService {
@Autowired
private ProductClient productClient; // 像使用本地工具一样注入
public void createOrder(Long productId) {
// ...
// 直接调用接口方法,就像调用自己项目里的一个普通方法一样!
// Feign会在后台自动帮你完成服务发现、HTTP请求组装、响应解析等所有脏活累活。
Product product = productClient.findById(productId);
// ...
}
}
12.2.3 API网关 (Gateway)
1. 核心问题
商业广场里有几百家店,难道让顾客(前端App或浏览器)自己去记每一家店的具体门牌号吗?而且,难道让每一家店都自己雇一个保安在门口检查顾客的身份吗?这显然不合理。
2. 解决方案:API网关
好比说:API网关就是整个商业广场的“正门入口和安检中心”。
-
统一入口:所有顾客都必须从这个正门进入。前端应用只需要知道网关这一个地址。
-
路由转发:顾客在门口告诉保安:“我要去电影院”。保安(网关)就会根据内部地图,指引顾客走向正确的道路(将请求路由到“订单服务”)。
-
统一鉴权:保安会在门口统一检查所有人的门票(身份认证),没票的直接拦下,无需每家店再自己检查一遍。
-
其他公共服务:比如在门口统计客流量(日志)、防止黄牛反复进出(限流)等。
3. 一步一步看网关如何配置
Spring Cloud Gateway是目前主流的网关实现。它的配置通常在.yml文件中。
YAML
# 在Gateway服务的配置文件中
spring:
cloud:
gateway:
routes:
# 定义第一条路由规则
- id: product_route # 规则的名字
uri: lb://product-service # lb:// 表示从Nacos中找一个叫product-service的服务
predicates:
- Path=/api/products/** # 如果请求路径匹配 /api/products/ 开头...
# 定义第二条路由规则
- id: order_route
uri: lb://order-service
predicates:
- Path=/api/orders/** # ...就把它转发给订单服务
12.2.4 配置中心 (Nacos)
1. 核心问题
商业广场要在国庆节搞统一的“全场8折”促销活动。难道要让管理人员一家一家店铺去口头通知,再由每个店长手动修改自己店里的收银机设置吗?这太低效且容易出错。
2. 解决方案:配置中心
好比说:配置中心就是广场管理处设立的一个“中央广播和电子公告牌”。
第一步:在Nacos中集中管理配置
管理员(开发/运维人员)登录Nacos的管理界面,发布一条新配置:“promotion.discount=0.8”。
第二步:所有服务监听“公告牌”
每一个专卖店(微服务)的收银机系统,在启动时都会连接到这个“中央公告牌”,读取最新的折扣信息。
第三步:配置的动态刷新
最强大的是,当管理员在Nacos上把折扣从0.8改成0.75时,所有连接着的收银机无需重启,就能几乎实时地收到这个更新,并自动应用新的折扣率。
在Spring Boot应用中,我们只需要引入Nacos配置中心的依赖,并在代码中使用@RefreshScope注解,就能实现配置的自动刷新。
12.2.5 服务熔断与限流 (Sentinel)
1. 核心问题:雪崩效应
在微服务架构中,服务之间是互相调用的(订单服务 -> 商品服务 -> 库存服务...)。
问题:如果最下游的“库存服务”因为过载而响应极其缓慢,会发生什么?
-
“商品服务”的所有请求都在苦苦等待“库存服务”的响应,很快“商品服务”自己的资源也被耗尽,跟着卡死。
-
然后,“订单服务”的所有请求都在等待“商品服务”,很快“订单服务”也卡死了。
-
这个故障会像雪崩一样,沿着调用链向上蔓延,最终导致整个系统瘫痪。
2. 解决方案:服务熔断 (Circuit Breaking)
好比说:熔断器就像是你家里的电路保险丝。
-
关闭状态 (Closed):正常情况下,保险丝是通的,电流(服务调用)正常通过。
-
打开状态 (Open):当“库存服务”出现大量超时或失败,Sentinel(保险丝)检测到电流异常增大,就会“跳闸”(熔断),直接切断电路。在接下来的一段时间里,任何流向“库存服务”的请求都会被立即拒绝,并返回一个预设的错误(例如“系统繁忙,请稍后再试”)。
-
半开状态 (Half-Open):过了一小段时间后,保险丝会尝试性地恢复一小点电流。如果这次请求成功了,就恢复正常供电(闭合);如果还是失败,就继续保持跳闸状态。
作用:牺牲非核心服务,保护核心服务。通过快速失败,防止故障蔓延,给了下游服务恢复的时间。
3. 解决方案:服务限流 (Rate Limiting)
-
核心概念:熔断是应对下游服务故障,而限流是应对上游洪峰流量。
-
好比说:限流就像是热门景点门口的保安,或者高速公路收费站的栏杆。
-
作用:你可以为你的服务设置一个QPS(每秒查询率)阈值,比如“每秒最多处理100个请求”。当请求超过这个速率时,Sentinel会直接拒绝多余的请求。
-
目的:保护你自己的服务不被突然涌入的、远超其处理能力的流量冲垮。
更多推荐


所有评论(0)