ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

聊一聊基于Nacos的metadata完成服务间的AB测试

2021-12-13 08:32:36  阅读:193  来源: 互联网

标签:AB http app 调用 Nacos feature 聊一聊 var builder


背景

在很多时候,产品同学或其他 boss 会有一些想法,或好或坏,都会想放到线上环境去验证,看看能不能带来更好的效果。

这其实就是一个提出假设和验证假设的过程,而 AB 测试,是验证假设的好方法。

对于服务之间的调用,这一块其实也是相当符合的。

举几个例子吧

  1. A -> B,B 进行了重构
  2. A -> B,B 进行了算法模型的调整
  3. A -> B,B 加入了新特性
  4. ...

对于这几个例子,正常的逻辑都是会让小部分用户或流量流进新的 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-sdk-csharp 的地址 :https://github.com/nacos-group/nacos-sdk-csharp

本文示例代码的地址 :https://github.com/catcherwong-archive/2021/tree/main/ABTestWithNacos

标签:AB,http,app,调用,Nacos,feature,聊一聊,var,builder
来源: https://www.cnblogs.com/catcher1994/p/15678360.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有