服务注册与发现:Nacos

为什么需要服务注册与发现

假设 mafeng-user 用户微服务部署了多个实例(组成集群模式),如下图所示:

会出现以下几个问题:

  • mafeng-order订单微服务发出Http远程调用时,该如何得知mafeng-user实例的IP和端口呢?
  • 在多个mafeng-user实例的情况下,mafeng-order该选择哪个实例进行调用呢?
  • mafeng-order如何得知mafeng-user实例状态是否健康?

微服务架构出现的以上问题, Spring Cloud 框架引入了 服务注册与发现 组件把这些问题很好地解决了!
在 Spring Cloud 框架里面,我们不止只有一种 服务注册与发现 组件,而是有四种比较常用的组件:

  • Eureka
  • Zookeeper
  • Consul
  • Nacos

Nacos 简介

Nacos 是 Alibaba 开发的是用于微服务管理的平台,其核心功能是服务注册与发现、集中配置管理。有了之前的一系列相关的技术的学习,Nacos 学习和使用起来就简单多了。

  • Nacos作为 服务注册发现 组件,可以替换Spring Cloud应用中传统的服务注册于发现组件,如:
  • Eureka、Zookeeper、Consul等,支持服务的健康检查。
  • Nacos作为服务配置中心,可以替换Apollo、Spring Cloud Config和Bus。
    官网: https://nacos.io/

    当然, Nacos 作为一个微服务管理平台,除了面向 Spring Cloud ,还支持很多其他的微服务基础设施,
    如: Docker 、 Dubbo 、 kubernetes 等。除了核心的服务注册与发现和配置管理功能,还提供了各种服
    务管理的功能特性,如:动态 DNS 、服务元数据管理等。
    所以当你的微服务架构为了维护众多的独立部署的基础组件而烦恼的时候, Nacos 可以在一定程度上解决你的烦恼。

搭建Nacos单机

WIndow****方式启动

下载 nacos 压缩包

  • nacos-server-2.1.1.zip

解压进入 bin 目录执行

  • startup.cmd -m standalone
    如下图效果,代表启动完成

    浏览器访问
    http://localhost:8848/nacos

    账户密码默认为nacos。

Docker 方式启动

拉取nacos最新镜像

docker pull nacos/nacos-server:2.0.3

创建容器
docker run --env MODE=standalone --restart=always --name nacos -d -p 8848:8848 - p 9848:9848 -p 9849:9849 nacos/nacos-server:2.0.3
注意: Nacos2.0版本相比1.X新增了gRPC的通信方式,因此需要增加2个端口:9848、9849 Nacos官网 | Nacos 官方社区 | Nacos 下载 | Nacos

|--------|-------------------|---------------------------------|
| 端口 | 与主端口的偏移 | 描述 |
| 9848 | 1000 | 客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求 |
| 9849 | 1001 | 服务端gRPC请求服务端端口,用于服务间同步等 |

访问:++++http://192.168.66.133:8848/nacos++++ ,同window。

服务注册到 Nacos 单机

mafeng-user和mafeng-order都需要注册到Nacos,步骤相同

导入 nacos 依赖

因为Nacos 属于 SpringCloudAlibaba 体系的组件,所以要单独锁定 ++++spring++++ ++++-++++ ++++cloud++++ ++++-++++ ++++alibaba-++++

++++dependencies++++

在父工程锁定依赖版本:

java 复制代码
<properties>
<springcloud.alibaba.version>2.2.9.RELEASE</springcloud.alibaba.version>
</properties>


<!-- nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${springcloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

以上配置加到dependencyManagement 里面

PS:关于SpringCloudAlibaba的与SpringCloud的版本关系说明:

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E 6%98%8E

在子工程再导入nacos依赖:

java 复制代码
<!-- nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置 yml 连接 nacos

javascript 复制代码
spring: 
    cloud:
        nacos:
            discovery:
                server-addr: 192.168.66.133:8848

注意:这里虽然8848端口,但会自动偏移+1000,真正连接的是gRPC端口:9848。

重启服务,查看 Nacos 客户端

临时实例和持久实例

在服务注册时有一个属性ephemeral 用于描述当前实例在注册时是否以临时实例出现;

  • 为true则为临时实例(默认值);
  • 为false则为持久实例;

临时实例

  • 默认情况,服务实例仅会注册在 Nacos 内存,不会持久化到 Nacos 磁盘 ,其健康检测机制为Client 模式,即Client主动向Server上报其健康状态(类似于推模式);
  • 默认心跳间隔为5秒,在15秒内Server未收到Client心跳,则会将其标记为"不健康"状态;在30秒内若收到了Client心跳,则重新恢复"健康"状态,否则该实例将从Server端内存清除。即对于不健康的实例,Server会自动清除;
  • Nacos的临时实例 选择采用AP模式 ,采用distro协议实现

持久实例

  • 服务实例不仅会注册到 Nacos 内存,同时也会被持久化到 Nacos 磁盘 ,其健康检测机制为Server 模式,即Server会主动去检测Client的健康状态(类似于拉模式);
  • 默认每20秒检测一次,健康检测失败后服务实例会被标记为"不健康"状态,但不会被清除,因为其是持久化在磁盘的,其对不健康持久实例的清除,需要专门进行;
  • Nacos的持久实例 选择采用CP模式 ,采用raft协议实现

应用场景

  • 临时实例:适合于存在突发流量暴增可能 的互联网项目,可以实现弹性扩容,正常生产中的环境就 是这样;
  • 持久实例:用于保护阈值,比如说服务A有100个实例,那么当有98个不可用时:
    • 如果是临时实例,则只会返回两个服务,那么大并发量请求这两个服务肯定会造成雪崩的, 造成整个服务不可用;
  • 如果是持久实例,实例会全部返回,虽然有98个不可用,消费者可能会请求失败,但不至于剩下的两个健康实例崩溃;

Nacos 环境隔离

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

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

创建新的 namespace

服务配置 namespace

修改mafeng-user的namespace,加入dev的namespace

java 复制代码
spring: 
    cloud:
        nacos:
            discovery:
                server-addr: 192.168.66.133:8848 
                ephemeral: true
                namespace: fb99a686-aa07-4ed4-a574-684e1f889189

Nacos 数据持久化

默认存储

默认采用内嵌式数据库 Derby 数据库,数据存放在 /nacos/data/derby-data 目录下:

Nacos的namespace、group、持久实例信息等都会持久化写入Derby数据库。

切换为 MySQL

做小型工程,用Derby数据库还行,但中大型应用更建议使用MySQL。我们尝试切换为MySQL。

1、登录nacos容器:
docker exec -it nacos /bin/bash
2、修改conf/application.properties文件,在最后追加以下内容

java 复制代码
SPRING_DATASOURCE_PLATFORM=mysql 
MYSQL_DATABASE_NUM=1 
MYSQL_SERVICE_HOST=192.168.66.133 
MYSQL_SERVICE_PORT=3306 
MYSQL_SERVICE_DB_NAME=nacos 
MYSQL_SERVICE_USER=root 
MYSQL_SERVICE_PASSWORD=root

3、在mysql导入nacos-mysql.sql

4、重启nacos
docker restart nacos

搭建 Nacos 集群

Nacos集群架构

搭建集群

我们采用docker-compose搭建,过程轻松简单。

1、上传nacos-docker-master到/root目录下

2、查看example/docker-compose.yml文件内容

javascript 复制代码
version: "3.3"
services:
  nacos1:
    hostname: nacos1
    container_name: nacos1
    image: nacos/nacos-server:2.0.3
    volumes:
      - ./cluster-logs/nacos1:/home/nacos/logs
    ports:
      - "8861:8848"
      - "9861:9848"
      - "10555:9555"
    env_file:
      - ../env/nacos-hostname.env
    restart: always
    depends_on:
      - mysql

  nacos2:
    hostname: nacos2
    image: nacos/nacos-server:2.0.3
    container_name: nacos2
    volumes:
      - ./cluster-logs/nacos2:/home/nacos/logs
    ports:
      - "8862:8848"
      - "9862:9848"
    env_file:
      - ../env/nacos-hostname.env
    restart: always
    depends_on:
      - mysql

  nacos3:
    hostname: nacos3
    image: nacos/nacos-server:2.0.3
    container_name: nacos3
    volumes:
      - ./cluster-logs/nacos3:/home/nacos/logs
    ports:
      - "8863:8848"
      - "9863:9848"
    env_file:
      - ../env/nacos-hostname.env
    restart: always
    depends_on:
      - mysql

  mysql:
    container_name: mysql8
    image: nacos/nacos-mysql:8.0.16
    env_file:
      - ../env/mysql.env
    volumes:
      - ./mysql:/var/lib/mysql
    ports:
      - "3307:3306"


  nginx:
    image: nginx:latest
    restart: always
    ports:
      - "8801:80"
    volumes:
      - ../nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ../nginx/conf/conf.d:/etc/nginx/conf.d
      - ../nginx/log:/var/log/nginx
      - ../nginx/html:/usr/share/nginx/html
    container_name: "nginx"
    depends_on:
      - nacos1
      - nacos2
      - nacos3

3、查看nginx/conf/nginx.conf文件内容:

java 复制代码
user  nginx;
worker_processes  auto;
 
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;
 
 
events {
    worker_connections  1024;
}
 
stream
{
    upstream nacos {
        server 192.168.66.133:9861;
        server 192.168.66.133:9862;
        server 192.168.66.133:9863;
    }
 
 
    server {
        listen  80;
        proxy_pass nacos;
    }
}

4、在example根目录下执行
docker-compose up -d
等待所有容器启动

5、访问集群

++++http://192.168.66.133:8861/nacos++++

服务注册到 Nacos 集群

mafeng-user和mafeng-order的Nacos连接地址改为:

java 复制代码
spring: 
    cloud:
        nacos:
            discovery:
                server-addr: 192.168.66.133:7801 # 7801(程序端口)+1000(偏移量)=8801(Nginx端口)

各大注册中心产品的相同点

作为服务注册中心,核心的服务注册功能和发现功能都是一样的。

项目中我们可以统一使用Spring Cloud框架的DiscoveryClient 对象实现服务发现和远程调用, 具体使用哪个注册中心产品是透明的。

各大注册中心产品的核心区别

|---------------|---------------------------|------------|------------|---------------|
| 核心对比 | Nacos( 推荐使用 ) | Eureka | Consul | Zookeeper |
| 一致性协议 | CP或AP | AP | CP | CP |
| 版本迭代 | 迭代升级中 | 不再升级 | 迭代升级中 | 迭代升级中 |
| SpringCloud集成 | 支持 | 支持 | 支持 | 支持 |
| Dubbo集成 | 支持 | 不支持 | 不支持 | 支持 |
| K8S集成 | 支持 | 不支持 | 支持 | 不支持 |

Eureka 优先支持 AP

Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和 查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节

点,只要有一台Eureka还在,就能保证注册服务可用(保证强可用性AP),只不过查到的信息可能不是最 新的(不保证强一致性CP)。

Zookeeper 优先支持 CP

Zookeeper在选举leader时,会停止服务,直到选举成功之后才会再次对外提供服务,这个时候就说明 了服务不可用,但是在选举成功之后,因为一主多从的结构,zookeeper在这时还是一个高可用注册中 心,只是在优先保证一致性的前提下,zookeeper才会顾及到可用性

Consul 优先支持 CP

1、服务注册相比Eureka会稍慢一些。因为Consul的raft协议要求必须过半数的节点都写入成功才认 为注册成功

2、Leader挂掉时,重新选举期间整个consul不可用。保证了强一致性但牺牲了可用性。

Nacos 同时支持 AP CP( 推荐使用 )

Nacos的临时实例 选择采用AP模式 ,采用distro协议实现

Nacos的持久实例 选择采用CP模式 ,采用raft协议实现

相关推荐
憨子周29 分钟前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
涔溪2 小时前
Docker简介
spring cloud·docker·eureka
霖雨2 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
Fiercezm2 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言
ZIM学编程3 小时前
Java基础Day-Sixteen
java·开发语言·windows
我不是星海3 小时前
1.集合体系补充(1)
java·数据结构
P.H. Infinity3 小时前
【RabbitMQ】07-业务幂等处理
java·rabbitmq·java-rabbitmq
爱吃土豆的程序员3 小时前
java XMLStreamConstants.CDATA 无法识别 <![CDATA[]]>
xml·java·cdata