Nacos
Nacos 基础
官网
https://github.com/alibaba/Nacos
Nacos 是什么
一句话:Nacos 就是注册中心[替代 Eureka]+配置中心[替代 Config]
Nacos:Dynamic Naming and Configuration Service
架构理论基础: CAP 理论 (支持 AP 和 CP, 可以切换)
Nacos 下载&运行
下载: https://github.com/alibaba/nacos/releases/tag/1.2.1
环境要求: Java8/Maven 3.2.x+
运行 bin/startup.cmd
浏览器输入**http://localhost:8848/nacos**
用户名/密码 为 nacos
,登录进去

创建 Nacos 服务提供者
需求说明/图解

创建 member-service-nacos-provider-10004 并注册到 NacosServer8848
创建 member-service-nacos-provider-10004
- 参考member-service-provider-10001 来创建 member-service-nacos-provider-10004 即 可
- 创建好后 , 使用 member-service-provider-10001 的源码和配置替换 member-service-nacos-provider-10004 生成的代码
- 提醒,拷贝时不要忘记拷贝 resources/mapper/MemberMapper.xml 这些 xxx.xml 文 件
- 修改本模块 pom.xml, 加入
spring-cloud-alibaba
依赖
<!--引入相关的依赖-->
<dependencies>
<!--引入nacos-starter nacos的场景启动starter-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--引入mybatis-starter 整合到springboot-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--引入druid-starter-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<!--这里需要我们指定版本, 因为父项目没有-->
<version>1.1.17</version>
</dependency>
<!--引入mysql依赖,使用版本仲裁-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--spring-boot-start-jdbc引入-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入test-starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--引入公共模块e_commerce_center-common-api-->
<dependency>
<groupId>com.lzw</groupId>
<artifactId>e_commerce_center-common-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
创建 application.yml
server:
port: 10004
spring:
application:
name: member-service-nacos-provider #配置应用的名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
# 配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置nacos Server的地址
# 配置暴露所有的监控点
management:
endpoints:
web:
exposure:
include: '*'
mybatis:
mapper-locations: classpath:mapper/*.xml # 指定mapper.xml文件配置
type-aliases-package: com.lzw.springcloud.entity # 实体类所在包,这样通过类名就可以引用
创建主启动类
package com.lzw.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author LiAng
*/
//@EnableDiscoveryClient 引入的是Nacos发现注解
@EnableDiscoveryClient
@SpringBootApplication
public class MemberNacosApplication10004 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosApplication10004.class, args);
}
}
为看到更好提示,修改 Controller
package com.lzw.springcloud.controller;
import com.lzw.springcloud.entity.Member;
import com.lzw.springcloud.entity.Result;
import com.lzw.springcloud.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
/**
* @author LiAng
*/
@Slf4j
@RestController
public class MemberController {
//装配MemberService
@Resource
private MemberService memberService;
@PostMapping("/member/save")
public Result save(@RequestBody Member member) {
log.info("service-provider member={}",member);
int affected = memberService.save(member);
if (affected > 0) { //说明添加成功
return Result.success("添加会员成功 member-service-nacos-provider-10004", affected);
} else {
return Result.error("401", "添加会员失败");
}
}
//查询的方法/接口
//使用url占位符+@PathVariable
@GetMapping("/member/get/{id}")
public Result getMemberById(@PathVariable("id") Long id, HttpServletRequest request) {
Member member = memberService.queryMemberById(id);
//使用Result把查询到的结果返回
if (member != null) {
return Result.success("查询会员成功 member-service-nacos-provider-10004" , member);
} else {
return Result.error("402","ID= " + id + "不存在");
}
}
}
测试
启动 Nacos Server 8848
启动 member-service-nacos-provider-10004
观察 nacos 服务是否注册成功

浏览器: http://localhost:10004/member/get/1

创建 member-service-nacos-provider-10006 并注册到 NacosServer8848
创建 member-service-nacos-provider-10006
- 参考 member-service-nacos-provider-10004 来创建 member-service-nacos-provider-10006 即可
- 创建好后,使用 member-service-nacos-provider-10004 的源码和配置替换 member-service-nacos-provider-10006 生成的代码
- 提醒,拷贝时不要忘记拷贝 resources/mapper/MemberMapper.xml 这些 xxx.xml 文件
- 从10004复制pom.xml中的依赖
- 修改 application.yml 中的 port
- 修改主启动类的名称和Controller中的信息提示
测试

浏览器: http://localhost:10006/member/get/1

创建 Nacos 的服务消费者
创建 member-service-nacos-consumer-80 并注册到 NacosServer8848
创建 member-service-nacos-consumer-80
参考 member-service-consumer-80 来创建 member-service-nacos-consumer-80 即可
修改 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>e-commerce-center</artifactId>
<groupId>com.lzw</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>member-service-nacos-consumer-80</artifactId>
<!--引入相关的依赖: 我们引入了当前需要的依赖,后面如果有其它需要,再灵活调整-->
<dependencies>
<!--引入sentinel 和 nacos持久化整合依赖,使用版本仲裁-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--引入 sentinel starter 即 场景启动器starter-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--引入openfeign starter 即场景启动器starter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--引入alibaba-nacos 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--引入web-starter 老师说明我们使用版本仲裁(从父项目继承了版本)
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入e_commerce_center-common-api-->
<dependency>
<groupId>com.lzw</groupId>
<artifactId>e_commerce_center-common-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
创建 application.yml
server:
port: 80
spring:
application:
name: member-service-nacos-consumer-80
# 配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos server的地址
创建主启动类
package com.lzw.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author LiAng
*/
@SpringBootApplication
@EnableDiscoveryClient //引入的是启动 nacos发现注解
public class MemberNacosConsumerApplication80 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosConsumerApplication80.class, args);
}
}
业务类
创建配置类 com/lzw/springcloud/config/CustomizationBean.java
package com.lzw.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author LiAng
* CustomizationBean: 配置类
* 配置注入 RestTemplate
*/
@Configuration
public class CustomizationBean {
//配置注入RestTemplate bean/对象
//这里的@LoadBalanced 就是 赋予 RestTemplate 负载均衡的能力
//默认是使用轮询算法来访问远程调用接口/地址
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
创建 com/lzw/springcloud/controller/MemberNacosConsumerController.java
package com.lzw.springcloud.controller;
import com.lzw.springcloud.entity.Member;
import com.lzw.springcloud.entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author LiAng
*/
@RestController
@Slf4j
public class MemberNacosConsumerController {
//http://member-service-nacos-provider 就是服务注册到Nacos server的服务名,这里是小写
public static final String MEMBER_SERVICE_NACOS_PROVIDER_URL =
"http://member-service-nacos-provider";
//配置RestTemplate
@Resource
private RestTemplate restTemplate;
//方法1/接口. 添加member
@PostMapping("/member/nacos/consumer/save")
public Result<Member> save(Member member) {
return restTemplate.postForObject(MEMBER_SERVICE_NACOS_PROVIDER_URL
+ "/member/save", member, Result.class);
}
//方法2/接口, 查询member
@GetMapping("/member/nacos/consumer/get/{id}")
public Result<Member> getMemberById(@PathVariable("id") Long id) {
return restTemplate.getForObject(
MEMBER_SERVICE_NACOS_PROVIDER_URL + "/member/get/" + id, Result.class);
}
}
测试
启动 Nacos Server 8848
启动 member-service-nacos-provider-10004/10006
启动 member-service-nacos-consumer-80
浏览器: http://localhost/member/nacos/consumer/get/1
默认是轮询调用
配置自己的负载均衡算法, 测试完毕恢复成原来的轮询算法
package com.lzw.springcloud.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
/**
* @author LiAng
* RibbonRule: 配置类:配置注入自己的负载均衡算法
*/
public class RibbonRule {
@Bean
public IRule myRibbonRule(){
//这里返回的是RandomRule
return new RandomRule();
}
}
Nacos AP 和 CP 切换-理论
各种注册中心对比

选择 AP 还是 CP?
1、CP: 服务可以不能用,但必须要保证数据的一致性。
2、AP: 数据可以短暂不一致,但最终是需要一致的,无论如何都要保证服务的可用。
3、取舍:只能在 CP 和 AP 选择一个平衡点, 大多数都是选择 AP 模式
AP 和 CP 切换
- Nacos 集群默认支持的是CAP原则中的AP原则,但是也可切换为CP原则(一般不切换)
- CURL切换命令:
curl -X PUT
$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP
- URL指令:
$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP
参考: https://www.jianshu.com/p/c56e22c222bb
Nacos 配置中心实例
需求分析/图解

在 Nacos Server 加入配置
进入到 Nacos Server
加入配置, 文件后缀.yaml
别忘了


点击发布
创建 Nacos 配置客户端模块 e-commerce-nacos-config-client5000
先创建 e-commerce-nacos-config-client5000 模块,参考以前的方法
修改 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>e-commerce-center</artifactId>
<groupId>com.lzw</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>e-commerce-nacos-config-client5000</artifactId>
<!--引入相关的依赖: 我们引入了当前需要的依赖,后面如果有其它需要,再灵活调整-->
<dependencies>
<!--加入nacos-config stater 即场景启动器 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--引入alibaba-nacos 使用版本仲裁-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--引入web-starter 说明我们使用版本仲裁(从父项目继承了版本)
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入e_commerce_center-common-api-->
<dependency>
<groupId>com.lzw</groupId>
<artifactId>e_commerce_center-common-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
创建 application.xml
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
参考: https://blog.csdn.net/zsl131557/article/details/80886114
创建 bootstrap.yml
server:
port: 5000
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id(e-commerce-nacos-config-client-dev)
name: e-commerce-nacos-config-client
# 配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
#1. nacos 配置客户端/当前的微服务模块, 会根据配置,找到配置中心的数据(配置文件)
#2. config.server-addr: localhost:8848 可以找到配置中心
#3. spring.application.name 对应是DataId e-commerce-nacos-config
#4. 在application.yml: 配置 spring.profiles.active dev
#5. spring.cloud.nacos.config.file-extension 配置文件的扩展名 .yaml
#6. 小结: 根据配置 就是 到 localhost:8848 下的 e-commerce-nacos-config-dev.yaml
# 获取配置信息/数据
#7. 规则就是: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 来定位配置中心的 Data ID
主启动类
package com.lzw.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
/**
* @author LiAng
*/
@SpringBootApplication
@EnableDiscoveryClient
@RefreshScope //@RefreshScope 是 springcloud 的原生注解,实现配置信息自动刷新
public class NacosConfigClientApplication5000 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientApplication5000.class, args);
}
}
业务类
package com.lzw.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author LiAng
*/
@RestController
@Slf4j
public class NacosConfigClientController {
/**
* 1. client 会拉取nacos server 的 e-commerce-nacos-config-client-dev.yaml
* config:
* ip: "122.22.22.22"
* name: "liang"
* 2. @Value("${config.ip}") 会将 config.ip 赋给 configIp
* 3. 这里${config.ip} 不能乱写,要有依据
*/
@Value("${config.ip}")
private String configIp;
@Value("${config.name}")
private String configName;
@GetMapping("/nacos/config/ip")
public String getConfigIp(){
return configIp;
}
@GetMapping("/nacos/config/name")
public String getConfigName(){
return configName;
}
}
测试
启动 Nacos Server
启动 e-commerce-nacos-config-client5000
浏览器:http://localhost:5000/nacos/config/ip

注意事项和细节
NacosConfigClientController.java 的 @Value("${config.ip}")
, 是 import org.springframework.beans.factory.annotation.Value;
而不是 lombok 包下的
- 配置文件 application.yml 和 bootstrap.yml 结合会得到配置文件/资源的地址
- 参考文档: https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

- 注意在 Nacos Server 的配置文件的后缀是
.yaml
, 而不是.yml
- 在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动, 也就是说如果项目不能正确的获取到 Nacos Server 的配置数据,项目是启动不了的
- springboot 中配置文件的加载是存在优先级顺序的,bootstrap.yml 优先级高于 application.yml
@RefreshScope
是 springcloud 原生注解,实现配置信息自动刷新, 如果在 Nacos Server 修改了配置数据,Client 端就会得到最新配置
@RefreshScope
public class NacosConfigClientController {
...
}
Nacos 分类配置 (实现配置隔离)
DataID 方案
需求分析

配置实现
在 nacos server 创建新的配置:e-commerce-nacos-config-client-test.yaml

修改 application.yml
spring:
profiles:
active: test #指定环境,常见的环境有 dev开发/test测试/prod生产
测试
浏览器: http://localhost:5000/nacos/config/ip

Group 方案
需求分析

配置实现
在 nacos server 创建新的配置:order/e-commerce-nacos-config-client-dev.yaml

在 nacos server 创建新的配置:seckill/e-commerce-nacos-config-client-dev.yaml


修改 application.yml
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
修改 bootstrap.yml
增加 group
server:
port: 5000
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id(e-commerce-nacos-config-client-dev)
name: e-commerce-nacos-config-client
# 配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
group: order #指定order组,默认是DEFAULT_GROUP
测试

Namespace 方案
需求分析

配置实现
在 nacos server 创建新的 namespace , baidu 和 alibaba



在 nacos server 创建新的 group/dataid




修改 application.yml
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
修改 bootstrap.yml
增加 Namespace 参数
server:
port: 5000
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id(e-commerce-nacos-config-client-dev)
name: e-commerce-nacos-config-client
# 配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
group: seckill #指定seckill组,默认是DEFAULT_GROUP
namespace: a63d5389-1011-4a8b-b3b0-09ff0839156a #指定对应namespace id[阿里]
测试
浏览器: http://localhost:5000/nacos/config/ip

Namespace/Group/Data ID 关系

- Nacos默认的命名空间是public,Namespace主要用来实现配置隔离,隔离范围大
- Group默认是DEFAULT GROUP,Group可以把不同的微服务划分到同一个分组里面去
- Service就是微服务, 相同的Service可以是一个Cluster(簇/集群),Instance 就是微服务的实例