Spring Cloud -3( 9000 字详解 Spring Cloud)
一:Nacos 简介
2018年6月,Eureka 2.0 宣布闭源,但其 1.X 版本仍然是一个活跃的项目。同年 7 月,阿里巴巴的 Nacos 宣布开源,并迅速成为国内最受欢迎的开源产品。作为 Eureka 的替代品,Nacos 已成为国内开发者的首选。
Nacos 不仅是一个注册中心组件,还具备动态服务发现、配置管理和服务管理等多种功能。截至目前,Nacos 几乎支持所有主流编程语言,包括 Java、Go、C++、Node.js、Python 和 Scala 等。
1.1 Nacos 搭建
首先安装并解压 Nacos 的压缩包。
bin 中存放着 Nacos 的启停脚本,conf 存放着 Nacos 的配置文件,target 存放着 Nacos 应用的 jar 包,
- startup.cmd :windows 平台的启动脚本
- shutdown.cmd : windows 平台的停止脚本
- startup.sh :Linux 平台的启动脚本
- shutdown.sh : Linux 平台的停止脚本
Nacos 默认以集群模式启动,如果想要以单机模式运行需要在启动前修改相应的配置。
修改后打开 bin 目录,双击 startup.cmd 就可以启动 Nacos 了。
访问 Nacos 主页面 http://127.0.0.1:8848/nacos ,如果出现以下界面,表示 Nacos 启动成功。
1.2 Nacos 快速上手
Nacos 是 Spring Cloud Alibaba 的组成部分,遵循 Spring Cloud 中定义的服务注册和服务发现规范。因此使用 Nacos 和使用 Eureka 对于微服务的实现并没有太大区别。他们的主要差异在于:Eureka 需要用户自行搭建服务,而 Nacos 则不需用户搭建,组件已经准备好,只需启动即可。此外,两者在依赖和配置上也存在差异。
1.3 服务注册和服务发现
Nacos 的服务注册和服务发现代码是相同的。接下来,我们需要在父工程的 pom.xml 文件中的 dependencyManagement 部分引入 Spring Cloud Alibaba 的依赖:
<properties><spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
</properties><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope>
</dependency>
注意:Spring Boot 和 Spring Cloud 的版本之间存在一定的对应关系,Spring Cloud Alibaba 也遵循这一标准。在引入依赖时,请务必确认各个版本的兼容性。有关 Spring Cloud Alibaba 与 Spring Cloud 的版本对应关系,请参考官方文档:Spring Cloud Alibaba 版本说明。在一定的范围内,版本选择是灵活的,接着我们在 order-service 和 product-service 中引入 nacos 依赖和 Load Balance依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter</artifactId> <!-- 假设该artifactId是你想要的 -->
</dependency>
1.4 配置 Nacos 地址
spring:application:name: product-servicecloud:nacos:discovery:server-addr: 110.41.51.65:10020
1.5 远程调用
- 修改 IP 为项目名
public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);String url = "http://product-service/product/" + orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;
}
- 为 restTemplate 添加负载均衡注解 @LoadBalanced
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
1.6 启动服务
启动两个服务后访问 Nacos 的管理界面,可以看到 order-service 和 product-service 都已成功注册。接下来,可以测试接口 http://127.0.0.1:8080/order/1。
1.7 启动多个服务, 测试负载均衡
启动三个 product-service 服务,并在 Nacos 控制台观察它们的状态。接着,多次访问接口 http://127.0.0.1:8080/order/1,并查看相关日志以监测请求的处理情况。
二:Nacos 负载均衡
生产环境通常较为复杂,因此我们需要对服务的流量进行更加精细的控制。Nacos 支持多种负载均衡策略,包括权重、同机房、同地域和同环境等,以确保服务的稳定性和可靠性。
2.1 服务下线
当某个节点的接口性能较差时,我们可以及时将该节点下线。我们可以先进入服务详情页,选择下线选项。下线后,再次请求接口时,将会发现该服务不再接收请求。若需恢复,该节点可以通过再次单击上线来重新接收请求。
2.2 权重配置
2.2.1 配置权重
找到对应节点,点击编辑,随后在弹出的窗口中将权重值修改。每个节点的默认权重为 1,这里将端口为 9091 的服务的权重调整为 0.1。
2.2.2 开启 Nacos 负载均衡策略
由于 Spring Cloud LoadBalance 组件自身具有负载均衡配置,因此不支持 Nacos 的权重属性配置。为了使权重配置生效,我们需要启用 Nacos 的负载均衡策略。
#开启nacos的负载均衡策略
spring.cloud.loadbalancer.nacos.enabled=truespring:cloud:loadbalancer:nacos:enabled: true
启动服务后,多次访问接口,可以观察到 9091 端口的实例接收到的请求明显少于其他两个实例。整体流量分配是有效的,但局部流量的分配并没有严格按照设置的比例进行。
2.3 同集群优先访问
Nacos 将同一个机房内的实例划分为一个集群,因此它优先访问同集群的实例,这也可以理解为优先访问同机房的实例。在微服务架构中,一个服务通常由多个实例共同提供服务,这些实例可以部署在不同的机器上,并分布在不同的机房。例如,product-service 的实例可能如下:实例1和实例2部署在上海机房,实例3和实例4部署在北京机房。
在微服务访问时,应该优先访问同机房的实例。当本机房内的实例不可用时,才考虑访问其他机房的实例。以 order-service 在上海机房为例,如果 product-service 在北京和上海机房都有实例,我们希望优先访问上海机房的实例;只有在上海机房没有可用实例时,才会访问北京机房的实例。通常情况下,由于同一机房内的机器处于同一局域网,局域网的访问速度会更快一些。
2.3.1 给实例配置集群名称
首先为 product-service 配置集群名称
spring:cloud:nacos:discovery:server-addr: 110.41.51.65:10020cluster-name: SH # 集群名称: 上海集群
重启服务观察 Nacos 控制台,发现 SH 集群下多了⼀个实例
复制 product-service 的启动配置,并添加 VM 选项,设置一个位于 9091 端口的实例,机房为 BJ。同时设置另一个位于 9092 端口的实例,机房也为 BJ。启动后,可以在 Nacos 中观察到 BJ 集群下新增了一个实例。
-Dserver.port=9091 -Dspring.cloud.nacos.discovery.cluster-name=BJ
-Dserver.port=9091 -Dspring.cloud.nacos.discovery.cluster-name=BJ
最后为 order-service 配置集群名称: SH
spring:cloud:nacos:discovery:server-addr: 110.41.51.65:10020cluster-name: SH # 集群名称: 上海集群
2.3.2 开启 Nacos 负载均衡策略
spring:cloud:nacos:discovery:server-addr: 110.41.51.65:10020cluster-name: SH # 集群名称: 上海集群
启动服务后,多次访问接口并观察日志,可以发现只有同集群的 9090 端口的实例接收到了请求。当将 9090 端口的实例下线后,再次访问接口并查看日志,发现 9091 端口和 9092 端口的实例开始接收请求。
三:Nacos 健康检查
3.1 两种健康检查机制
Nacos 作为注册中心,需要感知服务的健康状态,这样才能服务调用方提供可靠的服务,Nacos 提供了两种健康检查机制:
机制 | 描述 |
---|---|
客户端主动上报机制 | 客户端通过心跳上报的方式告知 Nacos 注册中心自身的健康状态,默认心跳间隔为 5 秒。 如果 Nacos 超过 15 秒未收到心跳,将把实例标记为不健康;若超过 30 秒将删除该实例。 |
服务器端反向探测机制 | Nacos 主动探测客户端的健康状态,默认间隔为 20 秒。 健康检查失败后,实例将被标记为不健康,但不会立即删除。 |
3.2 Nacos 服务实例类型
Nacos 的服务实例分为临时实例和非临时实例。临时实例在宕机超过一定时间后会从服务列表中剔除,这是默认类型;而非临时实例则不会被剔除,也称为永久实例。对于临时实例,Nacos 采用客户端主动上报机制来监测其健康状态;而对于非临时实例,则采用服务器端反向探测机制。
可以通过以下配置将一个服务实例设置为永久实例。配置完成后,重启服务并观察 Nacos 控制台。在停止服务后,再次查看控制台的状态可以看到节点不会丢失。
spring:cloud:nacos:discovery:ephemeral: false # 设置为非临时实例
四:Nacos 环境隔离
在企业开发中,一个服务通常会分为开发环境、测试环境和生产环境。开发环境是供开发人员使用的服务器,作为最基础的环境,日志级别一般较低,并可能开启一些调试信息。测试环境则是供测试人员进行测试的服务器,作为开发环境与生产环境之间的过渡。生产环境是正式对外提供服务的环境,通常会关闭调试信息。为了实现这些环境之间的隔离,Nacos 提供了命名空间 namespace 的功能,不同命名空间下的服务彼此不可见,确保环境之间的独立性。
4.1 创建 namespace
默认情况下,所有服务都位于同一个命名空间,称为 public。点击左侧的命名空间选项可以对命名空间进行管理和操作。
接着可以新增命名空间:
4.2 配置 namespace
命名空间创建完成后可以对服务进行配置,下面我们修改 order-service 的命名空间设置。
spring:cloud:nacos:discovery:namespace: 51152a13-7911-49e3-bbdc-16fd5670a257 # 设置命名空间
4.3 测试远程调用
启动服务后,在 Nacos 控制台中可以观察到,public 命名空间下只有 product-service 服务,而 order-service 则位于 dev 命名空间下。
此时如果尝试访问接口进行远程调用会出现错误。此时还需要将 product-service 的一个实例的命名空间修改为 dev。修改完成后,重启服务并再次访问接口 http://127.0.0.1:8080/order/3,发现远程调用成功。
spring:cloud:nacos:discovery:namespace: 51152a13-7911-49e3-bbdc-16fd5670a257 # 设置命名空间
五:Nacos 配置中心
除了作为注册中心和负载均衡工具,Nacos 还是一个配置中心,具备配置管理功能。命名空间的常见应用场景之一是区分和隔离不同环境的配置,例如开发、测试和生产环境之间的配置隔离。
5.1 为什么需要配置中心
当前项目的配置均在代码中管理,这可能导致以下问题:首先,修改配置文件时需要重新部署服务,在微服务架构中,单个服务可能有成百个实例,逐个部署既麻烦又容易出错;其次,在多人开发的情况下,配置文件可能频繁修改,使用同一配置文件容易产生冲突。因此,配置中心可以对这些配置项进行统一管理,使我们能够集中查看、修改和删除配置,而无需逐个修改配置文件,从而提高效率并降低出错的风险。
当服务启动时,会从配置中心读取配置项的内容进行初始化。当配置项被修改时,系统会通知微服务以实现配置的更新和加载。
5.2 快速上手
5.2.1 添加配置
在 Nacos 控制台添加配置项时,需要注意,配置管理的命名空间与服务列表的命名空间是相互隔离的,两者需要单独设置。默认情况下,服务管理的命名空间为 public,因此服务管理的命名空间配置与配置管理的命名空间是不相等的。
然后我们新建配置项,配置内容为 nacos.test.num=5
Data ID 为项目名称,数据格式仅支持 properties 和 yaml 类型。
5.2.2 获取配置
- 首先引入 Nacos Config 依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency><!-- 对于 Spring Cloud 2020.* 及之后的版本,需要引入 bootstrap -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
- 接着配置 bootstrap.properties
在微服务启动之前,需要先从 Nacos 获取配置,并将其与 application.yml 中的配置合并。在微服务运行之前,Nacos 要求必须使用 bootstrap.properties 文件或者使用 bootstrap.yml 文件来配置 Nacos 服务器地址。
spring:application:name: product-servicecloud:nacos:config:server-addr: 110.41.51.65:10020
spring.application.name 必须与 Nacos 配置管理的 Data ID 一致,而 spring.cloud.nacos.config.server-addr 则是 Nacos 服务器的地址。注意:配置中心和注册中心的配置是相互隔离的:Nacos 配置中心使用 spring.cloud.nacos.config.server-addr,Nacos 注册中心则使用 spring.cloud.nacos.discovery.server-addr。
- 编写代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; // NacosController 类用于处理与 Nacos 配置相关的请求
@RequestMapping("/config")
@RefreshScope // 使该类支持动态刷新配置,让配置进⾏热更新
@RestController
public class NacosController {// 从配置中读取 nacos.test.num 的值,默认为 0@Value("${nacos.test.num:0}")private Integer nacosNum;// 处理 GET 请求,返回 nacosNum 的值@RequestMapping("/get") // 定义子请求路径为 /getpublic Integer get() {return nacosNum; // 返回从 Nacos 配置中获取的 nacosNum 的值}
}
最后启动程序后通过访问接口 http://127.0.0.1:9090/config/get 来获取配置项的值。
5.3 设置命名空间
Nacos 配置管理的命名空间和服务列表的命名空间是分别设置的,默认值为 public。Nacos 的命名空间配置仍然在 bootstrap.yml 文件中进行配置。
spring:cloud:nacos:config:namespace: 51152a13-7911-49e3-bbdc-16fd5670a257 # value对应命名空间的ID,
如果设置了命名空间,在项目启动时将从该命名空间下查找对应的配置项。我们现在修改一下配置项的值,接着重新访问接口 http://127.0.0.1:9090/config/get 来观察结果变化。
5.4 Data Id
在 Nacos 中,dataId 的完整格式如下:
${prefix}-${spring.profiles.active}.${file-extension}
配置项 | 默认值 | 说明 |
---|---|---|
prefix | spring.application.name | 默认为 spring.application.name 的值,也可以通过 spring.cloud.nacos.config.prefix 配置。 |
spring.profiles.active | 空 | 当前环境对应的 profile。当 spring.profiles.active 为空时,连接符 - 将不再存在,dataId 的拼接格式变为 ${prefix}.${file-extension}。 |
file-extension | properties | 配置内容的数据格式,当前仅支持 properties 和 yaml 类型,可以通过 spring.cloud.nacos.config.file-extension 配置。 |
微服务启动时, 会从 Nacos 读取多个配置文件:
- ${prefix}-${spring.profiles.active}.${file-extension} 如 product-service-dev.properties
- ${prefix}.${file-extension},如 product-service.properties
- ${prefix} 如 product-service
注意:当使用 ${spring.application.name}、${spring.profiles.active} 等变量时,必须将它们放在 bootstrap.properties 文件中进行配置,三个文件的优先级顺序为:product-service-dev.properties > product-service.properties > product-service。
下面弄一个测试,bootstrap.yml 配置如下:
spring:application:name: product-serviceprofiles:active: devcloud:nacos:config:server-addr: 110.41.51.65:10020namespace: 51152a13-7911-49e3-bbdc-16fd5670a257
访问接口 http://127.0.0.1:9090/config/get ,发现成功获取了 product-service-dev.properties 的配置值。
接着删除 product-service-dev.properties 配置, 再次访问接口
注意事项:
- bootstrap.yml 中的配置格式必须与 Nacos 控制台中配置的数据格式保持一致。
- 如果未设置配置格式 (spring.cloud.nacos.config.file-extension),则默认使用 properties 格式。