Nacos+Node基础教程

2023-10-27

简介

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

功能:

  1. 动态配置服务

动态配置服务让您能够以中心化、外部化和动态化的方式挂历所有环境的配置。动态配置消除了配置变更时,重新部署应用和服务的需要。配置中心化管理让实现无状态服务更简单,也让安旭然性扩展服务更容易。

image-20220725214523587

  1. 服务发现以及管理

    动态服务发现对以服务为中心的(例如微服务和云原生)应用架构方式非常关键。Nacos支持DNS-Based和RPC-Based(Dubbo、gRPC)模式的服务发现。Nacos也提供实施健康检查,以防止将请求发往不健康的主机或服务实例。借助Nacos,您可以更容易的为您的服务实现断路器。

image-20220725214553596

  1. 动态DNS服务

    通过支持权重路由,动态DNS服务能让您轻松实现中间层负载均衡、更灵活的路由策略、流量控制以及简单数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易的实现以DNS协议为基础的服务发现,以消除耦合到厂商私有服务发现API上的风险。

    Nacos中文官方站点:

    https://nacos.io/zh-cn/

教程中涉及的代码,在文章末位有提供下载;

安装

Nacos Server依赖于java环境运行,jdk用1.8以上;

安装:

https://nacos.io/zh-cn/docs/quick-start.html

快速安装

  • 默认启动是集群方式,我们修改 /nacos/bin/startup.cmd,默认配置 set MODE="cluster",修改成单实例模式:set MODE="standalone"

image-20220725220927318

  • 打开 nacos/conf/application.properties,查看启动端口是:8848,启动路径是:/nacos

image-20220725221002064

  • 双击/nacos/bin/startup.cmd,启动时间可能比较长,耐心等待,看到下面的界面说明启动成功!如下:

    image-20220726002332350image-20220726003214199

  • 访问:localhost:8848/nacos,账号密码默认:nacos/nacos

    image-20220726003401889image-20220726003636071

启动时可能会遇到 秒退 的情况,可能是没有安装JDK包,这种情况先移步安装JDK,完了再启动。

安装JDK-window(装了则跳过)

  1. 下载JDK,下载地址

  2. 配置环境变量

    # 我的电脑属性 > 高级属性设置 > 高级 > 环境变量 > 系统变量
    # 主要设置以下项目:
    CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar
    JAVA_HOME=C:\Program Files\Java\jdk1.8.0_341
    PATH 新增三个 %JAVA_HOME%\bin  %JAVA_HOME%\jre\bin  %CLASSPATH%
    
  3. 验证

    cmd打开命令行,输入java -versionjavac -version,打印如下,说明安装成功;

    image-20220726001417162

配置mysql

nacos默认使用内嵌的文件存储数据,这里改成连接到mysql,需要做以下配置;

image-20220726224436278

db_nacos:是对应的数据库

打开数据库,修改user表中username=nacos123,然后进入localhost:8848/nacos,使用nacos123/nacos登录,如果登录成功!说明整个配置就成功了!

image-20220726225536296

image-20220726225516844

Nacos统一配置中心

spring-cloud-alibaba 版本说明

配置

新增配置

打开 配置管理 > 配置列表 > 添加,内容如下:

Data Id:
	nacos_config_properties

配置内容:
 {
     "name": "feiniu",
     "age": "23"
 }

点击发布!

获取配置

Nacos数据模型Key由三元组唯一确定,Namespace默认是空串,公共命名空间(public),分组默认是DEFAULT_GROUP。

image-20220727003845197

  1. 创建一个express项目

    #全局安装工具包
    npm install -g express
    npm install -g express-generator
    
    # 创建site项目
    express site
    
    #进入项目,安装初始化依赖包
    npm i
    
  2. 创建/nacos/getConfigInfo接口

    routes目录中创建nacos.js文件,代码如下:

    var express = require('express');
    var router = express.Router();
    
    router.get(/(\/|\/getConfigInfo)/, function (req, res, next) {
      let user = {
        name: "feiniu",
        age: "23"
      };
      res.send(`${user.name}:${user.age}`);
    });
    
    module.exports = router;
    
  3. 启动项目

    npm run start
    

    访问localhost:3000/nacos/getConfigInfo,看到界面如下:

    image-20220727000252876

    说明路由配置成功!

  4. 安装nacos+ip依赖

    npm i nacos ip
    
  5. 获取配置信息

    nacos.js代码修改如下:

    var express = require('express');
    var router = express.Router();
    
    router.get("/", function (req, res, next) {
    
      //nacos获取和监听相关代码 start
      const NacosConfigClient = require('nacos').NacosConfigClient;
      // nacos服务地址
      const nacosServerAddress = 'localhost:8848';
      // namespace: 名称空间必须在服务器上存在
      const providerNamespase = 'public';
      // 名称空间下的Group
      const group = 'DEFAULT_GROUP'
      // 命名空间下的Data Id
      const dataId = 'nacos_config_properties'
      // for direct mode
      const configClient = new NacosConfigClient({
        serverAddr: nacosServerAddress,
        namespace: providerNamespase,
      });
    
      // 获取nacos配置
      (async () => {
        const content1 = await configClient.getConfig(dataId, group);
        console.log('[Nacos] 获取配置: ', content1);
    
      })()
    
      // 监听远程nacos配置变化
      configClient.subscribe({
        dataId: dataId,
        group: group,
      }, content => {
        console.log('[Nacos] 监听远程nacos配置:', content);
      });
      //nacos获取和监听相关代码 end
    
      let user = {
        name: "feiniu",
        age: "23"
      };
      res.send(`${user.name}:${user.age}`);
    });
    
    module.exports = router;
    

    启动

    • 后台服务打印如下:

    image-20220727001611339

    • 修改nacos中age为24,并发布:

    image-20220727001657070

    • 后端控制台监听到nacos配置中的修改,打印内容:

    image-20220727001748892

取消配置监听

let listener=content => {
  console.log('[Nacos] 监听远程nacos配置:', content);
}
// 监听远程nacos配置变化
router.get("/subscribe", async (req, res, next) => {
  let r = await configClientDirect.subscribe({
    dataId: dataId,
    group: group,
  }, listener);
  res.send(r);
});
// 取消监听
router.get("/unSubscribe", async (req, res, next) => {
  let r = await configClientDirect.unSubscribe({
    dataId: dataId,
    group: group,
  }, listener);
  res.send(r);
});
  • 创建监听的时候需要判断是否重复监听,如果出现重复监听,那么后端配置在修改后,会触发多次listener

image-20220807152656573

  • 取消监听时,unSubscribe(info, [listener])[listener]如果不传值,则会取消此服务下的所有监听;如果入参则会取消指定的listener

修改配置

//直连模式
const configClientDirect = new NacosConfigClient({
  serverAddr: nacosServerAddress,
  namespace: providerNamespase,
});

router.get("/publish", async function (req, res, next) {
  const content = await configClientDirect.publishSingle("nacos_config_properties", 'DEFAULT_GROUP', '测试');
  console.log('getConfig = ', content);
  res.send("publish");
});

删除配置

// 删除配置
router.get("/remove", async function (req, res, next) {
  (async () => {
    const content = await configClientDirect.remove("test", group);
    console.log('[Nacos] 删除配置: ', content);
    res.send(content);
  })()
});

服务

创建不同命令空间

  • 创建一个dev命令空间,然后在里面同样创建一个nacos_config_properties配置项,内容为:
{
    "name":"feiniu",
    "age":88
}
  • 修改nacos.js中命名空间配置:

    //使用命名空间id
    const providerNamespase = 'cceb082a-e2cc-4210-886a-7491937c1df6';
    

    image-20220727005023514

  • 再次访问localhost:3000/nacos,后端服务控制台打印最新内容如下:

image-20220727004820325

注册服务

nacos.js中添加services路由,新增注册服务逻辑

router.get("/services", function (req, res, next) {
  // 注册服务到Nacos服务器
  const {
    NacosNamingClient,
  } = require('nacos');

  const {
    address,
  } = require('ip');
  const logger = console

  // 动态获取本机 IP 地址
  const ipAddr = address();
  // 我们当前app1应用的端口号
  const port = 3001

  // 服务名称,后面消费方调用的时候通过这个服务名进行服务查询。
  const providerServiceName = 'nacos-services-user';
  // nacos服务地址
  const nacosServerAddress = 'localhost:8848';
  // namespace: 命名空间必须在服务器上存在
  const providerNamespase = 'cceb082a-e2cc-4210-886a-7491937c1df6';
  const client = new NacosNamingClient({
    logger,
    serverList: nacosServerAddress,
    namespace: providerNamespase,
  });
  console.log('[Nacos] 注册Nacos服务',);
  (async () => {
    const allinstance = await client.getAllInstances()
    console.log('[Nacos]----allinstance----', allinstance)
  });
  (async () => {
    try {
      await client.ready();
      // 注册服务和实例
      await client.registerInstance(providerServiceName, {
        ip: ipAddr,
        port
      });
      // 这里也可以传入group,不传默认就是 DEFAULT_GROUP
      // const groupName = 'nodejs';
      // await client.registerInstance(providerServiceName, {
      // ip: ipAddr,
      // port
      // }, groupName);
      console.log(`[Nacos] Nacos服务注册实例成功: ${ipAddr}:${port}`);
    } catch (err) {
      console.log('[Nacos] Nacos服务注册实例失败: ' + err.toString());
    }
  })();

  res.send(`services`);

})

访问localhost:3000/nacos/services

页面正常显示:

image-20220727215421693

后台控制台打印如下:

image-20220727215512236

nacos服务列表中出现一条nacos-services-user服务:

image-20220727215720536

说明服务已经注册成功!

获取服务信息

新建路由文件service.js文件,创建/app1/app2/getAllInstances三个接口,app1、app2用来注册服务,getAllInstances用来拉取服务;

app.js中注册路由:

var serviceRouter = require('./routes/service');
app.use('/service', serviceRouter);

service.js代码如下:

var express = require('express');
var router = express.Router();
// nacos相关
const { NacosNamingClient, } = require('nacos');
const { address } = require('ip');
// 动态获取本机 IP 地址
const ipAddr = address();
// 我们当前app1应用的端口号
const port = 9900
const logger = console
// 服务名称,后面消费方调用的时候通过这个服务名进行服务查询。
const providerServiceName = 'edsp-component-app1';
// nacos服务地址
const nacosServerAddress = 'localhost:8848';
// namespace: 命名空间必须在服务器上存在
const providerNamespase = 'cceb082a-e2cc-4210-886a-7491937c1df6';

// 注册服务到Nacos服务器
const client = new NacosNamingClient({
  logger,
  serverList: nacosServerAddress,
  namespace: providerNamespase,
});

// 注册app1
router.get('/app1', function (req, res, next) {
  (async () => {
    try {
      await client.ready();
      // 注册服务和实例
      await client.registerInstance(providerServiceName, {
        ip: ipAddr,
        port:9000,
        metadata: {
          componentName: 'vue-app1',
          address: `${ipAddr}:${port}/app1.js`
        }
      });
      console.log(`[Nacos] Nacos服务实例注册成功: ${ipAddr}:${port}`);
    } catch (err) {
      console.log('[Nacos] Nacos服务实例注册失败: ' + err.toString());
    }
  })();
  res.send("success app1");
});

// 注册app2
router.get('/app2', function (req, res, next) {
  (async () => {
    try {
      await client.ready();
      // 注册服务和实例
      await client.registerInstance(providerServiceName, {
        ip: ipAddr,
        port:9001,
        metadata: {
          componentName: 'vue-app2',
          address: `${ipAddr}:${port}/app2.js`
        }
      });
      console.log(`[Nacos] Nacos服务实例注册成功: ${ipAddr}:${port}`);
    } catch (err) {
      console.log('[Nacos] Nacos服务实例注册失败: ' + err.toString());
    }
  })();
  res.send("success app2");
});

// 获取 getAllInstances
router.get('/getAllInstances', async function (req, res, next) {
  let allInstances = await client.getAllInstances(providerServiceName, 'DEFAULT_GROUP', 'DEFAULT', false)
  res.send(allInstances);
});

module.exports = router;

分别访问:

  1. http://localhost:3000/service/app1

    image-20220729002824507

  2. http://localhost:3000/service/app2

    image-20220729002835762

  3. http://localhost:3000/service/getAllInstances

    image-20220729002856546

    network请求返回数据:

    image-20220729002954569

    nacos服务列表中显示:

    image-20220729003057902

    image-20220729003046012

注销服务

router.get("/deregisterInstance", async function (req, res, next) {
  await client.deregisterInstance(providerServiceName, {
    ip: ipAddr,
    port: 9000,
  });
  res.send("注销");
});

获取服务状态

返回 ‘UP’ or ‘DOWN’。

// 获取服务状态
router.get("/getServerStatus", async function (req, res, next) {
  let r=await client.getServerStatus(providerServiceName, {
    ip: ipAddr,
    port: 9000,
  });
  res.send(r);
});

监听和取消监听

let listener = hosts => {
  console.log(hosts);
}
// 监听服务
router.get("/subscribe", async function (req, res, next) {
  let r = await client.subscribe(providerServiceName, listener);
  res.send(r);
});

// 取消监听服务
router.get("/unSubscribe", async function (req, res, next) {
  let r = await client.unSubscribe(providerServiceName, listener);
  res.send(r);
});

负载均衡

// 待整理

应用场景

数据库连接信息

限流阈值和降级开关

流量的动态调度

推荐阅读:

【微前端实践】: webpack5 + Node.js+ Nacos 搭建微前端应用网络
上述案例源码地址:本教程源码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Nacos+Node基础教程 的相关文章

  • java引用ScriptEngine解析表达式实现计算器功能

    包名 import javax script 使用 String str 2 6 7 ScriptEngine se new ScriptEngineManager getEngineByName JavaScript try double
  • 大数据技术原理与应用(复习)

    大数据 第一章 大数据的四个基本特性 p8 4V 数据量大 Volume 数据类型繁多 Variety 处理速度快 Velocity 价值密度低 Value 举例说明大数据的关键技术 p16 数据采集与预处理 利用ETL工具将分布在异构数据
  • Python123题目解析

    老样子 复习第一位 持续更新 慢慢附加知识点 python123 英寸和厘米的交互 升级版 描述 虽然我国已经很好的普及了国际单位制 而在现实生活中 仍然有很多地方采用了英制单位来描述 例如 我们买一台65寸的电视 这个地方的寸指的就是英寸
  • 编写测试用例的测试方法(等价类、判定表、边界值、正交排列法、场景法)

    一 等价类划分法 1 应用场合 在程序中 有数据输入的地方适合使用等价类划分法进行测试 方法思想 范围 将大量数据划分成若干的范围 等价类 再从每个范围中抽取少量代表数据进行测试 抽样测试 2 两个概念 1 有效等价类 对程序来说 正确的
  • Gerrit合并分支cherry-pick后提交代码push报错,43366 closed问题处理

    Gerrit合并分支cherry pick后提交代码push报错 43366 closed问题处理 这个问题是我cherry pick别的分支代码时遇到的 至于如何cherry pick代码可以参考 链接 如何cherry pick分支代码
  • html字符串转json

    业务场景 后端返回给前端的数据中 有html格式的字符串 如下 font color red 我是提示信息 font 后端使用fastjson data toJsonString 响应给前端 但是格式不是标准的json格式 如 msg fo

随机推荐

  • Qt 的信号与槽

    QT的信号与槽的三种实现方式 3种方式 1 直接在设计选项卡中拖动连接控件 然后选择控件间的关联函数 2 头文件mainwindows h中 ifndef MAINWINDOW H define MAINWINDOW H include
  • jdk8 api

    JDK 8是Java开发工具包的第8个主要版本 它于2014年3月18日发布 JDK 8 API是Java开发人员使用的程序包 类 接口和注释的集合 用于创建Java程序 它包括Java核心库 如java lang和java util 以及
  • MSP430F5529学习笔记(2)——点亮LED

    TI官方MSP430F5529开发板原理图和中文开发手册 MSP430F5529学习笔记 1 环境配置 目录 原理图和中文开发手册获取方法 点亮LED1 分析电路图 写程序 点亮LED1 1 首先我们需要告诉单片机 P1 0是输入还是输出
  • 二叉树的链式存储结构及(C语言)实现

    上一节讲了二叉树的顺序存储 通过学习你会发现 其实二叉树并不适合用数组存储 因为并不是每个二叉树都是完全二叉树 普通二叉树使用顺序表存储或多或多会存在空间浪费的现象 本节我们学习二叉树的链式存储结构 图 1 普通二叉树示意图 如图 1 所示
  • Makefile语法

    下面来介绍Makefile的基本语法 12 2 1 引入文件 OpenWrt 使用三个 makefile 的子文件 分别为 Include TOPDIR rules mk Include INCLUDE DIR kernel mk Incl
  • 14-5 使用 xml 完成布局

    14 3 小节中 helloworld程序创建窗口使用代码创建 此外 也可使用 xml 完成窗口布局 代码仅仅用来处理数据逻辑 实现布局和数据处理相分离 布局的 ui 代码 builder ui
  • JumpServer开源堡垒机安装配置

    JumpServer开源堡垒机安装与配置 一 简介 二 下载与安装 2 1 下载 2 2 安装 2 3 其他 一 简介 JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型的资产 支持 官网地址 https www jump
  • windows文件服务器 文件方案,windowsserver2008文件服务器搭建2种方案.docx

    文件服务器搭建的两种方案范光华制作 文件服务器搭建的两种方案范光华制作 文件服务器搭建的两种方案 搭建目的 1 实现企业文件共享与传输 提高工作效率 2 提高企业访问文件的安全性 搭建环境 1 windows server 2008 R2
  • Navicat Premium 安装 & 注册

    Navicat Premium 一 Navicat Premium的安装 1 暂时关闭windows的病毒与威胁防护弄完再开 之后安装打开过程中弹窗所有警告全部允许 不然会被拦住 2 下载安装包 解压 链接 https pan baidu
  • 爬虫抓取图片:下载高质量图片

    目录 1 抓取图片简介 2 准备工作 3 分析Unsplash网站结构 4 编写图片爬虫
  • stm32使用PWM时,关闭PWM引脚会出现高电平解决方案

    现在使用TIM3来产生PWM波形 并通过软件打开 关闭PWM以实现调制波形 做法是 打开 TIM Cmd TIM3 ENABLE 关闭 TIM Cmd TIM3 DISABLE 跟踪到TIM Cmd之后 发现直接操作寄存器就可以了 TIMx
  • 从Random Walk(随机游走)到Graph Embedding(DeepWalk,LINE,Node2vec,SDNE,Graph2vec,GraphGAN)

    前言 本文转载自csdn博主上杉翔二系列博客并外加一些自己收集的资料 在这里仅作为自己学习之用 原文链接 https blog csdn net qq 39388410 article details 87904974 1 随机游走 普通数
  • idea java 插件开发_Intellij IDEA插件开发入门详解

    现今的IDE尽管有如 洪水猛兽 般强大 但要知道再强大的IDE也没法提供给使用者想要的一切功能 所以IDE一般都提供有API接口供开发者自行扩展 下面以Intellij IDEA 12下的插件开发为例 来看一下如何进一步增强IDE以适应开发
  • ROS自学实践(6):ROS进行激光SLAM建图——gmapping

    本节主要记录运行ROS自带的SLAM建模包gmapping方法 为后续理解这些代码 建立自己的SLAM算法打下基础 基于粒子滤波算法 二维栅格地图 需要里程计信息 1 通过命令行安装gmapping包 sudo apt get instal
  • win10下qt 中没有代码提示框了怎么办?

    在这里我也找了好久 发现是跟你装的输入法有冲突了 所以代码提示没有了 请你切换到英文的输入下 把你的输入法换成标准的英文输入输入状态 图片如下 换成这样就可以提示了 如图所示完美解决不能提示的问题 好了完美解决问题 在这里我放上我讲的几个课
  • Elasticsearch搜索详解(六):文本检索

    文本检索是关系型数据库 如 MySQL 的弱项 而恰恰是 ES 的强项 前一篇文章已经提到了 match term 除此之外还有multi match match phrace 等 分别的含义是 match 从一个字段中检索关键字 包括模糊
  • react中setState即时更新解决方案

    博主在做一个前端项目时 需要根据props中的状态来修改state中的状态 由于react中setState更新状态不能及时显示到页面 博主总结如下可及时更新state中的方法 1 componentWillReceiveProps 2 g
  • Mybatis:xml配置和基本增删改查

    目录 一 环境配置 environments 1 事务管理器 transactionManager 2 数据源 dataSource 3 属性 property 4 设置 settings 5 类型别名 typeAliases 二 安装My
  • net.ipv4.tcp_tw_reuse是干嘛的?

    文章目录 前言 准备工作 sd01的配置 sd02的配置 开始测试 关闭net ipv4 tcp tw reuse 打开net ipv4 tcp tw reuse 关闭客户端的net ipv4 tcp timestamps 关闭服务器端的n
  • Nacos+Node基础教程

    简介 Nacos是一个更易于构建云原生应用的动态服务发现 配置管理和服务管理平台 功能 动态配置服务 动态配置服务让您能够以中心化 外部化和动态化的方式挂历所有环境的配置 动态配置消除了配置变更时 重新部署应用和服务的需要 配置中心化管理让