中间件(一)之Nacos的介绍及应用

目录

  • 一、Nacos介绍
    • 1、nacos文档说明
    • 2、nacos注解说明
  • 二、Nacos的安装
    • 1、下载安装包
    • 2、安装与启动
  • 三、Nacos的应用
    • 1、Nacos Spring
    • 2、Nacos SpringBoot
    • 3、Nacos SpringCloud
  • 四、实现Nacos与Dubbo结合
    • 1、指定命名空间及组名
    • 2、结合dubbo应用
  • 五、注册服务的迁移
    • 1、迁移方案
    • 2、Nacos Sync 介绍

一、Nacos介绍

1、nacos文档说明

Nacos官方文档地址: https://nacos.io/zh-cn/docs/what-is-nacos.html

(1)nacos 不仅是注册中心,也是配置中心;目前几乎支持所有主流类型的“服务”的发现、配置和管理,如: Kubernetes Service(K8s)、gRPC、 Dubbo RPC Service和Spring Cloud RESTful Service

(2)Nacos提供基于DNS和基于RPC的服务发现,即能被用来支持https/http的服务注册与发现;也支持RPC,如dubbo的服务注册与发现。

(3)与dubbo使用的zookeeper相比,两者差异较大。zookeeper是一种分布式的协调服务,天生作为分布式数据一致性场景下的解决方案,故zookeeper是CP原则,牺牲可用性,保证一致性;在极端情况下(master选举期间)服务会对外停止。Nacos是一种去中心化的框架,属于CAP理论中的AP架构,支持最终一致性,在分布式服务发现与注册具有很好的性能。
注:zookeeper满足CP原则,在进行数据同步时,因一致性要求(Leader-Follower),不允许客户端读写,程序阻塞。

(4)CAP原则:指的是分布式系统中,一致性(C)、可用性(A)、分区容错性( P );三个要素同时最多实现两点,不可能三者兼得。
一致性:在分布式系统中所有数据备份,在同一时刻是否同样的值。
可用性:在集群中一部分节点故障后,整体能否响应客户端的读写请求。(对数据更新具有高可用性)
分区容错性:系统如果不能在时限内达成数据一致性,则意味着发生了分区的情况,必须就当前操作在C和A之间做选择。

(5)动态配置服务:动态修改配置并实时生效,消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷,适合于“配置优先”的服务开发。

(6)保护阈(yu)值:可以设置0-1之间的浮点数,其实是个比例值(当前服务健康实例数/当前服务总实例数);意义至于,当服务健康实例数/总实例数 < 保护阈值,说明健康的实例数不多了,这时候会触发保护阈值状态为true,那么nacos会把所有(健康+不健康的)实例全部提供给消费者;消费者可能会访问到不健康的实例从而请求失败,但比造成雪崩要好,牺牲部分请求,保证了整个系统可用。

2、nacos注解说明

常用的注解:https://nacos.io/zh-cn/docs/open-api.html

(1)nacos-spring
   ① @EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = “127.0.0.1:8848”)) :注解启用 Nacos Spring 的配置管理服务。
   ② @EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = “127.0.0.1:8848”)) :注解开启 Nacos Spring 的服务发现功能。
   ③ @Configuration:配置spring并启动spring容器

(2)nacos-spring 和nacos-springboot
   ① @NacosPropertySource(dataId = “example”, autoRefreshed = true):配置属性值,以dataId和groupId划分维度; autoRefreshed表示数据被更改后是否自动刷新。
   ② @NacosValue(value = “${useLocalCache:false}”, autoRefreshed = true):设置属性值,表示可自动刷新。
   ③ @NacosInjected:用于注入 Nacos 的 NamingService 实例。

(3)nacos-springcloud
   ① @RefreshScope:实现配置自动更新;此注解需放在有@Value注解的类上
   ② @EnableDiscoveryClient:开启服务注册发现功能

二、Nacos的安装

1、下载安装包

(1)多版本下载列表:https://github.com/alibaba/nacos/releases

(2)Linux下载:wget https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.tar.gz

(3)可通过F12查看具体下载地址,如下图(zip是Windows版本,tar.gz是Linux版本)
中间件(一)之Nacos的介绍及应用_第1张图片

2、安装与启动

(1)解压
   tar -zxvf nacos-server-2.0.3.tar.gz

(2)可移动到指定的目录
   mv nacos /app

可能遇到的问题:
移动无权限:mv: cannot move ‘nacos’ to ‘/app/nacos’: Permission denied
解决:chmod -R 777 /app
① -R是目录下所有文件
② r(Read,读取,权限值为4):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目 录的权限。
③ w(Write,写入,权限值为2):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。
④ x(eXecute,执行,权限值为1):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。

(3)进入bin
   cd /app/nacos/bin

(4)单机模式启动(默认是集群启动)
   sh startup.sh -m standalone

① 问题:ERROR: Please set the JAVA_HOME variable in your environment, We
need java(x64)! jdk8 or later is better! !!
② 解决:在服务器中安装JDK1.8

(5)默认访问模板
默认模板:http://ip:8848/nacos/index.html
请求地址:http://127.0.0.1:8848/nacos/index.html
管理账户: nacos / nacos

(6)登录界面
   ① 命名空间:常用于对不同环境的配置区分隔离;不同命名空间,可以有相同的Group和Data ID的配置。
   ② 配置管理:一个配置文件通常就是一个配置集;配置集由Data ID和Group划分维度,通常Data ID以类包的命名规则保证唯一性,Group在Data ID相同的情况下,用于区分不同的配置。
中间件(一)之Nacos的介绍及应用_第2张图片

三、Nacos的应用

注:查看版本的地址:https://mvnrepository.com/artifact/groupId(如:com.alibaba.nacos)/artifactId(如:nacos-spring-context)

1、Nacos Spring

(1)pom.xml 配置

<dependency>
    <groupId>com.alibaba.nacosgroupId>
    <artifactId>nacos-spring-contextartifactId>
    <version>1.1.1version>
dependency>
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>4.3.7.RELEASEversion>
dependency>
<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>3.1.0version>
dependency>

(2)nacos的配置类(在com.lyb下,需要用到nacos配置的类,必须是同级包或其子包下,亦或者需要用此配置的需指定扫描到它)

@Configuration
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848")) // 启动配置管理
@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848")) // 启动服务发现与注册
@NacosPropertySource(dataId = “example”, autoRefreshed = true) // 配置管理使用的
public class NacosConfiguration {
}

(3)控制层(在com.lyb.controller包下,必须是配置类的子包或同级包)

// ① 获取配置控制层
@Controller
@RequestMapping("config")
public class NacosConfigController {
    @NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
    private boolean useLocalCache;
	
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    @ResponseBody
    public boolean get() {
        return useLocalCache;
    }
}
// ② 服务发现控制层
@Controller
@RequestMapping("discovery")
public class NacosDiscoveryController {
    @NacosInjected
    private NamingService namingService;

    @RequestMapping(value = "/get", method = RequestMethod.GET)
    @ResponseBody
    public List<Instance> get(@RequestParam String serviceName) throws NacosException {
        return namingService.getAllInstances(serviceName);
    }
}

(4)spring-mvc配置



<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    <context:component-scan base-package="com.lyb" />
    
    <mvc:annotation-driven />
    
    <context:annotation-config />
beans>

(5)发布
① 发布配置
curl -X POST “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP&content=useLocalCache=true”

② 注册实例
curl -X POST “http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=example&ip=127.0.0.1&port=8080”

2、Nacos SpringBoot

注:0.2.x.RELEASE版本:https://mvnrepository.com/artifact/com.alibaba.boot/nacos-config-spring-boot-starter

(1)pom.xml配置

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.3.9.RELEASEversion>
    <relativePath/> 
parent>

<dependencies>
    <dependency>
       <groupId>org.springframework.bootgroupId>
       <artifactId>spring-boot-starter-webartifactId>
   dependency>
   
   <dependency>
       <groupId>com.alibaba.bootgroupId>
       <artifactId>nacos-config-spring-boot-starterartifactId>
       <version>0.2.3version>
    dependency>
    
    <dependency>
        <groupId>com.alibaba.bootgroupId>
        <artifactId>nacos-discovery-spring-boot-starterartifactId>
        <version>0.2.3version>
    dependency>
dependencies>

(2)Spring Boot的启动类Application,在com.lyb包下

@SpringBootApplication
@NacosPropertySource(dataId = "example", autoRefreshed = true)
public class NacosSpringBootProviderMain implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(NacosSpringBootProviderMain.class, args);
    }

    // 应用名,可配置文件配置,默认: name:nacos-springboot-provider
    @Value("${spring.application.name:nacos-springboot-provider}")
    private String applicationName;

    @NacosInjected
    private NamingService namingService;

    @Override
    public void run(String... args) throws Exception {
        // 通过NamingService服务注册实例到注册中心(参数可用配置方式,提供外部访问的本地服务的ip和端口号)
        namingService.registerInstance(applicationName, "192.168.50.118", 8040);
    }
}

(3)控制层,在com.lyb.controller包下

// 获取配置管理的参数(与Nacos Spring相似)
@Controller
@RequestMapping("config")
public class NacosConfigController {

    @NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
    private boolean useLocalCache;
    
    public void setUseLocalCache(boolean useLocalCache) {
        this.useLocalCache = useLocalCache;
    }

    @RequestMapping(value = "/get", method = RequestMethod.GET)
    @ResponseBody
    public boolean get() {
        return useLocalCache;
    }
}
// 获取发布的服务
@Controller
@RequestMapping("discovery")
public class NacosDiscoveryController {
    @Resource
    private RestTemplate restTemplate;

    @NacosInjected
    private NamingService namingService;
	
    @RequestMapping(value = "/getAll", method = RequestMethod.GET)
    @ResponseBody
    public List<Instance> get(@RequestParam String serviceName) throws NacosException {
        return namingService.getAllInstances(serviceName);
    }
	
    @RequestMapping("/get")
    @ResponseBody
    public String getInfoByService(@RequestParam String name) throws Exception {
        // 根据服务名从注册中心获取一个健康的服务实例
        Instance instance = namingService.selectOneHealthyInstance("nacos-springboot-provider");
        String url = String.format("http://%s:%d/discovery/hello?name=%s", instance.getIp(), instance.getPort(), name);
        String result = restTemplate.getForObject(url, String.class);
        return String.format("消费者请求url:%s ;调用结果:%s", url, result);
    }
}

(4)application.properties的配置

# 应用名称
spring.application.name=nacos-springboot-provider
# 端口号
server.port=8040
# 启动配置管理
nacos.config.server-addr=127.0.0.1:8848
# 启动服务发现
nacos.discovery.server-addr=127.0.0.1:8848
# 命名空间,对于相同的data ID和groupId时,常用于区分测试和生产。默认nacos.config.namespace = public
# nacos.config.namespace=test

(5)启动测试
① cmd命令-> 配置管理:发布配置和获取配置
curl -X POST “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP&content=useLocalCache=true”
curl -X GET “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP”

② cmd命令-> 启动服务:注册实例和查询服务
curl -X POST “http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=example&ip=127.0.0.1&port=8040”
curl -X GET “http://127.0.0.1:8848/nacos/v1/ns/service?serviceName=example”

③ 启动程序(通过发布配置和注册实例,获取参数最新值和服务)
http://localhost:8040/config/get
http://localhost:8040/discovery/get?serviceName= nacos-springboot-provider

3、Nacos SpringCloud

(1)pom.xml 配置说明

注:pom.xml:版本说明:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
经测试,2.2.7. RELEASE版本有问题,无法实现获取配置的参数,其它版本正常。

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.3.9.RELEASEversion>
    <relativePath/> 
parent>
<!– 版本管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-alibaba-dependenciesartifactId>
            <version>2.2.6.RELEASEversion>
            <type>pomtype>
             <scope>importscope>
        dependency>
    dependencies>
dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
        <version>2.2.6.RELEASEversion>
    dependency>
    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        <version>2.2.6.RELEASEversion>
    dependency>
dependencies>

(2)启动类(在com.lyb包下)

@SpringBootApplication
@EnableDiscoveryClient //开启服务注册发现功能
public class NacosSpringCloudApplication {
    ......
    @LoadBalanced // 消费者项目使用,用于访问提供者
    @Bean
    public RestTemplate restTemplate() {return new RestTemplate();}
}

(3)控制层(在com.lyb.controller包下):消费者和提供者参数获取方式相同

@RestController
@RequestMapping("config")
@RefreshScope
public class NacosConfigController {
    @Value("${useLocalCache:false}")
    private boolean useLocalCache;

    @RequestMapping("/get")
    public boolean get() {
        return useLocalCache;
    }
}

(4)服务提供者和服务消费者

// ① 生产者提供一个请求接口,如: http://nacos-springcloud-provider/echo/string (string可变参数)
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
public String echo(@PathVariable String string) {
       returnHelloNacos Discovery+ string;
}

// ② 消费者使用提供的请求接口,外部请求消费者:http://192.168.50.118:8070/echo/string
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
public String echo(@PathVariable String str) {
       return restTemplate.getForObject(" http://nacos-springcloud-provider/echo /" + str, String.class);
}

(5)项目属性配置
① bootstrap.properties

# 发布配置和获取配置地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

注:配置管理需要放置文件bootstrap.properties内,不然无法生效参数发布和获取。解决办法,可以引入下列依赖:

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>

② application.properties

# 服务注册地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 服务应用名
spring.application.name=nacos-service-provider

③ 发布和获取配置属性的Data ID 的命名规范,如下:
p r e f i x − {prefix}- prefix{spring.profiles.active}. f i l e − e x t e n s i o n ( 1 ) p r e f i x 默 认 为 s p r i n g . a p p l i c a t i o n . n a m e 的 值 , 也 可 以 通 过 配 置 项 s p r i n g . c l o u d . n a c o s . c o n f i g . p r e f i x 来 配 置 ( 2 ) s p r i n g . p r o f i l e s . a c t i v e 即 为 当 前 环 境 对 应 的 p r o f i l e ; 当 s p r i n g . p r o f i l e s . a c t i v e 为 空 时 , 对 应 的 连 接 符 − 也 将 不 存 在 , 即 : {file-extension} (1) prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置 (2) spring.profiles.active 即为当前环境对应的 profile;当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,即: fileextension(1)prefixspring.application.namespring.cloud.nacos.config.prefix(2)spring.profiles.activeprofilespring.profiles.active{prefix}.${file-extension}
(3) file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和yaml 类型

发布配置属性: curl -X POST “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos-springcloud-consumer.properties&group=DEFAULT_GROUP&content=useLocalCache=true”

四、实现Nacos与Dubbo结合

1、指定命名空间及组名

# 实现dubbo的服务分组和使用不同的命令空间,dubbo的配置
dubbo.registry.address=nacos://127.0.0.1:8848?namespace=test&group=test

2、结合dubbo应用

(1)nacos + spring + dubbo

注:dubbo2.7.7版本不支持,需升级到2.7.8及以上


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubboartifactId>
    <version>2.7.8version>
dependency>
<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-registry-nacosartifactId>
    <version>2.7.8version>
dependency>
<!– 未用到配置管理,和服务注册和发现时,可选 -->
<dependency>
    <groupId>com.alibaba.nacosgroupId>
    <artifactId>nacos-spring-contextartifactId>
    <version>1.1.1version>
dependency>

(2)nacos + springboot + dubbo


<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-spring-boot-starterartifactId>
    <version>2.7.8version>
dependency>
<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubboartifactId>
    <version>2.7.8version>
dependency>
<dependency>
    <groupId>org.apache.dubbogroupId>
    <artifactId>dubbo-registry-nacosartifactId>
    <version>2.7.8version>
dependency>
<dependency>
    <groupId>com.alibaba.nacosgroupId>
    <artifactId>nacos-clientartifactId>
    <version>1.4.0version>
dependency>

<dependency>
    <groupId>com.alibaba.springgroupId>
    <artifactId>spring-context-supportartifactId>
    <version>1.0.9version>
dependency>

(3)nacos + springboot的dubbo配置

dubbo.protocol.name=dubbo
# 表示 dubbo 自动扫描并使用可用端口(从20880开始递增),避免了端口冲突的问题
dubbo.protocol.port=-1
dubbo.registry.address=nacos://127.0.0.1:8848
dubbo.application.name=dubbo-nacos-springboot-provider
dubbo.consumer.check=false

五、注册服务的迁移

1、迁移方案

(1)如果注册服务中间件用的是zookeeper的迁移方案
① 改造 dubbo 应用,将服务注册改为双注册(同时注册到 zookeeper 与 nacos),等所有应用改造完成后再统一切换到 nacos;

② 使用迁移工具,将 zookeeper 上注册的服务统一迁移到 nacos,然后慢慢修改应用,不必等完全迁移完即可享受 nacos 带来的新特性。

③ 方案区别
方案一:影响较大,需要多所有应用到zk的项目同时启动一遍,而且启动过程中会存在读取不到服务的情况,目前不考虑这种方案
方案二:需要用到nacos 提供了nacosSync同步工具,影响较小,需要对nacosSync迁移工具的同步策略做好规划。

2、Nacos Sync 介绍

(1)nacosSync 是一个支持多种注册中心的同步组件,基于 SpringBoot 开发框架;

(2)nacosSync可实现从 zookeeper 到 nacos 的双向同步功能,但双向同步可能有风险,新加的nacos不能保证稳定性,若出现数据有误,则同步到zookeeper上会带来故障。所以可以采取比较保守的 zookeeper 到 nacos 的单向同步策略。

你可能感兴趣的:(中间件,中间件,java,分布式)