5.Nacos注册中心
国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。
5.1.认识和安装Nacos
Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。
5.2 Windows安装
开发阶段采用单机安装即可。
1.下载安装包
在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
包即可。
2.解压
将这个包解压到任意非中文目录下,如图:
目录说明:
- bin:启动脚本
- conf:配置文件
3.端口配置
Nacos的默认端口是8848,如果你电脑上的其它进程占用了8848端口,请先尝试关闭该进程。
如果无法关闭占用8848端口的进程,也可以进入nacos的conf目录,修改配置文件中的端口:
修改其中的内容:
4.启动
- 启动非常简单,进入bin目录,结构如下:
- 然后执行命令即可:
- windows命令:以单服务器模式启动
startup.cmd -m standalone
- 执行后的效果如图:
- 建议创建一个快捷方式,以后方便运行
5.访问
在浏览器输入地址:http://127.0.0.1:8848/nacos即可:
默认的账号和密码都是nacos,进入后:
5.3.服务注册到nacos
Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。
主要差异在于:
- 依赖不同
- 服务地址不同
操作步骤
1)引入依赖
在cloud-demo父工程的pom文件中的<dependencyManagement>
中引入SpringCloudAlibaba的依赖:
<!-- nacos -->
<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依赖:
<!-- nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
注意:子工程不要忘了注释掉eureka的依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)配置nacos地址
在user-service和order-service的application.yml中添加nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848
注意:不要忘了注释掉eureka的地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
3)重启
重启微服务后,登录nacos管理页面,可以看到微服务信息:
将服务注册到nacos步骤:
- 导入依赖
- 配置文件编写nacos注册中心地址,注释Eureka相关依赖和配置
- 启动服务
注意:
5.4.环境隔离
为了便于管理,Nacos提供了namespace来实现环境隔离功能。用于进行租户级别的隔离,我们最常用的就是不同环境比如测试环境,线上环境进行隔离。
- nacos中可以有多个namespace
- namespace下可以有group等。业务相关性比较强的可以放在一组,比如:支付和订单
- 不同namespace之间相互隔离,即不同namespace的服务互相不可见
1.创建namespace
应用场景:基于不同的开发环境变化做隔离操作
默认情况下,所有service、group都在同一个namespace,名为public:
- 我们可以点击页面新增按钮,添加一个namespace:
- 然后,填写数据:
- 能在页面看到一个新的namespace:
2.给微服务配置namespace
- 给微服务配置namespace只能通过修改配置来实现。
例如,修改order-service的application.yml文件:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0 # 命名空间,填ID
- 重启order-service后,查看管理页面,可以看到在public下没有orderservice服务
点旁边的dev可以看到另一个空间的服务只有orderservice:
此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错
修改user-service中的application.yml,把它的namespace也设置成同一个命名空间
spring:
application:
name: userservice
cloud:
nacos:
server-addr: localhost:8848
discovery:
namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0
- 重启UserApplication8081的服务,查看nacos的服务列表
- 再次访问可以正常访问
小结:
使用namespace配置环境隔离步骤
- 创建命令空间
配置文件配置namespace的id
使用场景:
隔离开发环境/测试环境/生产环境的服务
5.5.Nacos与Eureka的区别
Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异:
- Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳的方式做健康检测
- Nacos与Eureka的区别
- 服务注册:Nacos的实例有永久和临时实例之分;而Eureka只支持临时实例
- 服务发现:Nacos支持定时拉取和主动推送两种模式;Eureka只支持定时拉取模式
- 健康检测:Nacos对临时实例采用心跳模式检测,对永久实例采用主动请求来检测;Eureka只支持心跳模式
1.Nacos配置中心
Nacos除了可以做注册中心,同样可以做配置中心来使用。1.1.统一配置管理
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。1.1.1.在nacos中添加配置文件
如何在nacos中管理配置呢?
然后在弹出的表单中,填写配置信息:
注:这里扩展名使用yaml
配置内容如下:pattern:
dateformat: yyyy-MM-dd HH:mm:ss
注意:需要热更新的配置才有放到nacos管理的必要,比如一些偶尔会变动的参数。基本不会变更的一些配置还是保存在微服务本地比较好。
1.1.2.微服务拉取nacos配置
微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。
但如果尚未读取application.yml,又如何得知nacos地址呢?
因此Spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:
1)在user-service服务中,引入nacos-config的客户端依赖:
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2)添加bootstrap.yaml
然后,在user-service中添加一个bootstrap.yaml文件,内容如下:
- 服务名为userservice,注:名字中间没有短横。
- 指定激活的配置dev
- 指定spring.cloud.nacos.server-addr的服务地址:localhost:8848
- 指定spring.cloud.nacos.config.file-extension配置文件的扩展名为yaml
spring:
application:
name: userservice # 服务名称,注:要与文件名一致
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,来读取配置。
本例中,就是去读取userservice-dev.yaml
:
- 去掉application.yml中相关重复的配置
application:
name: userservice
cloud:
nacos:
server-addr: localhost:8848
discovery:
namespace: a8ace27d-a737-4122-9f3f-92f5ee795b62
4)读取nacos配置
在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:
完整代码:
package cn.itcast.user.web;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Value("${pattern.dateformat}")
private String dateformat;
@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
}
访问不同的服务页面,可以看到效果:
小结:
如何实现统一配置管理:
- 在nacos配置中心新建配置文件
- 拉取配置文件
注意:通过bootstrap.yaml引导文件读取nacos配置文件
1.2.配置热更新
我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。
Nacos可以在配置变更时,及时通知微服务,实现配置的热更新。
要实现配置热更新,可以使用两种方式:
1.2.1.方式一
在@Value注入的变量所在类上添加注解@RefreshScope:
步骤
- 在UserController上添加@RefreshScope注解,这个注解会重新加载实例对象,并且使用新的配置
- 重新启动UserApplication让新的代码起作用
- 这时再修改配置管理中的配置
- 在浏览器输入访问地址,查看新的配置是否起作用
1.2.2.方式二
使用@ConfigurationProperties注解代替@Value注解。
- 去掉UserController上@RefreshScope注解和@Value注解
- 在user-service服务的config包中添加PatternProperties类
- 添加@Component注解
- 添加@ConfigurationProperties(prefix = “pattern”)注解
- 添加String dateformat属性
package cn.itcast.user.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
}
注:如果出现红色警告,在user-service的pom.xml中添加以下依赖即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
- 在UserController中使用这个类,并且使用@Autowired注入
- 完整代码:
package cn.itcast.user.web;
import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private PatternProperties patternProperties;
@GetMapping("now")
public String now(){
return LocalDateTime.now()
.format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}
}
- 重启UserApplication微服务
- 再修改nacos的配置
- 在浏览器查看效果
小结:
配置热更新的两种方式:
- @RefreshScope:加在使用@Value注解的类上
- 编写配置类@ConfigurationProperties注解代替@Value注解
1.3.配置共享
1. 共享配置的说明
应用场景:某个配置在开发,测试,生产环境中的配置是一样的,就可以使用共享配置
其实微服务启动时,会去nacos读取多个配置文件,例如:
[spring.application.name]-[spring.profiles.active].yaml
,例如:userservice-dev.yaml[spring.application.name].yaml
,例如:userservice.yaml
而[spring.application.name].yaml
不包含环境,因此可以被多个环境共享。
2. 测试配置共享
1)添加一个环境共享配置
我们在nacos中添加一个userservice.yaml文件:
pattern:
envSharedValue: 大家都可以用哦
这时有两个配置文件存在
2)在user-service中读取共享配置
- 在user-service服务中,修改PatternProperties类,读取新添加的属性:
- 在user-service服务中,修改UserController,添加一个方法,直接返回PatternProperties对象 ```java package cn.itcast.user.web;
@RestController @RequestMapping(“/user”) public class UserController {
@Autowired
private PatternProperties patternProperties;
@GetMapping("/prop")
public PatternProperties prop() {
return patternProperties;
}
}
<a name="2cf7c2d7"></a>
#### 3)运行两个UserApplication,使用不同的profile
修改UserApplication8082这个启动项,改变其profile值:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26006407/1651803282947-877c6844-ec58-4ebe-a81b-d63bafe46132.png#clientId=u5b51583e-c5c5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=103&id=u72d2f69f&name=image.png&originHeight=129&originWidth=648&originalType=binary&ratio=1&rotation=0&showTitle=false&size=40974&status=done&style=none&taskId=u5b83dc98-684c-4620-b685-73fe177e826&title=&width=518.4)
注:这个test的profiles是不存在的
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26006407/1651803292004-311b2d89-4e01-4cdf-a429-2a0efb07fe7d.png#clientId=u5b51583e-c5c5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=442&id=ua14d5115&name=image.png&originHeight=552&originWidth=800&originalType=binary&ratio=1&rotation=0&showTitle=false&size=79605&status=done&style=none&taskId=ubd59711d-29e4-4141-8b98-b9602854e49&title=&width=640)
这样,UserApplication8081使用的profile是dev,UserApplication8082使用的profile是test。
<a name="ae0fb202"></a>
#### 4) 执行结果
启动UserApplication和UserApplication2
访问http://localhost:8081/user/prop,结果:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26006407/1651803302206-81eac85e-f009-4066-bf75-10d2477a3484.png#clientId=u5b51583e-c5c5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=178&id=ufc9a413d&name=image.png&originHeight=223&originWidth=533&originalType=binary&ratio=1&rotation=0&showTitle=false&size=41240&status=done&style=none&taskId=u83bf43df-e473-4e0b-b7e0-ff7fdd8f53b&title=&width=426.4)
访问http://localhost:8082/user/prop,结果:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26006407/1651803309611-03e3269a-78ed-401e-ba70-641091cac9fe.png#clientId=u5b51583e-c5c5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=146&id=u0e7d3176&name=image.png&originHeight=183&originWidth=529&originalType=binary&ratio=1&rotation=0&showTitle=false&size=32681&status=done&style=none&taskId=u367685e1-ac0a-4d47-ac3d-f76f813c027&title=&width=423.2)
可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值。
小结:
如何实现nacos环境配置共享:
将共享配置属性配置到共享配置文件:不带环境名称的配置文件
<a name="25fe6974"></a>
### 3. 配置共享的优先级
<a name="7fb9a961"></a>
#### 1. 优先级说明
当nacos、服务本地同时出现相同属性时,优先级有高低之分:
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26006407/1651803320661-63cc86cf-4ccd-4248-b77f-e622682b7da6.png#clientId=u5b51583e-c5c5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=230&id=ua9000c30&name=image.png&originHeight=288&originWidth=650&originalType=binary&ratio=1&rotation=0&showTitle=false&size=41602&status=done&style=none&taskId=u41ef95e7-9b9c-4997-b6ce-7aeb117608d&title=&width=520)
服务器控制台显示:
Located property source: [BootstrapPropertySource {name=’bootstrapProperties-userservice-dev.yaml,DEFAULT_GROUP’}, BootstrapPropertySource {name=’bootstrapProperties-userservice.yaml,DEFAULT_GROUP’}, BootstrapPropertySource {name=’bootstrapProperties-userservice,DEFAULT_GROUP’}]
<a name="7a718ce6"></a>
#### 2. 演示
1. 在PatternProperties中添加新的username属性
```java
@Component
@ConfigurationProperties(prefix = "pattern")
@Data
public class PatternProperties {
private String dateformat;
private String envSharedValue;
private String username;
}
在application.yml中添加新的username属性,查看浏览器运行效果
pattern:
username: 孙悟空
在userservice.yaml中添加新的username属性,查看浏览器运行效果
- 在userservice-dev.xml中添加新的username属性,查看浏览器运行效果
小结
配置文件的优先级顺序:
nacos带有环境名称的配置文件>nacos共享配置文件>本地配置文件
1.4.搭建Nacos集群
1.集群结构图
官方给出的Nacos集群图:
SLB:负载均衡器,负责将我们的请求分发到不同的nacos节点
其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。
我们计划的集群结构:
三个nacos节点的地址:
节点 | 换成实际服务器的IP地址 | port |
---|---|---|
nacos1 | 192.168.132.2 | 8845 |
nacos2 | 192.168.132.2 | 8846 |
nacos3 | 192.168.132.2 | 8847 |
2.搭建集群
搭建集群的基本步骤:(参考nacos集群搭建.md文档)
- 搭建数据库,初始化数据库表结构
- 下载nacos安装包
- 配置nacos
- 启动nacos集群
- nginx反向代理
2.1.初始化数据库
Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。
官方推荐的最佳实践是使用带有主从的高可用数据库集群,主从模式的高可用数据库可以参考传智教育的后续高手课程。这里我们以单点的数据库为例来讲解。
首先新建一个数据库,命名为nacos。这个表结构已经由官方提供了。
注:要使用mysql5.7以上的版本,5.5运行不了。
数据库执行资料中的sql脚本:nacos.sql
2.2.配置Nacos
- 创建一个目录名为:nacos-cluster
- 进入目录nacos-cluster目录,重新解压安装一份新的nacos
- 进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf
4.然后添加内容,注意:此处的IP是你自己机器的IP地址,不要写成127.0.0.1,否则会导致微服务注册失败
192.168.132.2:8845
192.168.132.2:8846
192.168.132.2:8847
在cmd下使用ipconfig来查看自己的IP地址
5.然后修改application.properties文件,修改数据库配置。
# mysql的数据库集群
spring.datasource.platform=mysql
# 数据库的数量
db.num=1
# 连接字符串
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
这里的数据库地址、用户名、密码请根据实际情况配置。
2.3.启动
将nacos改名成nacos1,并且复制两份,分别命名为:nacos2、nacos3
然后分别修改三个文件夹中的application.properties,大约在21行
nacos1:
server.port=8845
nacos2:
server.port=8846
nacos3:
server.port=8847
然后打开三个cmd窗口,分别启动三个nacos节点,不需要带参数,默认是集群启动方式,也可以双击运行
startup.cmd
看到以下提示表示启动成功
INFO Nacos started successfully in cluster mode. use external storage
2.5.nginx反向代理
- 找到课前资料提供的nginx安装包:
- 解压到任意非中文目录下:
- 修改conf/nginx.conf文件,配置如下
这里使用127.0.0.1不影响
upstream nacos-cluster {
server 127.0.0.1:8845;
server 127.0.0.1:8846;
server 127.0.0.1:8847;
}
server {
listen 80;
server_name localhost;
location /nacos {
proxy_pass http://nacos-cluster;
}
}
粘贴到http元素的内部位置都可以,不用删除以前的server配置
- 在命令行下输入:start nginx.exe启动nginx服务器,也可以双击运行,运行后查看任务管理器
- 在浏览器访问:http://localhost/nacos即可。
- 查看
集群管理->节点列表
2.6. Java代码的修改
- 修改userservice服务的bootstrap.yaml文件配置如下:
spring:
cloud:
nacos:
server-addr: localhost:80 # Nacos地址
- 在nacos管理页面创建新的配置管理:userservice.yaml文件,同时修改java代码:在PatternProperties里增加属性username
- 重新启动UserApplication微服务
- 浏览器上访问
- 就会在mysql的nacos库的config_info表中出现上面的配置信息
注意点:启动Nacos集群服务时,确定启动IP是否本机IP地址,如果启动的服务地址是虚拟机IP地址,需要关闭虚拟网卡