nacosrustclient

介绍

rust实现的nacos客户端。

同时支持1.x版http协议和2.x版本协议,支持创建client时指定使用协议类型。

  1. 使用 actix + tokio 实现。
  2. 支持配置中心的推送、获取、监听。
  3. 支持注册中心的服务实例注册(自动维护心跳)、服务实例获取(自动监听缓存实例列表)。
  4. 创建的客户端后台处理,都放在同一个actix环境线程;高性能,不会有线程膨胀,稳定可控。

使用方式

首先加入引用

toml [dependencies] nacos_rust_client = "0.2"

使用配置中心

  1. 创建客户端

使用ConfigClient::new_with_addrs创建配置客户端,支持设置集群地址列表,支持验权校验.

rust use nacos_rust_client::client::config_client::ConfigClient; use nacos_rust_client::client::ClientBuilder; //... //let config_client = ConfigClient::new_with_addrs("127.0.0.1:8848,127.0.0.1:8848",tenant,auth_info); let config_client = ClientBuilder::new() .set_endpoint_addrs("127.0.0.1:8848,127.0.0.1:8848") .set_auth_info(auth_info) .set_tenant(tenant) .set_use_grpc(true) //select communication protocol .build_config_client();

创建客户端,后会把客户端的一个引用加入到全局对象,可以通过 get_last_config_client获取.

rust let config_client = nacos_rust_client::get_last_config_client().unwrap();

  1. 设置获取配置信息

rust let key = ConfigKey::new("data_id","group_name","" /*tenant_id*/); config_client.set_config(&key, "config_value").await.unwrap(); let v=config_client.get_config(&key).await.unwrap();

  1. 配置监听器

实时的接收服务端的变更推送,更新监听器的内容,用于应用配置动态下发。

```rust

[derive(Debug,Serialize,Deserialize,Default,Clone)]

pub struct Foo { pub name: String, pub number: u64, } //... let fooconfigobjlistener = Box::new(ConfigDefaultListener::new(key.clone(),Arc::new(|s|{ //字符串反序列化为对象,如:serdejson::fromstr::(s) Some(serdejson::fromstr::(s).unwrap()) }))); configclient.subscribe(fooconfigobjlistener.clone()).await; let fooobjfromlistener = fooconfigobjlistener.getvalue().unwrap(); ```

使用注册中心

  1. 创建客户端

使用NamingClient::new_with_addrs创建配置客户端,支持设置集群地址列表,支持验权校验.

rust use nacos_rust_client::client::naming_client::NamingClient; use nacos_rust_client::client::ClientBuilder; //... //let naming_client = NamingClient::new_with_addrs("127.0.0.1:8848,127.0.0.1:8848",namespace_id,auth_info); let naming_client = ClientBuilder::new() .set_endpoint_addrs("127.0.0.1:8848,127.0.0.1:8848") .set_auth_info(auth_info) .set_tenant(tenant) .set_use_grpc(true) //select communication protocol .build_naming_client();

创建客户端,后会把客户端的一个引用加入到全局对象,可以通过 get_last_naming_client获取.

rust let naming_client = nacos_rust_client::get_last_naming_client().unwrap();

  1. 注册服务实例

只要调拨一次注册实例,客户端会自动在后面维持心跳保活。

rust let instance = Instance::new_simple(&ip,port,service_name,group_name); naming_client.register(instance);

  1. 服务地址路由

查询指定服务的地址列表

rust let params = QueryInstanceListParams::new_simple(service_name,group_name); let instance_list_result=client.query_instances(params).await;

查询指定服务的地址列表并按重选中一个地址做服务调用。

rust let params = QueryInstanceListParams::new_simple(service_name,group_name); let instance_result=client.select_instance(params).await;

如果要在tonic中使用服务地址选择,可以使用对tonic的适配 (nacos-tonic-discover)[https://crates.io/crates/nacos-tonic-discover]

其它

应用结束时,nacosrustclient可能还有后台的调用,可以调用nacos_rust_client::close_current_system() 优雅退出nacosrustclient后台线程。

例子

运行下面的例子,需要先启动nacos服务,把例子中的host改成实际的地址。

例子完整依赖与代码可以参考 examples/下的代码。

配置中心例子

```rust use std::time::Duration; use std::sync::Arc;

use nacosrustclient::client::{ HostInfo, AuthInfo }; use nacosrustclient::client::configclient::{ ConfigClient,ConfigKey,ConfigDefaultListener }; use serde::{Serialize,Deserialize}; use serdejson;

[derive(Debug,Serialize,Deserialize,Default,Clone)]

pub struct Foo { pub name: String, pub number: u64, }

[tokio::main]

async fn main() { std::env::setvar("RUSTLOG","INFO"); envlogger::init(); //let host = HostInfo::parse("127.0.0.1:8848"); //let configclient = ConfigClient::new(host,String::new()); let tenant = "public".toowned(); //default teant //let authinfo = Some(AuthInfo::new("nacos","nacos")); let authinfo = None; let configclient = ConfigClient::newwithaddrs("127.0.0.1:8848,127.0.0.1:8848",tenant,authinfo); tokio::time::sleep(Duration::frommillis(1000)).await;

let key = ConfigKey::new("001","foo","");
//设置
config_client.set_config(&key, "1234").await.unwrap();
//获取
let v=config_client.get_config(&key).await.unwrap();
println!("{:?},{}",&key,v);
check_listener_value().await;
nacos_rust_client::close_current_system();

}

async fn checklistenervalue(){ //获取全局最后一次创建的configclient let configclient = nacosrustclient::getlastconfigclient().unwrap(); let mut fooobj= Foo { name:"foo name".toowned(), number:0u64, }; let key = ConfigKey::new("fooconfig","foo",""); let fooconfigobjlistener = Box::new(ConfigDefaultListener::new(key.clone(),Arc::new(|s|{ //字符串反序列化为对象,如:serdejson::fromstr::(s) Some(serdejson::fromstr::(s).unwrap()) }))); let fooconfigstringlistener = Box::new(ConfigDefaultListener::new(key.clone(),Arc::new(|s|{ //字符串反序列化为对象,如:serdejson::fromstr::(s) Some(s.toowned()) }))); configclient.setconfig(&key,&serdejson::tostring(&fooobj).unwrap()).await.unwrap(); //监听 configclient.subscribe(fooconfigobjlistener.clone()).await; configclient.subscribe(fooconfigstringlistener.clone()).await; //从监听对象中获取 println!("key:{:?} ,value:{:?}",&key.dataid,fooconfigstringlistener.getvalue()); for i in 1..10 { fooobj.number=i; let foojsonstring = serdejson::tostring(&fooobj).unwrap(); configclient.setconfig(&key,&foojsonstring).await.unwrap(); // 配置推送到服务端后, 监听更新需要一点时间 tokio::time::sleep(Duration::frommillis(1000)).await; let fooobjfromlistener = fooconfigobjlistener.getvalue().unwrap(); let fooobjstringfromlistener = fooconfigstringlistener.getvalue().unwrap(); // 监听项的内容有变更后会被服务端推送,监听项会自动更新为最新的配置 println!("fooobjfromlistener :{}",&fooobjstringfromlistener); asserteq!(fooobjstringfromlistener.tostring(),foojsonstring); asserteq!(fooobjfromlistener.number,fooobj.number); asserteq!(fooobjfrom_listener.number,i); } } ```

服务中心例子

```rust use nacosrustclient::client::naming_client::{ServiceInstanceKey, InstanceDefaultListener}; use std::sync::Arc;

use std::time::Duration;

use nacosrustclient::client::{HostInfo, AuthInfo, naming_client::{NamingClient, Instance,QueryInstanceListParams}};

[tokio::main]

async fn main(){ //std::env::setvar("RUSTLOG","INFO"); std::env::setvar("RUSTLOG","INFO"); envlogger::init(); //let host = HostInfo::parse("127.0.0.1:8848"); //let client = NamingClient::new(host,"".toowned()); let namespaceid = "public".toowned(); //default teant //let authinfo = Some(AuthInfo::new("nacos","nacos")); let authinfo = None; let client = NamingClient::newwithaddrs("127.0.0.1:8848,127.0.0.1:8848", namespaceid, authinfo); let servciekey = ServiceInstanceKey::new("foo","DEFAULTGROUP"); //可以通过监听器获取指定服务的最新实现列表,并支持触发变更回调函数,可用于适配微服务地址选择器。 let defaultlistener = InstanceDefaultListener::new(servciekey,Some(Arc::new( |instances,addlist,removelist| { println!("service instances change,count:{},add count:{},remove count:{}",instances.len(),addlist.len(),removelist.len()); }))); client.subscribe(Box::new(defaultlistener.clone())).await.unwrap(); let ip = localipaddress::get().unwrap(); let servicename = "foo"; let groupname="DEFAULTGROUP"; for i in 0..10{ let port=10000+i; let instance = Instance::newsimple(&ip,port,servicename,groupname); //注册 client.register(instance); tokio::time::sleep(Duration::from_millis(1000)).await; }

//tokio::spawn(async{query_params2().await.unwrap();});
//let client2 = client.clone();
tokio::spawn(
    async move {
        query_params().await;
    }
);

//let mut buf = vec![0u8;1];
//stdin().read(&mut buf).unwrap();
tokio::signal::ctrl_c().await.expect("failed to listen for event");
println!("n:{}",&client.namespace_id);

}

async fn queryparams() -> anyhow::Result<()>{ //get client from global let client = nacosrustclient::getlastnamingclient().unwrap(); let servicename = "foo"; let groupname="DEFAULTGROUP"; let params = QueryInstanceListParams::newsimple(servicename,groupname); // 模拟每秒钟获取一次实例 loop{ //查询并按权重随机选择其中一个实例 match client.selectinstance(params.clone()).await{ Ok(instances) =>{ println!("select instance {}:{}",&instances.ip,&instances.port); }, Err(e) => { println!("selectinstance error {:?}",&e) }, } tokio::time::sleep(Duration::from_millis(1000)).await; } Ok(()) }

```