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

背景

在很多时候,产品同学或其他 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。当然这一步很多公司都会有相应的系统去管理,好比体验用户。

也可以看看下面这个流程图,基本涉及到了。

c0c81f164f6195aded362c106a63d95d.png

接下来就根据上面的这个,做一个简单的例子。

示例

首先是准备两个被调用方 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 的服务详情页大致如下:

d667698b0e20320f30e567bd7468b1a6.png

后面就是比较关键的调用方了。

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。

b9a3feefbca51db43966b4a463029a2f.png

到这里我们已经可以做到根据不同的逻辑,将用户导向到相同服务的不同版本上面了。

写在最后

充分利用好服务实例的 metadata ,可以衍生出许多有意思的实践。

另外,《Nacos 架构与原理》 的电子书过段时间会放出,大家感兴趣的可以关注一下。

nacos-sdk-csharp 的地址 :https://github.com/nacos-group/nacos-sdk-csharp

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

豆瓣评分9分+,每一部看完不禁感慨!这里是神州大地!

全世界只有3.14 % 的人关注了爆炸吧知识纪录片的一大重要意义&#xff0c;就在于它能将我们的视野和脚步&#xff0c;引向我们无法企及的地方和领域&#xff0c;又能让那些我们曾经到过的地方、经历过的人事&#xff0c;变得更有深意。今天&#xff0c;就给大家分享7部顶级纪录…

旅游社交网站 游范儿

为什么80%的码农都做不了架构师&#xff1f;>>> 应用名称&#xff1a;旅游社交网站 游范儿 应用URL地址&#xff1a;http://tumi.cloudfoundry.com/ 应用说明及使用场景&#xff1a; 用于爱好旅游的人士&#xff0c;发游记&#xff0c;以及所见所闻&#xff0c;…

C++复习(四)

C++引用(Reference) 引用(Reference)是C++相对于C语言的又一个扩充。引用类似于指针,只是在声明的时候用 & 取代了 *。引用可以看做是被引用对象的一个别名,在声明引用时,必须同时对其进行初始化。引用的声明方法如下: 类型标识符 &引用名 = 被引用对象 [例1]C…

jquery获取文档高度和窗口高度的例子

jquery获取文档高度和窗口高度&#xff0c;$(document).height()、$(window).height() $(document).height()&#xff1a;整个网页的文档高度 $(window).height()&#xff1a;浏览器可视窗口的高度 $(window).scrollTop()&#xff1a;浏览器可视窗口顶端距离网页顶端的高度&…

nginx源码学习Unix - Unix域协议

说到什么是域协议就会出现这么个解释&#xff1a; UNIX域协议并不是一个实际的协议族&#xff0c;而是在单个主机上执行客户/服务器通信的一种方法&#xff0c;所用API与在不同主机上执行客户/服务器通信所使用的API相同。UNIX域协议可以视为IPC方法之一。 我们白话解释下Unix域…

oracle12c考试内容,12c ocp考试内容

oca1z0-047(Oracle Database SQL Expert 1Z0-047) 60个题&#xff0c;90分钟&#xff0c;66%过关。/1z0-051(Oracle Database 11g: SQL Fundamentals I 1Z0-051) 64个题&#xff0c;120分钟&#xff0c;60%过关。/1z0-061(Oracle Database 12c: SQL Fundamentals 1Z0-061) 75个…

微软开源的Web测试和自动化神器 Playwright

Playwright 是微软开源的一个用于 Web 测试和自动化的框架, 提供了可靠的端到端测试, 功能非常强大, 可以在测试, 爬虫&#xff0c;自动化场景中使用。跨浏览器Playwright 支持所有现代的渲染引擎&#xff0c;包括 Chromium、WebKit 和 Firefox。跨平台在 Windows, Linux 和 ma…

史上最厉害的“1+2”!这个270年前出现的大难题,已经60多年没有出现好消息了..........

全世界只有3.14 % 的人关注了爆炸吧知识费马费马欧拉欧拉数学是科学的皇后数论是数学中的皇冠这顶皇冠每一次被举起它的光芒都在照亮数学的前方从112到“12”人类一次次逼近“哥德巴赫猜想”的真相从一张白纸到上面写满n>2的证明“费马大定理”凝聚成了一部数学史从2、3、5、…

C++复习五

C++类的成员变量和成员函数 类是一种数据类型,它类似于普通的数据类型,但是又有别于普通的数据类型。类这种数据类型是一个包含成员变量和成员函数的一个集合。 类的成员变量和普通变量一样,也有数据类型和名称,占用固定长度的内存空间。但是,在定义类的时候不能对成员变…

PowerCenter基础心得

心得学习 [转自&#xff23;&#xff33;&#xff24;&#xff2e;&#xff1a;http://blog.csdn.net/hualin_xie/article/details/4885800] 通过将近一周的学习时间&#xff0c;我大致掌握了PowerCenter 的基本架构和设计开发过程中的一些方法和技巧。PowcerCenter 也是属于典…

Git删除不存在对应远程分支的本地分支

远程分支已经删除&#xff0c;对应的本地分支还存在 # git remote show origin * remote origin Fetch URL: gitgithub.com:xxx/xxx.git Push URL: gitgithub.com:xxx/xxx.git HEAD branch: master Remote branches: master trackedrefs/remotes/origin/b1 stale (use git remo…

Java输入输出流和文件操作

操作系统中的文件和目录概念 文件与文件系统 文件是信息的一种组织形式&#xff0c;是存储在外部存储介质上的具有标志名的一组相关信息集合。 文件系统用文件概念来组织和管理存放在各种介质上的信息。文件系统提供目录机制实现文件的“按名存取”。 目录结构与文件检索 目录是…

C++复习(七)

C++构造函数 当创建一个对象时,往往需要做一些初始化工作,例如对数据成员赋值等。为了解决这个问题,C++提供了构造函数。 构造函数(Constructor)是一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户调用(用户也不能调用),而是在创建对象时自动执行。构造…

放寒假的硕博研究生将经历什么?

全世界只有3.14 % 的人关注了爆炸吧知识1月中下旬基本全国的高校都放假了&#xff0c;除了部分因为疫情滞留在学校和外地的学生&#xff0c;绝大多数的学生都会回家过年。平时自带学霸光环&#xff0c;可以借口工作学业繁忙&#xff0c;不回家&#xff0c;不用应酬&#xff0c;…

怎么在php登录首页添加样式,首页登录后怎么在首页显示用户名以及隐藏登录框?...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼index.php&#xff1a;登录页面用户名&#xff1a;密码&#xff1a;没有账号&#xff1f;立即注册——————————————————————————doaction.php&#xff1a;header("Content-type:text/html;charsetutf…

.NET 6新特性试用 | HTTP日志记录middleware

前言在以前&#xff0c;通常需要我们自己编写middleware记录HTTP请求和响应。而在.NET 6中默认就有已经实现好的middleware&#xff0c;添加了对HTTP日志记录的支持。Demo要想启用HTTP日志记录middleware十分简单&#xff1a;app.UseHttpLogging();运行程序&#xff0c;发现没有…

C++复习8

C++ this指针详解 this 是C++中的一个关键字,也是一个常量指针,指向当前对象(具体说是当前对象的首地址)。通过 this,可以访问当前对象的成员变量和成员函数。 所谓当前对象,就是正在使用的对象,例如对于stu.say();,stu 就是当前对象,系统正在访问 stu 的成员函数 say…

自动化测试有感

1、 研究自动化测试也有一段时间了&#xff0c;从不熟悉到慢慢的了解&#xff0c;从不会到会&#xff0c;从迷茫到清晰...... 前段时间一直都很疑惑&#xff0c;为什么要自动化&#xff0c;自动化能给我们带来哪些好处&#xff1f;它存在的价值在哪里&#xff1f;运行一个脚本…

iOS 集合的深复制与浅复制

2019独角兽企业重金招聘Python工程师标准>>> 概念 对象拷贝有两种方式&#xff1a;浅复制和深复制。顾名思义&#xff0c;浅复制&#xff0c;并不拷贝对象本身&#xff0c;仅仅是拷贝指向对象的指针&#xff1b;深复制是直接拷贝整个对象内存到另一块内存中。 一图以…

linux实时进程优先级rt,Linux实时性- PREEMPT_RT实时抢占实现

作者&#xff1a;Paul E. McKenney翻译整理&#xff1a;土豆丝624原文链接&#xff1a;概述&#xff1a;本篇文章主要讲Linux的实时包PREEMPT_RT 是如何实现的。PREEMPT_RT 的原理PREEMPT_RT包的关键点是要使非抢占式的内核代码量尽可能的少&#xff0c;同时为了提供抢占性而必…