聊一聊基于Nacos的metadata完成服务间的AB测试
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊一聊基于Nacos的metadata完成服务间的AB测试相关的知识,希望对你有一定的参考价值。
背景
在很多时候,产品同学或其他 boss 会有一些想法,或好或坏,都会想放到线上环境去验证,看看能不能带来更好的效果。
这其实就是一个提出假设和验证假设的过程,而 AB 测试,是验证假设的好方法。
对于服务之间的调用,这一块其实也是相当符合的。
举几个例子吧
A -> B,B 进行了重构
A -> B,B 进行了算法模型的调整
A -> B,B 加入了新特性
...
对于这几个例子,正常的逻辑都是会让小部分用户或流量流进新的 B,观察一段时间的数据,是否达到预期,再决策 B 是否真的可以上线。
在引入注册中心 Nacos 之后我们对服务之间调用这一块可以怎么做到呢?
答案就是 metadata(元数据)!!!
每个应用的实例基本信息比较少,但是 metadata 是可以很丰富的。
我们在向 Nacos Server 进行服务注册的时候往往会附加一些 metadata ,可以参考官方文档中 Dubbo 融合 Nacos 成为注册中心 章节。
对于上述的被调用方新版 B 而已,完全可以把相关内容放进 metadata 中,好比说版本号,特性名等等。
调用方 A 就可以根据当前的用户来判断是否要走那个版本的被调用方 B。当然这一步很多公司都会有相应的系统去管理,好比体验用户。
也可以看看下面这个流程图,基本涉及到了。
接下来就根据上面的这个,做一个简单的例子。
示例
首先是准备两个被调用方 B。
带特性的:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddNacosAspNet(builder.Configuration);
var app = builder.Build();
app.MapGet("/", () =>
return Results.Ok("OK - feature");
);
app.Run("http://*:9885");
"nacos":
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "cs",
"ListenInterval": 1000,
"ServiceName": "providerb",
"PreferredNetworks": "192.168",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Weight": 100,
"Metadata":
"version": "1.0",
"feature": "true"
正常的:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddNacosAspNet(builder.Configuration);
var app = builder.Build();
app.MapGet("/", () =>
return Results.Ok("OK - normal");
);
app.Run("http://*:9886");
"nacos":
"ServerAddresses": [ "http://localhost:8848" ],
"DefaultTimeOut": 15000,
"Namespace": "cs",
"ListenInterval": 1000,
"ServiceName": "providerb",
"PreferredNetworks": "192.168",
"GroupName": "DEFAULT_GROUP",
"ClusterName": "DEFAULT",
"Weight": 100,
"Metadata":
"version": "1.0",
"feature": "false"
启动这两个被调用方,然后可以看到 Nacos 的服务详情页大致如下:
后面就是比较关键的调用方了。
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddNacosV2Naming(x =>
x.ServerAddresses = new List<string> "http://localhost:8848/" ;
x.Namespace = "cs";
);
var app = builder.Build();
app.MapGet("/req/id", Call);
app.Run("http://*:9884");
async Task<IResult> Call(ILoggerFactory loggerFactory, INacosNamingService svc, IHttpClientFactory factory, int id)
var logger = loggerFactory.CreateLogger(nameof(Call));
var allIns = await svc.GetAllInstances("providerb", "DEFAULT_GROUP", new List<string> "DEFAULT" );
// 按照对应的逻辑做对应的地址获取方式
// 这里是:id 小于 100 的走新特性
string address = GetAddress(allIns, id < 100);
var client = factory.CreateClient();
var res = await client.GetStringAsync(address);
logger.LogInformation("user=id,url=url,result=res", id, address, res);
return Results.Ok($"caller ------ res");
string GetAddress(List<Instance> instances, bool isFeature)
var str = isFeature ? "true" : "false";
var ins = instances
.Where(x => x.Healthy
&& x.Enabled
&& x.Metadata.TryGetValue("feature", out var feature)
&& feature.Equals(str))
.OrderBy(x=>Guid.NewGuid())
.FirstOrDefault();
return ins != null
? $"http://ins.Ip:ins.Port"
: throw new Exception("Can not find out ins");
启动调用方程序,访问并指定小于100和大于100的两个用户,可以看到调用的虽然是同一个服务,但是一个是访问的 feature,另一个访问的是 normal。
到这里我们已经可以做到根据不同的逻辑,将用户导向到相同服务的不同版本上面了。
写在最后
充分利用好服务实例的 metadata ,可以衍生出许多有意思的实践。
另外,《Nacos 架构与原理》 的电子书过段时间会放出,大家感兴趣的可以关注一下。
nacos-sdk-csharp 的地址 :https://github.com/nacos-group/nacos-sdk-csharp
本文示例代码的地址 :https://github.com/catcherwong-archive/2021/tree/main/ABTestWithNacos
以上是关于聊一聊基于Nacos的metadata完成服务间的AB测试的主要内容,如果未能解决你的问题,请参考以下文章