1.Nacos简介
在博客Dubbo生态之初识dubbo协议-CSDN博客种我们已经介绍了为什么要使用注册中心,nacos作为注册中心的一种,相对于其它的主流注册中心有什么区别呢?
Nacos | Eureka | Zookeeper | |
数据存储 | 存储在内存 | 存储在内存 | 存储在内存 |
通信协议 | gRPC | http | jute协议 |
数据变更推送方式 | push+pull | pull(30s) | push |
CAP模型 | AP/CP默认AP | AP | CP |
Nacos的整体架构
从架构图种,我们可以很清晰的看到,nacos提供了两个很核心的服务
- Config Service 配置中心
- Naming Service 命名服务,也就是服务注册与发现
再接着就是Nacos Core也就是Nacos的核心实现部分。最底层是Consistency Protocol,数据一致性协议,用来实现Nacos集群数据同步。
对外,是使用http协议,提供OpenAPI,客户端程序可以通过该API来完成数据的交互和处理。
2. Nacos作为注册中心的使用
nacos作为注册中心的使用,就至少要提供下面的这些接口
服务注册接口,应用程序启动以后把服务地址注册保存到注册中心服务地址获取接口,获取指定服务的所有地址信息服务地址变更监听接口,实现服务变更的动态监听
2.1 服务注册接口和使用
void registerInstance(String serviceName, String ip, int port) throws NacosException;void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException;void registerInstance(String serviceName, Instance instance) throws NacosException;
- serviceName : 表示服务名称
- ip: 表示服务实例的ip地址
- port: 服务实例的端口
- clusterName: 集群名
- instance: 实例属性
下面演示以下Spring Boot集成Nacos实现服务注册的Demo
a. 引入Nacos依赖包
<dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-discovery-spring-boot-starter</artifactId><version>0.2.12</version>
</dependency>
b.配置Nacos的服务地址
nacos.discovery.server-addr=192.168.8.133:8848
c.编写Controller接口
@RestController
public class NacosController {@NacosInjectedprivate NamingService namingService;@GetMapping("/registry")public void registry() throws NacosException {Instance instance=new Instance();instance.setClusterName("Test1"); //集群名字instance.setEnabled(true); //是否启用//临时节点/持久节点, 临时节点是AP模式(采用distro算法),持久节点是CP(采用raft算法)instance.setEphemeral(true);instance.setHealthy(true); //健康状态instance.setIp("192.168.216.112"); //ipinstance.setPort(8080); //端口instance.setWeight(4.0); //权重 取值范围 1 到 100,数值越大,权重越大namingService.registerInstance("example",instance);}
}
注册成功以后,就可以在nacos的控制台看到注册上去的服务信息。
2.2 服务实例查找
当客户端需要获取目标服务的全部实例时,可以通过以下api来完成,它会返回执行服务名字或者指定集群列表中的所有实例。
List<Instance> getAllInstances(String serviceName) throws NacosException;
List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException;
演示代码如下,增加下面的接口,根据指定服务名称获取实例列表
@RestController
public class NacosController {@NacosInjectedprivate NamingService namingService;@GetMapping("/discovery")public List<Instance> get(@RequestParam String serviceName) throws NacosException {return namingService.getAllInstances(serviceName);}
}
2.3 服务事件订阅
当服务提供者出现服务扩容和缩容时,服务消费者需要感知到服务地址的变化,可以通过监听服务来动态感知到服务的变化
void subscribe(String serviceName, EventListener listener) throws NacosException;
void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
其中,listen表示的是服务监听的事件回调
Nacos还提供了取消监听的接口
void unsubscribe(String serviceName, EventListener listener) throws NacosException;
void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
增加如下接口,用来注册订阅事件,当我们调用registry发起注册,或者在nacos控制台对服务下线的时候,都会触发事件通知。
@GetMapping("/sub")
public void subscribe(@RequestParam String serviceName) throws NacosException {namingService.subscribe(serviceName, new EventListener() {@Overridepublic void onEvent(Event event) {NamingEvent namingEvent=(NamingEvent)event;System.out.println("收到事件:"+namingEvent.getServiceName());}});
}
2.4 namespace和group
在nacos中还提供了namespace和group命名空间和分组的机制
namespace可以解决多环境以及多租户数据的隔离问题。比如在多套环境下,可以根据指定环境创建不同的namespace,实现多环境隔离。或者在多租户的场景中,每个用户可以维护自己的namespace,实现每个用户的配置数据和注册数据的隔离。group是分组机制,它的纬度是实现服务注册信息或者DataId的分组管理机制,对于group的用法,没有固定的规则,它也可以实现不同环境下的分组,也可以实现同一个应用下不同配置类型或者不同业务类型的分组。
官方的建议是,namespace用来区分不同环境,group可以专注在业务层面的数据分组。实际上在使用过程中,最重要的是提前定好统一的口径和规定,避免不同的项目团队混用导致后期维护混乱的问题。
Nacos中的namespace和group关系如下图所示,其中namespace默认是public,Group默认是DEFAULT_GROUP
namespace和group也可以自定义
自定义namespace
name用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在没有明确指定配置的情况下,默认使用的是nacos上public这个namespace
如果需要使用自定义的命名空间,可以通过以下配置来实现:
a.在nacos-console中创建两个命名空间,分别是
b.修改dubbo相关配置项目
dubbo.registries.nacosregistry.address=nacos://192.168.8.133:8848?
namespace=47201fb3-2b45-4199-87c5-298a748c9385
或者
dubbo.registry.parameters.namespace=5cbb70a5-xxx-xxx-xxxd43479ae0932
自定义Group
在没有明确指定配置的情况下,默认使用的是DEFAULT_GROUP。如果需要自定以自己的Group,可以通过以下配置来实现
dubbo.registries.nacosregistry.address=nacos://192.168.8.133:8848?
namespace=47201fb3-2b45-4199-87c5-298a748c9385&group=example
或者
dubbo.registry.parameters.group=example
3. Nacos作为配置中心的使用
nacos作为配置中心,其存储方式就是k-v的形式,在服务启动的时候,会从远程服务器获取配置
nacos作为配置中心,支持服务端的配置存储、配置的CRUD、配置的动态感知
dubbo本身并没有集成nacos作为配置中心,其实质是springboot集成的。
nacos也会跟注册中心一样提供配置管理相关的API来完成功能的实现
- 从远程服务器上获取配置
- 服务器上配置变更后的通知
3.1 从服务器获取配置
用于服务启动的时候从Nacos获取配置
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException
参数名 | 参数类型 | 描述 |
dataId | string | 配置 ID,采用类似 package.class(如 com.taobao.tc.refund.log.level)的命名规则保 证全局唯一性,class 部分建议是配置的业务含 义。全部字符小写。只允许英文字符和 4 种特 殊字符("."、":"、"-"、"_"),不超过 256 字 节。 |
group | string | 配置分组,建议填写产品名:模块名 (Nacos:Test)保证唯一性,只允许英文字符和 4种特殊字符("."、":"、"-"、"_"),不超过128 字节。 |
timeout | long | 读取配置超时时间,单位 ms,推荐值 3000 |
案例演示:
a. 引入jar包依赖
<dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>2.1.1</version>
</dependency>
<dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-api</artifactId><version>2.1.1</version>
</dependency>
<dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-common</artifactId><version>2.1.1</version>
</dependency>
编写配置获取代码
public class NacosExample {public static void main(String[] args) {String serverAddr="192.168.8.133:8848";String dataId="example";String groupId="DEFAULT_GROUP";Properties properties=new Properties();properties.put("serverAddr",serverAddr);try {//通过nacosfactory创建一个配置中心的服务ConfigService configService=NacosFactory.createConfigService(properties);// 5000表示读取配置的超时时间,如果超时或者出现网络故障,会抛出NacosException的异常String content=configService.getConfig(dataId,groupId,3000);System.out.println(content);} catch (NacosException e) {e.printStackTrace();}}
}
上述代码的含义是:
- 使用nacosFactory构建ConfigService
- 通过getConfig来获得配置,查询指定groupid下对应的dataid这个数据
3.2 配置变更订阅
如果希望nacos推送配置变更,可以使用nacos动态监听配置接口来实现
public void addListener(String dataId, String group, Listener listener)
listener 代表是监听器,配置变更进入监听器的回调函数
演示代码如下:
public class NacosMain {public static void main(String[] args) {String serverAddr="192.168.8.133:8848";String dataId="example";String groupId="DEFAULT_GROUP";Properties properties=new Properties();properties.put("serverAddr",serverAddr);try {//通过nacosfactory创建一个配置中心的服务ConfigService configService=NacosFactory.createConfigService(properties);// 5000表示读取配置的超时时间,如果超时或者出现网络故障,会抛出NacosException的异常String content=configService.getConfig(dataId,groupId,3000);configService.addListener(dataId, groupId, new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String s) {System.out.println("收到配置变更通知:"+s);}});System.out.println(content);System.in.read(); //保证程序不执行结束}catch (NacosException | IOException e) {e.printStackTrace();}}
}
4.Springboot集成Nocos实现动态配置
springboot集成nacos实现动态配置获取的演示案例:
a.添加jar包依赖
<dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.12</version>
</dependency>
b.编写测试案例
@NacosPropertySource(dataId="example",autoRefreshed = true)
@SpringBootApplication
public class NacosDemoApplication {public static void main(String[] args) {SpringApplication.run(NacosDemoApplication.class, args);}
}
使用@NacosroperSource加载dataId为example的配置源,并开启自动更新
c.增加一个controller作为测试
@RestController
public class NacosController {@NacosValue(value = "${txt:default-msg}",autoRefreshed =true)private String txt;@GetMapping("/")public String get(){return txt;}
}
@NacosValue注解,表示它在启动时会从Nacos-Server中获取配置项。
d.修改application.properties文件,增加nacos-server的服务端连接配置
nacos.config.server-addr = 192.168.8.133 : 8848
e.启动Springboot项目,并访问上述创建的controller接口,此时打印的消息就是在nacos上配置的,应该时default-msg
接着,我们在Nacos-server上添加一个配置,配置项目如下
txt=Hello, this Msg is from Nacos Server
f.再次访问上述接口,就可以看到加载的信息已经发生了变化。
总结:
nacos集成dubbo做动态配置管理,其实本质上就是Spring boor集成nacos.
只是多了一个Dubbo作为RPC服务通信,其实相当于就是Springboot这个生态下集成dubbo以及其它各个组件来实现微服务架构下的服务治理需求
真正来说,DUBBO组件本身并没有提供动态配置管理集成的能力