5.Nacos注册中心

国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。

5.1.认识和安装Nacos

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。

image.png

5.2 Windows安装

开发阶段采用单机安装即可。

1.下载安装包

在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:

GitHub主页:https://github.com/alibaba/nacos

GitHub的Release下载页:https://github.com/alibaba/nacos/releases

如图:

image.png

本课程采用1.4.1.版本的Nacos,课前资料已经准备了安装包:

image.png

windows版本使用nacos-server-1.4.1.zip包即可。

2.解压

将这个包解压到任意非中文目录下,如图:

image.png

目录说明:

  • bin:启动脚本
  • conf:配置文件

3.端口配置

Nacos的默认端口是8848,如果你电脑上的其它进程占用了8848端口,请先尝试关闭该进程。

如果无法关闭占用8848端口的进程,也可以进入nacos的conf目录,修改配置文件中的端口:

image.png

修改其中的内容:

image.png

4.启动

  1. 启动非常简单,进入bin目录,结构如下:

image.png

  1. 然后执行命令即可:
  • windows命令:以单服务器模式启动
    1. startup.cmd -m standalone
  1. 执行后的效果如图:

image.png

  1. 建议创建一个快捷方式,以后方便运行

image.png

5.访问

在浏览器输入地址:http://127.0.0.1:8848/nacos即可:

image.png

默认的账号和密码都是nacos,进入后:

image.png

5.3.服务注册到nacos

Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。

主要差异在于:

  • 依赖不同
  • 服务地址不同

操作步骤

1)引入依赖

在cloud-demo父工程的pom文件中的<dependencyManagement>中引入SpringCloudAlibaba的依赖:

  1. <!-- nacos -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  5. <version>2.2.6.RELEASE</version>
  6. <type>pom</type>
  7. <scope>import</scope>
  8. </dependency>

然后在子工程user-service和order-service中的pom文件中引入nacos-discovery依赖:

  1. <!-- nacos -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  5. </dependency>

注意:子工程不要忘了注释掉eureka的依赖。

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  4. </dependency>

2)配置nacos地址

在user-service和order-service的application.yml中添加nacos地址:

  1. spring:
  2. cloud:
  3. nacos:
  4. server-addr: localhost:8848

注意:不要忘了注释掉eureka的地址

  1. eureka:
  2. client:
  3. service-url:
  4. defaultZone: http://127.0.0.1:10086/eureka

3)重启

重启微服务后,登录nacos管理页面,可以看到微服务信息:

image.png

将服务注册到nacos步骤:

  1. 导入依赖
  2. 配置文件编写nacos注册中心地址,注释Eureka相关依赖和配置
  3. 启动服务

注意:

5.4.环境隔离

为了便于管理,Nacos提供了namespace来实现环境隔离功能。用于进行租户级别的隔离,我们最常用的就是不同环境比如测试环境,线上环境进行隔离。

  • nacos中可以有多个namespace
  • namespace下可以有group等。业务相关性比较强的可以放在一组,比如:支付和订单
  • 不同namespace之间相互隔离,即不同namespace的服务互相不可见

image.png

1.创建namespace

应用场景:基于不同的开发环境变化做隔离操作

默认情况下,所有service、group都在同一个namespace,名为public:

image.png

  1. 我们可以点击页面新增按钮,添加一个namespace:

image.png

  1. 然后,填写数据:

image.png

  1. 能在页面看到一个新的namespace:

image.png

2.给微服务配置namespace

  1. 给微服务配置namespace只能通过修改配置来实现。

例如,修改order-service的application.yml文件:

  1. spring:
  2. cloud:
  3. nacos:
  4. server-addr: localhost:8848
  5. discovery:
  6. namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0 # 命名空间,填ID
  1. 重启order-service后,查看管理页面,可以看到在public下没有orderservice服务

image.png

  1. 点旁边的dev可以看到另一个空间的服务只有orderservice:
    image.png

  2. 此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错

image.png

  1. 修改user-service中的application.yml,把它的namespace也设置成同一个命名空间

    1. spring:
    2. application:
    3. name: userservice
    4. cloud:
    5. nacos:
    6. server-addr: localhost:8848
    7. discovery:
    8. namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0
  1. 重启UserApplication8081的服务,查看nacos的服务列表
    image.png
  2. 再次访问可以正常访问

image.png
小结:

  1. 使用namespace配置环境隔离步骤
  1. 创建命令空间
  2. 配置文件配置namespace的id

    使用场景:

    1. 隔离开发环境/测试环境/生产环境的服务

5.5.Nacos与Eureka的区别

Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异:

image.png

  • Nacos与eureka的共同点
    • 都支持服务注册和服务拉取
    • 都支持服务提供者心跳的方式做健康检测
  • Nacos与Eureka的区别
    • 服务注册:Nacos的实例有永久和临时实例之分;而Eureka只支持临时实例
    • 服务发现:Nacos支持定时拉取和主动推送两种模式;Eureka只支持定时拉取模式
    • 健康检测:Nacos对临时实例采用心跳模式检测,对永久实例采用主动请求来检测;Eureka只支持心跳模式

      1.Nacos配置中心

      Nacos除了可以做注册中心,同样可以做配置中心来使用。

      1.1.统一配置管理

      当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。

      1.1.1.在nacos中添加配置文件

      如何在nacos中管理配置呢?
      image.png
      然后在弹出的表单中,填写配置信息:
      注:这里扩展名使用yaml
      image.png
      配置内容如下:
      1. pattern:
      2. dateformat: yyyy-MM-dd HH:mm:ss

      注意:需要热更新的配置才有放到nacos管理的必要,比如一些偶尔会变动的参数。基本不会变更的一些配置还是保存在微服务本地比较好。

1.1.2.微服务拉取nacos配置

微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。

但如果尚未读取application.yml,又如何得知nacos地址呢?

因此Spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:

image.png

1)在user-service服务中,引入nacos-config的客户端依赖:

  1. <!--nacos配置管理依赖-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  5. </dependency>

2)添加bootstrap.yaml

image.png

然后,在user-service中添加一个bootstrap.yaml文件,内容如下:

  1. 服务名为userservice,注:名字中间没有短横。
  2. 指定激活的配置dev
  3. 指定spring.cloud.nacos.server-addr的服务地址:localhost:8848
  4. 指定spring.cloud.nacos.config.file-extension配置文件的扩展名为yaml
  1. spring:
  2. application:
  3. name: userservice # 服务名称,注:要与文件名一致
  4. profiles:
  5. active: dev #开发环境,这里是dev
  6. cloud:
  7. nacos:
  8. server-addr: localhost:8848 # Nacos地址
  9. config:
  10. 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

image.png

  1. 去掉application.yml中相关重复的配置
  1. application:
  2. name: userservice
  3. cloud:
  4. nacos:
  5. server-addr: localhost:8848
  6. discovery:
  7. namespace: a8ace27d-a737-4122-9f3f-92f5ee795b62

4)读取nacos配置

在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:

image.png

完整代码:

  1. package cn.itcast.user.web;
  2. import cn.itcast.user.pojo.User;
  3. import cn.itcast.user.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.beans.factory.annotation.Value;
  6. import org.springframework.web.bind.annotation.*;
  7. import java.time.LocalDateTime;
  8. import java.time.format.DateTimeFormatter;
  9. @RestController
  10. @RequestMapping("/user")
  11. public class UserController {
  12. @Autowired
  13. private UserService userService;
  14. @Value("${pattern.dateformat}")
  15. private String dateformat;
  16. @GetMapping("now")
  17. public String now(){
  18. return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
  19. }
  20. }

访问不同的服务页面,可以看到效果:

image.png
小结:
如何实现统一配置管理:

  1. 在nacos配置中心新建配置文件
  2. 拉取配置文件
    注意:通过bootstrap.yaml引导文件读取nacos配置文件

1.2.配置热更新

我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新

Nacos可以在配置变更时,及时通知微服务,实现配置的热更新。

image.png

要实现配置热更新,可以使用两种方式:

1.2.1.方式一

在@Value注入的变量所在类上添加注解@RefreshScope:

image.png

步骤

  1. 在UserController上添加@RefreshScope注解,这个注解会重新加载实例对象,并且使用新的配置
  2. 重新启动UserApplication让新的代码起作用
  3. 这时再修改配置管理中的配置 image.png
  4. 在浏览器输入访问地址,查看新的配置是否起作用

image.png

1.2.2.方式二

使用@ConfigurationProperties注解代替@Value注解。

  1. 去掉UserController上@RefreshScope注解和@Value注解
  2. 在user-service服务的config包中添加PatternProperties类
    1. 添加@Component注解
    2. 添加@ConfigurationProperties(prefix = “pattern”)注解
    3. 添加String dateformat属性
  1. package cn.itcast.user.config;
  2. import lombok.Data;
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4. import org.springframework.stereotype.Component;
  5. @Component
  6. @Data
  7. @ConfigurationProperties(prefix = "pattern")
  8. public class PatternProperties {
  9. private String dateformat;
  10. }

注:如果出现红色警告,在user-service的pom.xml中添加以下依赖即可

image.png

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-configuration-processor</artifactId>
  4. </dependency>
  1. 在UserController中使用这个类,并且使用@Autowired注入

image.png

  1. 完整代码:
  1. package cn.itcast.user.web;
  2. import cn.itcast.user.config.PatternProperties;
  3. import cn.itcast.user.pojo.User;
  4. import cn.itcast.user.service.UserService;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.PathVariable;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11. import java.time.LocalDateTime;
  12. import java.time.format.DateTimeFormatter;
  13. @Slf4j
  14. @RestController
  15. @RequestMapping("/user")
  16. public class UserController {
  17. @Autowired
  18. private UserService userService;
  19. @Autowired
  20. private PatternProperties patternProperties;
  21. @GetMapping("now")
  22. public String now(){
  23. return LocalDateTime.now()
  24. .format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
  25. }
  26. }
  1. 重启UserApplication微服务
  2. 再修改nacos的配置
    image.png
  3. 在浏览器查看效果
    image.png

小结:

  1. 配置热更新的两种方式:
  1. @RefreshScope:加在使用@Value注解的类上
  2. 编写配置类@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)添加一个环境共享配置

  1. 我们在nacos中添加一个userservice.yaml文件:

    1. pattern:
    2. envSharedValue: 大家都可以用哦

    image.png

  2. 这时有两个配置文件存在
    image.png

2)在user-service中读取共享配置

  1. 在user-service服务中,修改PatternProperties类,读取新添加的属性:

image.png

  1. 在user-service服务中,修改UserController,添加一个方法,直接返回PatternProperties对象 ```java package cn.itcast.user.web;

@RestController @RequestMapping(“/user”) public class UserController {

  1. @Autowired
  2. private PatternProperties patternProperties;
  3. @GetMapping("/prop")
  4. public PatternProperties prop() {
  5. return patternProperties;
  6. }

}

  1. <a name="2cf7c2d7"></a>
  2. #### 3)运行两个UserApplication,使用不同的profile
  3. 修改UserApplication8082这个启动项,改变其profile值:
  4. ![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)
  5. 注:这个test的profiles是不存在的
  6. ![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)
  7. 这样,UserApplication8081使用的profile是dev,UserApplication8082使用的profile是test。
  8. <a name="ae0fb202"></a>
  9. #### 4) 执行结果
  10. 启动UserApplication和UserApplication2
  11. 访问http://localhost:8081/user/prop,结果:
  12. ![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)
  13. 访问http://localhost:8082/user/prop,结果:
  14. ![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)
  15. 可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值。
  16. 小结:
  17. 如何实现nacos环境配置共享:
  18. 将共享配置属性配置到共享配置文件:不带环境名称的配置文件
  19. <a name="25fe6974"></a>
  20. ### 3. 配置共享的优先级
  21. <a name="7fb9a961"></a>
  22. #### 1. 优先级说明
  23. 当nacos、服务本地同时出现相同属性时,优先级有高低之分:
  24. ![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)
  25. 服务器控制台显示:

Located property source: [BootstrapPropertySource {name=’bootstrapProperties-userservice-dev.yaml,DEFAULT_GROUP’}, BootstrapPropertySource {name=’bootstrapProperties-userservice.yaml,DEFAULT_GROUP’}, BootstrapPropertySource {name=’bootstrapProperties-userservice,DEFAULT_GROUP’}]

  1. <a name="7a718ce6"></a>
  2. #### 2. 演示
  3. 1. 在PatternProperties中添加新的username属性
  4. ```java
  5. @Component
  6. @ConfigurationProperties(prefix = "pattern")
  7. @Data
  8. public class PatternProperties {
  9. private String dateformat;
  10. private String envSharedValue;
  11. private String username;
  12. }
  1. 在application.yml中添加新的username属性,查看浏览器运行效果

    1. pattern:
    2. username: 孙悟空


    image.png

  2. 在userservice.yaml中添加新的username属性,查看浏览器运行效果
    image.png

  3. 在userservice-dev.xml中添加新的username属性,查看浏览器运行效果

image.png
小结
配置文件的优先级顺序:
nacos带有环境名称的配置文件>nacos共享配置文件>本地配置文件

1.4.搭建Nacos集群

1.集群结构图

官方给出的Nacos集群图:

SLB:负载均衡器,负责将我们的请求分发到不同的nacos节点

image.png

其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。

我们计划的集群结构:

image.png
三个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运行不了。

  1. 数据库执行资料中的sql脚本:nacos.sql

2.2.配置Nacos

  1. 创建一个目录名为:nacos-cluster
  2. 进入目录nacos-cluster目录,重新解压安装一份新的nacos
  3. 进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf

image.png

4.然后添加内容,注意:此处的IP是你自己机器的IP地址,不要写成127.0.0.1,否则会导致微服务注册失败

  1. 192.168.132.2:8845
  2. 192.168.132.2:8846
  3. 192.168.132.2:8847

在cmd下使用ipconfig来查看自己的IP地址

image.png

5.然后修改application.properties文件,修改数据库配置。

  1. # mysql的数据库集群
  2. spring.datasource.platform=mysql
  3. # 数据库的数量
  4. db.num=1
  5. # 连接字符串
  6. 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
  7. # 用户名
  8. db.user.0=root
  9. # 密码
  10. db.password.0=root

这里的数据库地址、用户名、密码请根据实际情况配置。

2.3.启动

将nacos改名成nacos1,并且复制两份,分别命名为:nacos2、nacos3

image.png

然后分别修改三个文件夹中的application.properties,大约在21行

nacos1:

  1. server.port=8845

nacos2:

  1. server.port=8846

nacos3:

  1. server.port=8847

然后打开三个cmd窗口,分别启动三个nacos节点,不需要带参数,默认是集群启动方式,也可以双击运行

  1. startup.cmd

看到以下提示表示启动成功

  1. INFO Nacos started successfully in cluster mode. use external storage

2.5.nginx反向代理

  1. 找到课前资料提供的nginx安装包:

image.png

  1. 解压到任意非中文目录下:

image.png

  1. 修改conf/nginx.conf文件,配置如下
    这里使用127.0.0.1不影响
  1. upstream nacos-cluster {
  2. server 127.0.0.1:8845;
  3. server 127.0.0.1:8846;
  4. server 127.0.0.1:8847;
  5. }
  6. server {
  7. listen 80;
  8. server_name localhost;
  9. location /nacos {
  10. proxy_pass http://nacos-cluster;
  11. }
  12. }

粘贴到http元素的内部位置都可以,不用删除以前的server配置

  1. 在命令行下输入:start nginx.exe启动nginx服务器,也可以双击运行,运行后查看任务管理器
    image.png
  2. 在浏览器访问:http://localhost/nacos即可。 image.png
  3. 查看集群管理->节点列表

image.png

2.6. Java代码的修改

  1. 修改userservice服务的bootstrap.yaml文件配置如下:
  1. spring:
  2. cloud:
  3. nacos:
  4. server-addr: localhost:80 # Nacos地址
  1. 在nacos管理页面创建新的配置管理:userservice.yaml文件,同时修改java代码:在PatternProperties里增加属性username image.png
  2. 重新启动UserApplication微服务
  3. 浏览器上访问
    image.png
  4. 就会在mysql的nacos库的config_info表中出现上面的配置信息
    image.png
    注意点:启动Nacos集群服务时,确定启动IP是否本机IP地址,如果启动的服务地址是虚拟机IP地址,需要关闭虚拟网卡