暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

基于.NET Core框架nacos的简单应用

码农游乐场 2021-09-08
3435

么是Nacos?

服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:Nacos 的关键特性包括:

  • 服务发现和服务健康监测

  • 动态配置服务

  • 动态 DNS 服务

  • 服务及其元数据管理

具体的请参考官网地址: https://nacos.io/zh-cn/index.html

Nacos 2.0.0兼容性/环境准备

当前推荐的稳定版本为2.0.3,nacos有多种部署方式,这里为了测试只要单机版就行了。

Nacos2.0版本相比1.X增加了grpc的通信方式,因此需要增加2个端口。新增端口是配置的主端口(server.port)基础上,进行一定偏移量自动生成。

端口与主端口的偏移量描述
98481000客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求
98491001服务端gRPC请求服务端端口,用于服务间同步等

使用VIP/nginx请求时,需要配置成TCP转发,不能配置http2转发,否则连接会被nginx断开。 客户端拥有相同的计算逻辑,用户如同1.X的使用方式,配置主端口(默认8848),通过相同的偏移量,计算对应gRPC端口(默认9848)。

因此如果客户端和服务端之前存在端口转发,或防火墙时,需要对端口转发配置和防火墙配置做相应的调整。

兼容性

Nacos2.0的服务端完全兼容1.X客户端。Nacos2.0客户端由于使用了gRPC,无法兼容Nacos1.X服务端,请勿使用2.0以上版本客户端连接Nacos1.X服务端。

下载编译后压缩包方式

您可以从 https://github.com/alibaba/nacos/releases 下载最新稳定版本 nacos-server-$version.zip 包。

unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin

复制

修改配置文件

  • 打开conf/application.properties配置文件;

  • 修改mysql连接字符串,如下:

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://ip:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123456

复制
  • nacos-mysql.sql用初始化nacos_config数据库

启动服务

Windows

启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

复制

Linux/Unix/Mac

启动命令(standalone代表着单机模式运行,非集群模式):

sh startup.sh -m standalone

复制

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone

复制

登入控制台

打开http://localhost:8848/nacos,默认用户和密码都是nacos。  这样简单的单机环境就搭建好了。

创建命名空间

基于ASP.NET Core的应用

随着 nacos 2.0.3 正式发布,我这边也用nacos-sdk-csharp 1.1.1版本体验下。

安装依赖

新版已经移除了后缀unofficial。

dotnet add package nacos-sdk-csharp
dotnet add package nacos-sdk-csharp.AspNetCore
dotnet add package nacos-sdk-csharp.Extensions.Configuration

复制

服务注册

  • appseting.json增加配置

 "nacos": {
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "10525b8b-6f88-4c8b-9d5e-d518d8205f46",
"ListenInterval": 1000,
"ServiceName": "App1",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "",
"Port": 5000,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"UserName": "",
"Password": "",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"Metadata": {
"version": "1.0.0",
"updatetime": "2020/02/01"
}
},

复制
- Namespace:我这里是自定义了一个cs,请参考前一个章节,必须用id,不能用名称。
- ConfigUseRpc/NamingUseRpc:是否使用gRPC 协议和服务端对接。
- IP/Port: 是APP对外暴露的IP和端口
- ServerAddresses:nacos服务地址
- Metadata:元数据,可以用来控制版本信息等

复制
  • Stautup.cs中增加以下代码

 services.AddNacosAspNet(Configuration);

复制

运行APP

  • 运行之后我们可以看到这个命名空间下有个服务名为App1。 

  • 再启动一个一模一样的APP,只不过端口变了,集群里可以看到两个实例 

服务发现

//获取单个实例
var instance = _svc.SelectOneHealthyInstance("App1", "DEFAULT_GROUP").GetAwaiter().GetResult();

复制

上面获取单实例,每次获取到的可能不一样,取决于nacos负载均衡机制。

//获取所有健康的实例
var instances=_svc.SelectInstances("App1", true).GetAwaiter().GetResult();

复制

此种方式可以获取出所有健康的实例。

测试代码

[HttpGet]
public ActionResult<string> Get()
{
//获取实例
var instance = _svc.SelectOneHealthyInstance("App1", "DEFAULT_GROUP").GetAwaiter().GetResult();
var instances=_svc.SelectInstances("App1", true).GetAwaiter().GetResult();

var host = $"{instance.Ip}:{instance.Port}";
var baseUrl = instance.Metadata.TryGetValue("secure", out _)
? $"https://{host}"
: $"http://{host}";

if (string.IsNullOrWhiteSpace(baseUrl))
{
return "empty";
}

var url = $"{baseUrl}/api/user";

using (HttpClient client = new HttpClient())
{
var result = client.GetAsync(url).GetAwaiter().GetResult();
return result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
}
}

复制

结果符合上面的预期。

配置中心

  • 新增配置项,把原来的配置全部移入nacos配置中心中。

{
"AdminSafeList": "127.0.0.1;192.168.10.134",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"nacos": {
"EndPoint": "",
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "10525b8b-6f88-4c8b-9d5e-d518d8205f46",
"ListenInterval": 1000,
"ServiceName": "App1",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Ip": "",
"PreferredNetworks": "",
"Port": 5000,
"Weight": 100,
"RegisterEnabled": true,
"InstanceEnabled": true,
"Ephemeral": true,
"Secure": false,
"AccessKey": "",
"SecretKey": "",
"UserName": "nacos",
"Password": "nacos",
"ConfigUseRpc": true,
"NamingUseRpc": true,
"NamingLoadCacheAtStart": "",
"LBStrategy": "WeightRandom", WeightRandom WeightRoundRobin
"Metadata": {
"aa": "bb",
"cc": "dd"
}
},
"AllowedHosts": "*",
"Urls": "http://*:5000",
"ConnectionStrings": {
"Default": "Server=127.0.0.1;Port=3306;Database=demo;User Id=root;Password=123456;"
},
"version": "测试version",
"AppSettings": {
"Str": "val",
"num": 1,
"arr": [1, 2, 3],
"subobj": {
"a": "b"
}
}
}

复制

  • 修改应用程序

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var c = builder.Build();
builder.AddNacosV2Configuration(c.GetSection("NacosConfig"));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

复制
  • 修改appsettings.json

"NacosConfig": {
"Listeners": [
{
"Optional": false,
"DataId": "common",
"Group": "DEFAULT_GROUP"
}
],
"Tenant": "10525b8b-6f88-4c8b-9d5e-d518d8205f46",
"ServerAddresses": [ "http://localhost:8848/" ],
"UserName": "",
"Password": "",
"AccessKey": "",
"SecretKey": "",
"EndPoint": ""
}

复制

这里的意思是,这个应用需要监听commo配置项的变化,Optional 设置成 false,表示这个配置项不是可选的,是必须的,少了它程序就会出错。

  • 如果使用 Option 的方式来读取配置的话,还需要在 Startup 里面进行绑定。

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

复制
  • 测试接口用来查询配置

[Route("api/[controller]")]
[ApiController]
public class ConfigController : ControllerBase
{
private readonly ILogger<ConfigController> _logger;
private readonly IConfiguration _configuration;
private readonly AppSettings _settings;
private readonly AppSettings _sSettings;
private readonly AppSettings _mSettings;
public ConfigController(ILogger<ConfigController> logger, IConfiguration configuration,
IOptions<AppSettings> options,
IOptionsSnapshot<AppSettings> sOptions,
IOptionsMonitor<AppSettings> _mOptions
)

{
_logger = logger;
_configuration = configuration;
_settings =options.Value;
_sSettings = sOptions.Value;
_mSettings = _mOptions.CurrentValue;
}


[HttpGet]
public string Get()
{
string id = Guid.NewGuid().ToString("N");

_logger.LogInformation($"==========={_configuration["all"]}======");

_logger.LogInformation($"============== begin {id} =====================");

var conn = _configuration.GetConnectionString("Default");
_logger.LogInformation($"{id} conn = {conn}");

var version = _configuration["version"];
_logger.LogInformation($"{id} version = {version}");

var str1 = Newtonsoft.Json.JsonConvert.SerializeObject(_settings);
_logger.LogInformation($"{id} IOptions = {str1}");

var str2 = Newtonsoft.Json.JsonConvert.SerializeObject(_sSettings);
_logger.LogInformation($"{id} IOptionsSnapshot = {str2}");

var str3 = Newtonsoft.Json.JsonConvert.SerializeObject(_mSettings);
_logger.LogInformation($"{id} IOptionsMonitor = {str3}");

_logger.LogInformation($"===============================================");

return "ok";
}
}

复制
  • 测试结果 



微信识别二维码关注


文章转载自码农游乐场,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论