文章目录
- 学习连接
- 1.Nacos安装与简单使用
- 2.服务分级存储模型
- 集群介绍
- 服务跨集群调用问题
- 服务集群属性
- 同集群优先的负载均衡
- 给user-service配置集群
- 修改user-service的yml配置文件
- 访问nacos
- 给order-service配置集群
- 修改order-service的yml配置文件
- 访问nacos
- 测试
- 权重负载均衡
- 测试
- 环境隔离
- Nacos环境隔离
- 测试
- 3. Nacos注册中心原理
- nacos注册中心细节分析
- nacos与eureka区别
- nacos的 临时实例&非临时实例
- 主动推送变更消息
- 总结
- 测试
- 4. Nacos配置管理
- 统一配置管理
- 在nacos中添加配置文件
- 从微服务拉取配置
- 示例
- 总结
- 配置热更新
- 方式一:@RefreshScope
- 方式二:@ConfigurationProperties
- 测试
- 多环境配置共享
- 优先级
- 测试一
- 添加一个环境共享配置
- 在user-service中读取共享配置
- 运行两个UserApplication,使用不同的profile
- 测试二
- 添加一个redis.yml
- 修改UserApplication1的bootstrap.yaml
- 修改redis.yml,并发布,再次访问测试
- 5. Nacos集群
- 集群结构图
- 搭建集群
- 初始化数据库
- 下载nacos
- 配置nacos
- 启动
- nginx反向代理
- 项目配置
- 依赖
- bootstrap.yaml
- application.yml
- UserApplication
- UserController2
- 测试
学习连接
SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
nacos官网
nacos github地址
【微服务】Nacos注册中心
nacos核心源码深度剖析
国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。
1.Nacos安装与简单使用
1.1. Nacos安装指南
Windows安装
开发阶段采用单机安装即可。
下载安装包
在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:
GitHub主页:https://github.com/alibaba/nacos
GitHub的Release下载页:https://github.com/alibaba/nacos/releases
如图:
本课程采用1.4.1.版本的Nacos,课前资料已经准备了安装包:
windows版本使用nacos-server-1.4.1.zip
包即可。
解压
将这个包解压到任意非中文目录下,如图:
目录说明:
- bin:启动脚本
- conf:配置文件
端口配置
Nacos的默认端口是8848,如果你电脑上的其它进程占用了8848端口,请先尝试关闭该进程。
如果无法关闭占用8848端口的进程,也可以进入nacos的conf目录,修改配置文件中的端口:
修改其中的内容:
启动
启动非常简单,进入bin目录,结构如下:
然后执行命令即可:
-
windows命令:
## 此时由于没有修改配置文件, 默认将数据持久化到与bin文件夹同级目录data文件夹中 startup.cmd -m standalone
执行后的效果如图:
访问
在浏览器输入地址:http://127.0.0.1:8848/nacos即可:
默认的账号和密码都是nacos,进入后:
Linux安装
Linux或者Mac安装方式与Windows类似。
安装JDK
Nacos依赖于JDK运行,索引Linux上也需要安装JDK才行。
上传jdk安装包:
上传到某个目录,例如:/usr/local/
然后解压缩:
tar -xvf jdk-8u144-linux-x64.tar.gz
然后重命名为java
配置环境变量:
export JAVA_HOME=/usr/local/java
export PATH=$PATH:$JAVA_HOME/bin
设置环境变量:
source /etc/profile
上传安装包
如图:
也可以直接使用课前资料中的tar.gz:
上传到Linux服务器的某个目录,例如/usr/local/src
目录下:
解压
命令解压缩安装包:
tar -xvf nacos-server-1.4.1.tar.gz
然后删除安装包:
rm -rf nacos-server-1.4.1.tar.gz
目录中最终样式:
目录内部:
端口配置
与windows中类似
启动
在nacos/bin目录中,输入命令启动Nacos:
sh startup.sh -m standalone
1.2.服务注册到nacos
Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。
主要差异在于:
- 依赖不同
- 服务地址不同
使用步骤
引入依赖
在cloud-demo父工程的pom文件中的<dependencyManagement>
中引入SpringCloudAlibaba的依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
然后在user-service和order-service中的pom文件中引入nacos-discovery依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
注意:不要忘了注释掉eureka的依赖。
配置nacos地址
在user-service和order-service的application.yml中添加nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848
注意:不要忘了注释掉eureka的地址
重启
重启微服务后,登录nacos管理页面,可以看到微服务信息:
示例
父工程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">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itcast.demo</groupId>
<artifactId>cloud-demo</artifactId>
<version>1.0</version>
<modules>
<module>user-service</module>
<module>order-service</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
<mysql.version>5.1.47</mysql.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
user-service
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>cloud-demo</artifactId>
<groupId>cn.itcast.demo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
server-addr: localhost:8848
datasource:
url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
UserController
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 路径: /user/110
*
* @param id 用户id
* @return 用户
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id) {
return userService.queryById(id);
}
}
UserService
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Long id) {
return userMapper.findById(id);
}
}
order-service
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>cloud-demo</artifactId>
<groupId>cn.itcast.demo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--引入HttpClient依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8080
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848
datasource:
url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients("cn.itcast.order.feign")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
OrderService
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.用Feign远程调用
User user = userClient.findById(order.getUserId());
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
}
UserClient
@FeignClient(value = "user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
访问nacos
将user-service分别以8081和8082启动,order以8080启动。
效果如下:
2.服务分级存储模型
集群介绍
一个服务可以有多个实例,例如我们的user-service,可以有:
- 127.0.0.1:8081
- 127.0.0.1:8082
- 127.0.0.1:8083
假如这些实例分布于全国各地的不同机房,例如:
- 127.0.0.1:8081,在上海机房
- 127.0.0.1:8082,在上海机房
- 127.0.0.1:8083,在杭州机房
Nacos就将同一机房内的实例 划分为一个集群。
也就是说,user-service是服务,一个服务可以包含多个集群,如杭州、上海,每个集群下可以有多个实例(按地域划分集群),形成分级模型,如图:
服务跨集群调用问题
微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快
。当本集群内不可用时,才访问其它集群。例如:
杭州机房内的order-service应该优先访问同机房的user-service。
服务集群属性
Nacos服务分级存储模型
- 一级是服务,例如userservice
- 二级是集群,例如杭州或上海
- 三级是实例,例如杭州机房的某台部署了userservice的服务器
如何设置实例的集群属性
- 修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name属性即可
同集群优先的负载均衡
默认的ZoneAvoidanceRule
并不能实现根据同集群优先来实现负载均衡。
因此Nacos中提供了一个NacosRule
的实现,可以优先从同集群中挑选实例。
NacosRule负载均衡策略
- 优先选择同集群服务实例列表
- 本地集群找不到提供者,才去其它集群寻找,并且会报警告
- 确定了可用实例列表后,再采用随机负载均衡挑选实例
下面通过1个示例来演示
给user-service配置集群
修改user-service的yml配置文件
在前面最基础的示例上,仅修改user-service的yml配置文件,启动3个user-service实例,分别占用8081,8082,8083端口,其中8081,8082的集群名称使用HZ,8083的集群名称使用SH
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
datasource:
url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
访问nacos
点击详情进去查看
给order-service配置集群
修改order-service的yml配置文件
在前面最基础的示例上,仅修改order-service的yml配置文件
server:
port: 8080
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
discovery:
cluster-name: HZ # 设置当前服务实例所属集群名称
datasource:
url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
访问nacos
测试
现在我们多次调用:http://localhost:8080/order/103
,发现:order-service会轮询调用这3个实例。可是,我们知道order-service服务是在HZ这个集群的,它应当要优先
选择HZ集群下的user-service服务,当HZ集群下的user-service服务不可用时,再去选择其它集群下的user-service服务实例。
为了解决上面这个问题,我们在order-service中设置负载均衡的IRule为NacosRule
(如下配置),这个规则优先会寻找与自己同集群的服务,重启order-service后,多次调用:http://localhost:8080/order/103
发现:order-service会去HZ集群中随机选择1个user-service实例,而SH集群的user-service实例没有被选择。此时,把HZ集群下的user-service实例全部关掉,多次调用:http://localhost:8080/order/103
发现:刚开始报错几次之后,就选择到了SH集群下的user-service实例,并且此时order-service下会有WARN级别的日志:[nio-8080-exec-3] c.alibaba.cloud.nacos.ribbon.NacosRule : A cross-cluster call occurs
,当查看到这个日志时,就知道发生了跨集群调用了。
server:
port: 8080
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ
datasource:
url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
权重负载均衡
实际部署中会出现这样的场景:
-
服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求
-
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高
实例的权重控制
- Nacos控制台可以设置实例的权重值,0~1之间
- 同集群内的多个实例,权重越高被访问的频率越高
- 权重设置为0则完全不会被访问(可以用作平滑升级:当某个服务需要升级时,先把权重调的很低,先放部分用户过来,当没有问题时,再提高权重)
测试
如下修改8082的权重为0.1,现在我们调用:http://localhost:8080/order/103
20次,发现:18次都在8081上,有2次再8082上,说明权重设置是生效的。
可以看到8082的权重改为了0.1,而8081的权重仍然为1
再尝试把8081的权重设置为0,8082的权重恢复为1,发现:8081没有被访问,全都到了8082上。
环境隔离
Nacos提供了namespace
来实现环境隔离功能。Nacos中服务存储
和数据存储
的最外层
都是一个名为namespace
的东西,用来做最外层隔离
- nacos中可以有多个namespace
- namespace下可以有group、service等(而服务由下分为:服务-集群-实例)
- 不同namespace之间相互隔离,例如不同namespace的服务互相不可见(不同namespace下的各服务完全隔离,互相之间完全看不见对方)
Nacos环境隔离
- 每个namespace都有唯一id
- 服务设置namespace时要写id而不是名称
- 不同namespace下的服务互相不可见(如果要让2个服务之间能调用,那么它们必须在同1个namespace下)
测试
最初的默认配置如下:
创建1个dev的命名空间:
修改order-service的application.yml,添加namespace(注意是命名空间id),重启order-service,发现:order-service已经从public命名空间下移除掉了,并且注册到了dev命名空间下,此时访问:http://localhost:8080/order/103
,就会报错:com.netflix.client.ClientException: Load balancer does not have available server for client: user-service
负载均衡已经找不到user-service
服务
server:
port: 8080
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ
namespace: 7fe7efeb-e4a4-4cd1-82f4-46d46c6f7bba # 填命名空间ID
datasource:
url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
3. Nacos注册中心原理
nacos注册中心细节分析
服务提供者在启动时,都会把自己的信息提交给注册中心,注册中心就会把服务提供者的信息保存下来。当消费者需要消费时,就会从注册中心拉取服务提供者的信息(或者叫作服务发现),缓存到本地服务列表中,这样当下一次需要获取服务信息时,就不用从注册中心拉取了,而是使用缓存的服务列表信息。
当注册中心的服务列表变化时,就需要消费者定时从注册中心拉取服务信息缓存到本地,其中,eureka就每隔默认30s从注册中心拉取服务信息。当消费者获取到服务后,从提供的服务中根据负载均衡策略挑选服务发起远程调用。
nacos与eureka区别
nacos的 临时实例&非临时实例
Nacos的服务实例分为两种类型:
临时实例
:如果实例宕机超过一定时间,会从服务列表剔除
,默认的类型(如果不作任何配置,默认就是临时实例;临时实例每隔一段时间,定时向注册中心发送1次心跳报告健康状态,这一点与eureka相同;超过一定时间未收到心跳,将会从服务列表中剔除)。非临时实例
:如果实例宕机,不会从服务列表剔除
,也可以叫永久实例。(非临时实例不会向注册中心发送心跳请求,而是由注册中心主动询问健康状态;nacos主动发请求询问,如果检测不到,也不会清除这个服务,而是会一直等待这个非临时实例好为止)
主动推送变更消息
当服务提供者信息发生变化,而服务消费者由于采用的是定时拉取,未能及时更新本地缓存服务列表,此时发起远程调用会发生问题。eureka采取的是pull定时拉取
方案,因此更新的不够及时,服务列表更新效率差,而nacos采取的是pull定时拉取 + 主动推送变更消息
,如果服务提供信息发生变化时,会立即将此变更消息推送到消费者。
总结
- Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
- Nacos与Eureka的区别
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
测试
修改order-service的application.yml配置文件,将order-service注册为非临时实例
server:
port: 8080
spring:
application:
name: order-service
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ
namespace: 7fe7efeb-e4a4-4cd1-82f4-46d46c6f7bba # 填命名空间ID
ephemeral: false # 是否临时实例
datasource:
url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
从中可以看到order-service注册为非临时实例了,这与之前的注册为临时实例是不同的
当关闭order-service,发现order-service仍然还在列表中(如果是临时实例,会直接在列表中被移除掉。因此,只能手动移除它。)
当order-service重新上线,就恢复了
4. Nacos配置管理
Nacos除了可以做注册中心,同样可以做配置管理来使用。
统一配置管理
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。
Nacos一方面可以将配置集中管理
,另一方可以在配置变更时,及时通知微服务,实现配置的热更新
。
在nacos中添加配置文件
在Nacos中添加配置信息,点击“+”号:
然后在弹出的表单中,填写配置信息(注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。):
从微服务拉取配置
微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。
但如果尚未读取application.yml,又如何得知nacos地址呢?
因此spring cloud引入了一种新的配置文件:bootstrap.yaml
文件,会在application.yml之前被读取
,流程如下:
示例
第一步:给user-service 引入Nacos的配置管理客户端依赖:
<?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>cloud-demo</artifactId>
<groupId>cn.itcast.demo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--nacos服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第二步:添加bootstrap.yaml
然后,在user-service中添加一个bootstrap.yaml文件,内容如下:
spring:
application:
name: user-service # 服务名称
profiles:
active: dev # 开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
config:
file-extension: yaml # 文件后缀名
这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作为文件id,来读取配置。本例中,就是去读取user-service-dev.yaml
:
此时的application.yml配置如下:
server:
port: 8081
spring:
cloud:
nacos:
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
datasource:
url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
第三步:修改UserController,注入nacos配置文件的配置,测试是否生效
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
// ... 省略其它代码
/* 注入nacos配置文件的配置 */
@Value("${pattern.dataFormat}")
private String dataFormat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataFormat));
}
}
第四步:以8081端口,重启user-service服务,发现user-service已成功注册到了nacos,并且是在HZ集群。此时访问:http://localhost:8081/user/now
,返回如下
总结
将配置交给Nacos管理的步骤
- 在Nacos中添加配置文件
- 在微服务中引入nacos的config依赖
- 在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件
配置热更新
我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。
Nacos中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:
方式一:@RefreshScope
在@Value注入的变量所在类上添加注解@RefreshScope
方式二:@ConfigurationProperties
使用@ConfigurationProperties注解,此时无需使用@RefreshScope注解
测试
修改UserController,如下:
@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope // 添加@RefreshScope注解
public class UserController {
// ...省略其它代码
@Value("${pattern.dataFormat}")
private String dataFormat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataFormat));
}
}
创建UserController2,如下:
@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope
public class UserController2 {
@Autowired
private PatternProperties properties;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDataFormat()));
}
}
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dataFormat;
private String envSharedValue;
private String name;
}
重启user-service,访问如下:
此时修改nacos中的配置,如下:
此时,可以看到user-service日志输出如下:
06-15 16:27:23:837 INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [polling-resp] config changed. dataId=user-service-dev.yaml, group=DEFAULT_GROUP
06-15 16:27:23:837 INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : get changedGroupKeys:[user-service-dev.yaml+DEFAULT_GROUP]
06-15 16:27:23:840 INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [data-received] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, tenant=null, md5=a64c8b4c6e466eaa891f821c40ee71c1, content=pattern:
dataFormat: yyyy-MM-dd, type=yaml
06-15 16:27:23:840 INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-context] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1
06-15 16:27:25:999 WARN 15636 --- [-localhost_8848] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[user-service] & group[DEFAULT_GROUP]
06-15 16:27:26:002 WARN 15636 --- [-localhost_8848] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[user-service.yaml] & group[DEFAULT_GROUP]
06-15 16:27:26:005 INFO 15636 --- [-localhost_8848] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-user-service-dev.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-user-service.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-user-service,DEFAULT_GROUP'}]
06-15 16:27:26:009 INFO 15636 --- [-localhost_8848] o.s.boot.SpringApplication : The following profiles are active: dev
06-15 16:27:26:014 INFO 15636 --- [-localhost_8848] o.s.boot.SpringApplication : Started application in 2.173 seconds (JVM running for 313.295)
06-15 16:27:26:044 INFO 15636 --- [-localhost_8848] o.s.c.e.event.RefreshEventListener : Refresh keys changed: [pattern.dataFormat]
06-15 16:27:26:044 INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-ok] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@22606caa
06-15 16:27:26:044 INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-listener] time cost=2204ms in ClientWorker, dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@22606caa
此时,再次访问如下,发现,在未重启user-service的情况下,对配置的修改已生效
多环境配置共享
其实微服务启动时,会去nacos读取多个配置文件
,例如:
-
[spring.application.name]-[spring.profiles.active].yaml
,例如:user-service-dev.yaml -
[spring.application.name].yaml
,例如:user-service.yaml
而[spring.application.name].yaml
不包含环境,因此会被多个环境共享(也就是user-service.yaml这个配置文件会被所有的spring.application.name为user-service的服务所共享)。
即:无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件,如果不同的配置文件的配置了相同的属性,那么优先级是:[服务名]-[环境].yaml >[服务名].yaml > 本地配置
优先级
微服务默认读取的配置文件:
- [服务名]-[spring.profile.active].yaml,默认配置
- [服务名].yaml,多环境共享
不同微服务共享的配置文件:
- 通过shared-configs指定
- 通过extension-configs指定
优先级:
- 环境配置 >服务名.yaml > extension-config > extension-configs > shared-configs > 本地配置
测试一
添加一个环境共享配置
我们在nacos中添加一个userservice.yaml文件:
此时配置如下:
在user-service中读取共享配置
在user-service服务中,修改PatternProperties类,读取新添加的属性:
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dataFormat;
// 读取定义在user-service.yaml中的配置
private String envSharedValue;
private String name;
}
UserController2,如下
@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope
public class UserController2 {
@Autowired
private PatternProperties properties;
@GetMapping("props")
public PatternProperties props(){
return properties;
}
}
运行两个UserApplication,使用不同的profile
user-service的配置同:统一配置管理中的示例。在此配置的基础上,作如下修改:
修改UserApplication2这个启动项,改变其profile值为test(等价于修改spring.profile.active的值)
这样,UserApplication(8081)使用的profile是dev,UserApplication2(8082)使用的profile是test。
启动UserApplication和UserApplication2(启动UserApplication2,此时日志会输出:The following profiles are active: test
)
访问http://localhost:8081/user2/props,结果:
访问http://localhost:8082/user2/props,结果:
可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值,而dev还读取到了自己的user-service-dev.yaml中配置的pattern.dataFormat的值。
可以看出,每个服务实例不仅会加载当前所设置的profile配置(user-service-dev.yaml),还会默认加载上不带profile的公共配置(user-service.yaml)
测试二
有的时候,某个服务实例,需要加载自己所需要的配置,这些配置被某些服务实例所共享,但其它服务却是不需要的。此时,可以用到nacos提供的扩展配置
添加一个redis.yml
此时配置如下:
修改UserApplication1的bootstrap.yaml
添加 spring.cloud.nacos.config.extension-configs
配置
spring:
application:
name: user-service # 服务名称
profiles:
active: dev # 开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
config:
file-extension: yaml # 文件后缀名
extension-configs:
- data-id: redis.yml
group: common
refresh: true
此时的application.yml配置文件(未作任何修改)
server:
port: 8081
spring:
cloud:
nacos:
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
datasource:
url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
重启UserApplication1,访问测试,发现读取到了redis.yml中的配置
修改redis.yml,并发布,再次访问测试
可以看到,redis.port的值 热更新了
5. Nacos集群
Nacos生产环境下一定要部署为集群状态
集群结构图
官方给出的Nacos集群图
其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。
我们计划的集群结构,Nginx做负载均衡,MySQL集群做数据共享:
三个Nacos节点的地址
节点 | ip | port |
---|---|---|
nacos1 | 192.168.134.5 | 8845 |
nacos2 | 192.168.134.5 | 8846 |
nacos3 | 192.168.134.5 | 8847 |
搭建集群
搭建集群的基本步骤
- 搭建数据库,初始化数据库表结构
- 下载nacos安装包
- 配置nacos
- 启动nacos集群
- nginx反向代理
初始化数据库
Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。
官方推荐的最佳实践是使用带有主从模式的高可用数据库集群,这里我们以单点的数据库为例来讲解
首先新建一个数据库,命名为nacos,而后导入下面的SQL:
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) DEFAULT NULL,
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL,
`c_use` varchar(64) DEFAULT NULL,
`effect` varchar(64) DEFAULT NULL,
`type` varchar(64) DEFAULT NULL,
`c_schema` text,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(64) unsigned NOT NULL,
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`data_id` varchar(255) NOT NULL,
`group_id` varchar(128) NOT NULL,
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL,
`md5` varchar(32) DEFAULT NULL,
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`src_user` text,
`src_ip` varchar(50) DEFAULT NULL,
`op_type` char(10) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY,
`password` varchar(500) NOT NULL,
`enabled` boolean NOT NULL
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL,
`role` varchar(50) NOT NULL,
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL,
`resource` varchar(255) NOT NULL,
`action` varchar(8) NOT NULL,
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
下载nacos
nacos在GitHub上有下载地址: https://github.com/alibaba/nacos/tags,可以选择任意版本下载。
本例中采用1.4.1版本
配置nacos
将这个包解压到任意非中文目录下,如图:
目录说明
- bin:启动脚本
- conf:配置文件
进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf,然后添加每个nacos节点的ip和端口,内容如下:
然后,修改application.properties文件,修改数据库配置:
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root
启动
将nacos文件夹复制三份,分别命名为: nacos1、nacos2、nacos3
然后分别修改三个文件夹中的application.properties
nacos1:
server.port=8845
nacos2:
server.port=8846
nacos3:
server.port=8847
然后分别启动三个nacos节点:双击 startup.cmd 以集群模式启动即可
nginx反向代理
解压nginx-1.18.0.zip压缩包,如下:
将如下内容,添加到http块中,以实现nginx对nacos集群的负载均衡
upstream nacos-cluster {
server 192.168.134.5:8845;
server 192.168.134.5:8846;
server 192.168.134.5:8847;
}
server {
listen 80;
server_name 192.168.134.5;
location /nacos {
proxy_pass http://nacos-cluster;
}
}
此时访问nacos就不用带端口号了:http://192.168.134.5/nacos
添加user-service-dev.yaml配置文件
项目配置
仅修改了user-service的bootstrap.yaml配置文件的spring.cloud.nacos.server-addr配置,其它未动,这里将user-service的重要配置列出来
依赖
<!--nacos服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
bootstrap.yaml
仅修改了spring.cloud.nacos.server-addr=192.168.134.5:80
spring:
application:
name: user-service # 服务名称
profiles:
active: dev # 开发环境,这里是dev
cloud:
nacos:
server-addr: 192.168.134.5:80 # nacos集群地址(就是nginx作负载均衡的地址)
config:
file-extension: yaml # 文件后缀名
extension-configs:
- data-id: redis.yml
group: common
refresh: true
application.yml
server:
port: 8081
spring:
cloud:
nacos:
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
datasource:
url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.itcast.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
UserController2
此处使用@RefreshScope的方式来热更新
@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope
public class UserController2 {
@Autowired
private PatternProperties properties;
@GetMapping("props")
public PatternProperties props(){
return properties;
}
}
测试
访问http://localhost:8081/user2/props
如上修改配置后,再次访问http://localhost:8081/user2/props
说明集群搭建成功