上一篇:SpringClound之Nacos简介——让Nacos不再是谜
下一篇:SpringClound之Nacos配置中心——让Nacos不再是谜
注册中心
Nacos可以直接提供注册中心(Eureka)+配置中心(Config),所以它的好处显而易见,我们在前面成功安装和启动了Nacos以后就可以发现Nacos本身就是一个小平台,它要比之前的Eureka更加方便,不需要我们在自己做配置。
服务发现是微服务架构中的关键组件之一。在这样的架构中,手动为每个客户端配置服务列表可能是一项艰巨的任务,并且使得动态扩展极其困难。Nacos Discovery 帮助您自动将您的服务注册到 Nacos 服务器,Nacos 服务器会跟踪服务并动态刷新服务列表。此外,Nacos Discovery 将服务实例的一些元数据,如主机、端口、健康检查 URL、主页等注册到 Nacos。
学习任何知识我们都需要从它的官方文档入手,所以我们直接来看官网给我们提供的文档:https://spring.io/projects/spring-cloud-alibaba#learn
创建父项目
首先创建一个Maven的父项目。用来聚合管理。并声明了SpringCloud和SpringCloudAlibaba的版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hopeful</groupId>
<artifactId>SpringCloudNacosExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringCloudNacosExample</name>
<description>SpringCloudNacosExample</description>
<packaging>pom</packaging>
<!-- 声明版本号 -->
<properties>
<java.version>1.8</java.version>
<maven.complier.source>8</maven.complier.source>
<maven.complier.target>8</maven.complier.target>
<spring-cloud-alibaba-version>2021.1</spring-cloud-alibaba-version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
服务提供者
然后创建一个服务提供者的模块。父项目为上面创建的项目,同样是一个SpringBoot项目。pom.xml中的完整依赖信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hopeful</groupId>
<artifactId>SpringCloudNacosExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.hopeful</groupId>
<artifactId>NacosProvider9001</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>NacosProvider9001</name>
<description>NacosProvider9001</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
注意需要在父项目中标记:
<modules>
<module>NacosProvider9001</module>
</modules>
然后在application.yml
中添加nacos的配置信息
server:
port: 9001
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #单机版注册地址 127.0.0.1:8848/localhost:8848 都可以
management:
endpoint:
web:
exposure:
include:'*'
然后在启动类中添加@EnableDiscoveryClient
注解
@EnableDiscoveryClient
@SpringBootApplication
public class NacosProvider9001Application {
public static void main(String[] args) {
SpringApplication.run(NacosProvider9001Application.class, args);
}
}
然后添加提供的服务接口
@RestController
public class UserController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/hello")
public String getServerPort() {
System.out.println("nacos Provider run....");
return "hello Nacos Provider: " + serverPort;
}
}
启动服务我们就可以在Nacos中服务列表中看到注册的服务信息
服务消费者
同样的我们再创建一个服务消费者的SpringBoot项目(NacosConsumer9101)。并添加相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hopeful</groupId>
<artifactId>SpringCloudNacosExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.hopeful</groupId>
<artifactId>NacosConsumer9101</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>NacosConsumer9101</name>
<description>NacosConsumer9101</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
同样在父项目中记得添加关系
<modules>
<module>NacosProviderExample9001</module>
<module>NacosConsumerExample9101</module>
</modules>
在属性文件中添加对应的application.yml配置信息
server:
port: 9101
spring:
application:
name: nacos-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 服务注册地址 ip地址也可以 如:192.168.2.158:8848
service-url:
nacos-user-service: http://nacos-provider
management:
endpoint:
web:
exposure:
include:'*'
在主启动类中一样添加对应的注解
package com.hopeful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConsumer9101Application {
public static void main(String[] args) {
SpringApplication.run(NacosConsumer9101Application.class, args);
}
}
启动消费服务后一样可以在Nacos服务列表中看到注册的服务信息
服务调用
上面我们创建了服务的提供者和服务的消费者。但是都只是完成了服务的nacos注册。并没有串联起来。在我们使用的SpringCloudAlibaba2021版本中移除了Ribbon
,因为Ribbon
已经停止更新维护了。使用loadBalancer
作用新的负载均衡器。我们需要在消费者NacosConsumer9101项目中添加新的依赖
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
然后配置RestTemplate实现远程调用
package com.hopeful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConsumer9101Application {
public static void main(String[] args) {
SpringApplication.run(NacosConsumer9101Application.class, args);
}
// @LoadBalanced 该注解千万千万不要忘记添加
// 否则启动会提示无法找到nacos-provider 这是巨坑 我爬了好久才上来
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
然后在服务调用的接口中的获取RestTemplate对象。并完成相关的逻辑
package com.hopeful.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* UserController
*
* @author : yl
* @version : [v1.0]
* @createTime : [2024/7/7 21:22]
*/
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverUrl;
@GetMapping("/consumer/hello")
public String helloConsumer() {
System.out.println("helloConsumer...");
System.out.println(serverUrl + "/hello");
return restTemplate.getForObject(serverUrl + "/hello",String.class);
}
}
说明:getForObject方法的参数的含义
第一个参数url表示被调用的目标Rest接口位置
- url的第一部分是在Nacos中注册的服务提供者名称,如果多个服务提供者注册相同名称,Ribbon会自动寻找其中一个服务提供者,并且调用接口方法。这个就是负载均衡功能。
- url后半部是控制器的请求路径。
第二个参数是返回值类型
- JavaBean类型或者JavaBean数组类型,如果控制器返回的是List集合,需要使用数组类型接收。
第三个参数是可变参数
- 是传递给url的动态参数,使用参数时候需要在url上需要使用{1}、{2}、{3}进行参数占位,这样传递的参数就会自动替换占位符。
启动服务后访问测试:http://localhost:9101/consumer/nacos
OpenFeign服务调用
OpenFegin是一个声明式的服务调用组件。本质上是封装的Ribbon实现的。
同样的我们再创建一个服务消费者的SpringBoot项目。并添加相关的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hopeful</groupId>
<artifactId>SpringCloudNacosExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.hopeful</groupId>
<artifactId>NacosConsumerFeign9102</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>NacosConsumerFeign9102</name>
<description>NacosConsumerFeign9102</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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-loadbalancer</artifactId>
</dependency>
<!-- 使用feign进行服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
同样在父项目中记得添加关系
<modules>
<module>NacosProvider9001</module>
<module>NacosConsumer9101</module>
<module>NacosConsumerFeign9102</module>
</modules>
然后在属性文件中添加对应的application.yml配置信息
server:
port: 9102
spring:
application:
name: nacos-consumer-feign
cloud:
nacos:
discovery:
server-addr: 192.168.2.158:8848
management:
endpoint:
web:
exposure:
include:'*'
在主启动类中一样添加对应的注解
package com.hopeful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConsumerFeign9102Application {
public static void main(String[] args) {
SpringApplication.run(NacosConsumerFeign9102Application.class, args);
}
}
启动服务我们就可以在Nacos中服务列表中看到注册的服务信息
然后创建对应的Feign接口
package com.hopeful.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* ProviderService
*
* @author : yl
* @version : [v1.0]
* @createTime : [2024/7/8 20:53]
*/
@FeignClient(name = "nacos-provider")
public interface ProviderService {
@GetMapping("/hello")
public String getServierPort();
}
然后在启动类中添加@EnableFeignClients(basePackages = "com.boge.consumer.feign")
注解。指定我们存放Feign接口的位置
package com.hopeful;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients("com.hopeful.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConsumerFeign9102Application {
public static void main(String[] args) {
SpringApplication.run(NacosConsumerFeign9102Application.class, args);
}
}
然后在controller中通过OpenFeign实现服务的远程调用
package com.hopeful;
import com.hopeful.feign.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* controller
*
* @author : yl
* @version : [v1.0]
* @createTime : [2024/7/8 20:55]
*/
@RestController
public class controller {
@Autowired
private ProviderService providerService;
@GetMapping("/feignConsumer/hello")
public String helloFeignConsumer() {
System.out.println("consumer feign controller...");
return providerService.getServierPort();
}
}
启动服务后访问测试:http://localhost:9102/feignConsumer/hello
注册中心对比
服务注册与发现框架 | CAP模型 | 控制台管理 | 社区活跃度 |
---|---|---|---|
Eureka | AP | 支持 | 低(2.x版本闭源) |
Zookeeper | CP | 不支持 | 中 |
Consul | CP | 支持 | 高 |
Nacos | AP/CP | 支持 | 高 |
CAP模型
计算机专家 埃里克·布鲁尔(Eric Brewer)于 2000 年在 ACM 分布式计算机原理专题讨论会(简称:PODC)中提出的分布式系统设计要考虑的三个核心要素:
- 一致性(Consistency):同一时刻的同一请求的实例返回的结果相同,所有的数据要求具有强一致性(Strong Consistency)
- 可用性(Availability):所有实例的读写请求在一定时间内可以得到正确的响应
- 分区容错性(Partition tolerance):在网络异常(光缆断裂、设备故障、宕机)的情况下,系统仍能提供正常的服务
以上三个特点就是CAP原则(又称CAP定理),但是三个特性不可能同时满足,所以分布式系统设计要考虑的是在满足P(分区容错性)的前提下选择C(一致性)还是A(可用性),即:CP或AP
CP原则
一致性 + 分区容错性原则
CP 原则属于强一致性原则,要求所有节点可以查询的数据随时都要保持一直(同步中的数据不可查询),即:若干个节点形成一个逻辑的共享区域,某一个节点更新的数据都会立即同步到其他数据节点之中,当数据同步完成后才能返回成功的结果,但是在实际的运行过程中网络故障在所难免,如果此时若干个服务节点之间无法通讯时就会出现错误,从而牺牲了以可用性原则(A),例如关系型数据库中的事务。
AP原则
可用性原则 + 分区容错性原则
AP原则属于弱一致性原则,在集群中只要有存活的节点那么所发送来的所有请求都可以得到正确的响应,在进行数据同步处理操作中即便某些节点没有成功的实现数据同步也返回成功,这样就牺牲一致性原则(C 原则)。
使用场景:对于数据的同步一定会发出指令,但是最终的节点是否真的实现了同步,并不保证,可是却可以及时的得到数据更新成功的响应,可以应用在网络环境不是很好的场景中。
Nacos的AP/CP
Nacos无缝支持一些主流的开源生态,同时再阿里进行Nacos设计的时候重复的考虑到了市场化的运作(市面上大多都是以单一的实现形式为主,例如:Zookeeper使用的是 CP、而 Eureka采用的是AP),在Nacos中提供了两种模式的动态切换。
Nacos 何时选择切换模式
一般来说,如果不需要储存服务界别的信息且服务实例通过nacos-client注册,并能够保持心跳上报,那么就可以选择AP模式。如Spring Cloud 和 Dubbo,都适用于AP模式,AP模式为了服务的可用性减弱了一致性,因此AP模式下只支持注册
临时实例
。如果需要在服务级别编辑或者储存配置信息,那么CP是必须的,K8S服务和DNS服务则是用于CP模式。CP模式下则支持注册
持久化实例
,此时则是以Raft协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误。切换命令(默认是AP):
curl -X PUT ‘$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP’
注意:临时和持久化的区别主要在健康检查
失败后的表现,持久化实例健康检查失败后会被标记成不健康,而临时实例会直接从列表中被删除。
上一篇:SpringClound之Nacos简介——让Nacos不再是谜
下一篇:SpringClound之Nacos配置中心——让Nacos不再是谜