什么是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)基础上,进行一定偏移量自动生成。
端口 | 与主端口的偏移量 | 描述 |
---|
9848 | 1000 | 客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求 |
9849 | 1001 | 服务端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
修改配置文件
### 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
启动服务
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
服务注册
"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:元数据,可以用来控制版本信息等
services.AddNacosAspNet(Configuration);
运行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();
}
}
结果符合上面的预期。
配置中心
{
"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();
});
}
"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,表示这个配置项不是可选的,是必须的,少了它程序就会出错。
services.Configure(Configuration.GetSection("AppSettings"));
[Route("api/[controller]")]
[ApiController]
public class ConfigController : ControllerBase
{
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
private readonly AppSettings _settings;
private readonly AppSettings _sSettings;
private readonly AppSettings _mSettings;
public ConfigController(ILogger logger, IConfiguration configuration,
IOptions options,
IOptionsSnapshot sOptions,
IOptionsMonitor _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";
}
}
测试结果
微信识别二维码关注