Nacos简介
一、简介
1、概述
Nacos(Dynamic Naming and Configuration Service)是一个开源的动态服务发现、配置管理和服务管理平台。
2、下载
下载nacos-server-xxx.zip后解压。
3、运行
切换到bin目录,执行以下命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone
访问http://localhost:8848/nacos即可打开Nacos管理控制台:

二、核心功能
1、命名空间
Nacos的命名空间(Namespace)可以实现多环境(如开发、测试、生产)或多租户的隔离,可以为不同的环境创建不同的命名空间,实现配置和服务的完全隔离。
Nacos通过Namespace、Group、Data ID等元素来唯一确定一个配置或服务,不同的命名空间下,可以存在相同的Group 或 Data ID的配置。

2、服务发现与注册
服务提供者(Provider)在启动时,会向Nacos服务器注册自己的服务信息(例如IP、端口、服务名等);服务消费者(Consumer)通过Nacos查询并获取可用的服务实例列表,从而实现服务间的发现与调用。
- 服务注册
curl -X POST "http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080"

- 服务发现
curl -X GET "http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName"
- Java样例
package demo;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
public class NacosNamingExample {
public static void main(String[] args) throws Exception{
Logger log = LoggerFactory.getLogger(NacosNamingExample.class);
Properties properties = new Properties();
//Nacos地址
properties.put(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
//指定命名空间
properties.put(PropertyKeyConst.NAMESPACE, "dev");
NamingService namingService = NacosFactory.createNamingService(properties);
//注册服务
namingService.registerInstance("testService", "10.0.0.1", 8080);
wait2Sync();
//订阅服务
namingService.subscribe("testService", new EventListener() {
@Override
public void onEvent(Event event) {
if(event instanceof NamingEvent) {
NamingEvent namingEvent = (NamingEvent) event;
log.info("serviceName: {}", namingEvent.getServiceName());
log.info("instances: {}", namingEvent.getInstances());
}
}
});
namingService.registerInstance("testService", "10.0.0.2", 8080);;
wait2Sync();
}
/**
* 等待同步nacos
*/
private static void wait2Sync() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
serviceName: testService
instances: [Instance{instanceId='10.0.0.1#8080#DEFAULT#DEFAULT_GROUP@@testService', ip='10.0.0.1', port=8080, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='DEFAULT_GROUP@@testService', metadata={}}]
serviceName: testService
instances: [Instance{instanceId='10.0.0.2#8080#DEFAULT#DEFAULT_GROUP@@testService', ip='10.0.0.2', port=8080, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='DEFAULT_GROUP@@testService', metadata={}}]
3、动态配置管理
Nacos提供了一个中心化的配置服务器,可以通过Nacos控制台统一管理所有环境的配置信息。当配置需要变更时,无需重启应用,Nacos就能将变更的配置实时推送到客户端并生效,极大减少了系统停机时间,为实现灰度发布、版本控制等高级特性提供了基础。
- 发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
- 获取配置
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
- Java样例
package demo;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.client.config.listener.impl.PropertiesListener;
public class NacosConfigExample {
public static void main(String[] args) throws Exception{
Logger log = LoggerFactory.getLogger(NacosConfigExample.class);
Properties properties = new Properties();
//Nacos地址
properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
ConfigService configService = NacosFactory.createConfigService(properties);
String group = "testGroup";
String dataId = "testDataId";
String content = "connectTimeoutInMills=5000";
//监听配置
configService.addListener(dataId, group, new PropertiesListener() {
@Override
public void innerReceive(Properties properties) {
//Properties类型
log.info("receive: {}", properties);
}
});
configService.addListener(dataId, group, new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
//其他类型配置,例如json、yaml或pojo对象,可按需做反序列化
log.info("receive(String): {}", configInfo);
}
});
//发布配置
boolean result = configService.publishConfig(dataId, group, content);
log.info("publishConfig: {}", result);
wait2Sync();
//查询配置
String config = configService.getConfig(dataId, group, 3000);
log.info("getConfig: {}", config);
//更新配置
String newContent = "connectTimeoutInMills=3000";
boolean updateResult = configService.publishConfig(dataId, group, newContent);
log.info("updateConfig: {}", updateResult);
wait2Sync();
//删除配置
boolean removeResult = configService.removeConfig(dataId, group);
log.info("removeConfig: {}", removeResult);
wait2Sync();
config = configService.getConfig(dataId, group, 3000);
log.info("getConfig: {}", config);
}
/**
* 等待同步nacos
*/
private static void wait2Sync() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
publishConfig: true
receive: {connectTimeoutInMills=5000}
receive(String): connectTimeoutInMills=5000
getConfig: connectTimeoutInMills=5000
updateConfig: true
receive: {connectTimeoutInMills=3000}
receive(String): connectTimeoutInMills=3000
removeConfig: true
receive(String): null
getConfig: null
三、部署模式
1、单机
- 启动
执行以下命令:
startup.cmd -m standalone
或修改startup.cmd中的MODE变量后直接运行startup.cmd:
set MODE="standalone"
-
使用MySQL
单机模式时默认使用内置数据库Derby实现数据的存储,可以通过配置使用MySQL(5.6.5+)作为数据存储,步骤如下:
- 初始化nacos数据库
执行
conf\mysql-schema.sql文件完成初始化。- 配置数据源
修改
conf\application.properties文件,增加数据库配置:spring.sql.init.platform=mysql db.num=1 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 db.user.0=nacos db.password.0=nacos
2、集群
集群模式通常用于生产环境,确保高可用;需要3个或3个以上Nacos节点才能构成集群。
步骤如下:
- 配置集群
在conf\cluster.conf中配置节点信息:
200.8.9.16:8848
200.8.9.17:8848
200.8.9.18:8848
- 开启默认鉴权插件(可选)
Nacos是一个内部微服务组件,需要在可信的内部网络中运行,不可暴露在公网环境,防止带来安全风险。
Nacos提供简单的鉴权实现,为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。
如果运行在不可信的网络环境或者有强鉴权诉求,可以参考鉴权插件实现自定义鉴权。
可以通过如下步骤开启默认鉴权:
修改conf\application.properties文件,增加鉴权配置:
nacos.core.auth.enabled=true
nacos.core.auth.system.type=nacos
#base64字符串
nacos.core.auth.plugin.nacos.token.secret.key=${自定义,保证所有节点一致}
nacos.core.auth.server.identity.key=${自定义,保证所有节点一致}
nacos.core.auth.server.identity.value=${自定义,保证所有节点一致}
-
配置MySQL数据源
-
执行
conf\mysql-schema.sql文件完成初始化 -
修改
conf\application.properties配置文件
spring.sql.init.platform=mysql db.num=1 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 db.user.0=nacos db.password.0=nacos -
启动三个节点后,访问http://localhost:8848/nacos/,需要登录:

输入nacos/nacos即可登录成功。
登录后在节点列表中可以看到Nacos节点信息(此处使用同一机器不同端口启动多个Nacos服务):

四、其他
- 配置鉴权插件后客户端连接时需传递认证信息
properties.setProperty(PropertyKeyConst.USERNAME, "nacos");
properties.setProperty(PropertyKeyConst.PASSWORD, "nacos");
- 自定义用户信息
使用BCrypt加密密码:
//创建BCrypt加密器实例
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//明文密码
String rawPassword = "hello";
//加密密码
String encodedPassword = encoder.encode(rawPassword);
System.out.println("BCrypt加密后的密码: " + encodedPassword);
然后在users和roles表中插入相关信息:
INSERT INTO users (username, password, enabled) VALUES ('xxx', '$2a$10$gUteC5T1metlzuBytrAdyeudXmZ4N025MwIt77Z.sgm7bj6311962', TRUE);
INSERT INTO roles (username, role) VALUES ('xxx', 'ROLE_ADMIN');
之后就可以使用此用户密码登录。