Nacos学习

微服务架构

为了适应企业的业务发展,软件架构现如今也做了升级和优化,将一个独立的系统拆分成若干个小的服务,每个服务都运行在不同的进程中,服务和服务之间采用RESTFul, RPC等协议传输数据,每个服务所拥有的功能具有独立性强的特点,这样的设计实现了服务之间的低耦合、服务内部的高内聚。

服务发现流程

在很多架构中,当微服务很多时,可能会出现A服务调用B服务,B服务调用C服务,C服务调用A服务,从而服务循环;微服务之间的调用需要有各个服务的地址,当某个服务出现升级或宕机的情况,服务实例网址可能会发生变化,因此就需要有服务发现。

服务发现流程引入了一个服务发现中心

  1. 在每个服务启动时会向服务中心上报自己的网络地址,这样在服务发现中心内部会形成一个服务注册表服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库;
  2. 服务发现客户端会定期的从服务中心同步服务注册表,并缓存在客户端;
  3. 当需要对某个服务进行请求时,服务实例通过注册表,定位目标服务网络地址,若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择一个,然后发出请求。

Nacos

目前市面上用得比较多的服务中心有:Nacos、Eureka、Consul 和 Zookeeper

image-20240119101927536

Nacos作为服务中心,相比较其他软件具有更多的功能特性,且从长远角度来看,Nacos会在以后的版本中会支持SpringCloud和Kubernetes的组合,填补两者之间的鸿沟。另外,Nacos计划实现Service Mesh,也是未来微服务发展的趋势。

特性

  • 服务发现与服务健康检查

    Nacos使服务更容易注册,通过DNS和http端口更容易发现其他服务,Nacos提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。

  • 动态配置管理

    动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。消除了在更新配置时重新部署应用程序,这使配置的更改更加高效灵活。

  • 动态DNS服务

    Nacos提供基于DNS协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端口,让三方应用方便的查阅和发现。

  • 服务和元数据管理

    Nacos能让你以微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康检查、服务的流量管理、路由及安全策略。

安装

Nacos依赖Java环境来运行需提前配置JAVA_HOME>1.8+,下载地址:https://github.com/alibaba/nacos/releases

启动服务器:

Nacos的默认端口是8848,需要保证8848端口没有被其他进程占用;

进入安装程序的bin目录,启动命令(standalone代表单机模式运行,cluster代表集群模式):

1
startup.cmd -m standalone

image-20240119104636690

默认用户名/密码:nacos/nacos

简单的使用

在SpringBoot工程中的pom.xml中引入客户端依赖

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

配置application.yml文件

1
2
3
4
5
6
7
spring:
cloud:
nacos:
# nacos服务地址
server-addr: 127.0.0.1:8848
application:
name: xxx-service

请求示范

1
2
3
4
5
6
7
8
9
public Order queryOrderById(Long orderId) {
RestTemplate restTemplate = new RestTemplate();
Order order = orderMapper.findById(orderId);
// 此处user-service为另外一个服务的服务名称
String url = "http://user-service/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}

领域模型

image-20240119105407174

NameSpace:命名空间,默认的NameSpace是public。比如,我们开发,测试环境共用一个nacos,必定我们的接口地址也是不同,而且你在开发过程中,也是不建议随意配置测试环境的,这时我们就应该用namespace来隔离我们的空间。

image-20240119105053186

group:分组。也是用来隔离的,打个比方啊,在系统中有用户服务,订单服务,仓储服务和物流服务四个服务,订单服务中有一个接口叫getData仓储服务中也有一个接口叫getData,我们的用户服务只想调用到我们的订单服务的getData,不想调用到仓储服务的getData,这时我们可以用group分组来隔离
image-20240119105238408

cluster:集群。打个比方,我们现在有两组集群,一组是北京的订单服务集群,北京的商品服务集群,还有一组是南京的订单服务集群,南京的商品服务集群。 我们希望北京的订单集群,优先去调用北京的商品系统,南京的优先调用南京的集群服务。并不希望我们跨地区远程调用(如果组内实在没有服务了,也可以调用,但是优先考虑同一集群的)

image-20240119105510440

Nacos服务分级存储模型

  • 一级是服务,例如userservice
  • 二级是集群,例如杭州或上海
  • 三级是实例,例如杭州机房的某台部署了userservice的服务器

集群配置

spring.cloud.nacos.discovery.cluster-name属性即可

1
2
3
4
5
6
7
8
9
10
spring:
cloud:
nacos:
server-addr: 127.0.0.1:8848
# 服务发现配置
discovery:
# 集群配置
cluster-name: ${cname}
application:
name: user-service

image-20240119105705265

集群负载均衡

在客户端的yml中配置

1
2
3
user-service: # 集群名称
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

更改默认策略规则

配置文件的方式:

1
2
3
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

通过代码的方式

1
2
3
4
5
6
7
8
9
10
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}

@Bean
public IRule randomRule() {
return new RandomRule();
}

统一配置管理

抽取共同的配置交给Nacos管理

image-20240119110941442

  • Data ID:实际上就是配置文件名,可以以 【服务名称-环境.文件后缀名】格式命名

image-20240119110949869

实际上并不是所有的配置都适合放到配置中心,建议将一些关键参数,需要运行时随时可调整的参数放到 nacos 配置中心,一些比较固定的配置则可以放在项目本身的配置文件当中。

服务拉取配置

一个服务如果以 nacos 作为配置中心,则会先拉取 nacos 中管理的配置,然后与本地的配置文件比如 application.yml 中的配置合并,最后作为项目的完整配置,启动项目。

  • 没有nacos管理配置文件的情况下的项目启动流程:

    image-20240119111128049

  • 使用nacos管理配置时项目的启动流程

    image-20240119111159338

项目启动的时候需要提前知道 nacos 的环境信息,而 application.yml 在读取 nacos 配置后才会读取,所以无法把 nacos 的相关信息配置在 application.yml 中,此时我们可以使用 bootstrap.yml文件。bootstrap.ym是一个引导文件,优先级高于application.yml,它会在application.yml之前被读取

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-a libaba-nacos-config</artifactId>
</dependency>

创建bootstart.yml文件,将有关Nacos的配置项以及服务名称都需写进这个文件

1
2
3
4
5
6
7
8
9
10
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】 作为配置的 DATA ID来从配置中心读取配置,也就是读取了 userservice-dev.yaml 配置。

多环境配置共享

实际上微服务启动时,会去 nacos 配置中心读取多个配置文件,也就是不仅仅会读取指定的 profile 的配置文件,还会读取多个环境共享的配置文件。

当 nacos 和项目的本地配置文件中存在相同配置时,优先级如下: 服务名-profile.yaml > 服务名.yaml > 本地配置,如下

image-20240119111801836

配置热更新

默认情况下,修改了 nacos 配置中心的配置,微服务的配置不会随之更新的,需要重启微服务才能读到新配置。

通过 @Value 和通过 @ConfigurationProperties 来读取配置时,实现热更新的方式不同。

RefreshScope

如果是通过 @Value 来读取配置的,此时只需在使用 @Value 注入的变量所在类上添加注解 @RefreshScope 即可,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RefreshScope
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Value("${pattern.dateformat}")
private String dateformat;

@GetMapping("test01")
public String now(){
return dateformat;
}
}
ConfigurationProperties

nacos的坑

安装环节

  1. 解压安装时最好不要有中文路径及空格,否则会报错

启动环节

  1. java.io.IOException: java.lang.IllegalArgumentException: db.num is null

    这个是在集群模式下启动的时候缺少数据库文件,要么单机启动startup.cmd -m standalone,要么加载数据库

    或者编辑startup.cmd文件把其中的set MODE = “cluster” 修改为以下内容(默认集群启动,修改为单机启动)

    1
    2
    rem set MODE="cluster"
    set MODE="standalone"
  2. Java环境需配置JAVA_HOME且大于1.8