作为一款面向ToB市场的产品——火山引擎A/B测试(DataTester)为了满足客户对数据安全、合规问题等需求,探索私有化部署是产品无法绕开的一条路。
 
在面向ToB客户私有化的实际落地中,火山引擎A/B测试(DataTester)也遇到了字节内部服务和企业SaaS服务都不容易遇到的问题。在解决这些问题的落地实践中,火山引擎A/B测试团队沉淀了一些流程管理、性能优化等方面的经验。
 
本文主要分享火山引擎A/B测试当前的私有化架构,遇到的主要问题以及从业务角度出发的解决思路。
 
 

火山引擎A/B测试私有化架构

 
架构图整套系统采用 Ansible+Bash 的方式构建,为了适应私有化小集群部署,既允许各实例对等部署,复用资源,实现最小三节点交付的目标,,又可以做在线、离线资源隔离提高集群稳定性。集群内可以划分为三部分:
  1. 业务服务: 主要是直接向用户提供界面或者功能服务的, 例如实验管理、实验报告、OpenAPI、数据接入等。
  2. 基础服务: 不直接面向用户,为上层服务的运行提供支撑,例如支持实验报告的计算引擎、为指标创建提供元信息的元信息服务;基础服务同时还会充当一层对基础设施的适配,用来屏蔽基础设施在 SaaS 和私有化上的差异, 例如 SaaS 采用的实时+离线的 Lambda 架构, 私有化为了减少资源开销,适应中小集群部署只保留实时部分, 计算引擎服务向上层屏蔽了这一差异。
  3. 基础设施: 内部团队提供统一私有化基础设施底座 minibase,采用宿主机和 k8s 结合的部署方式,由 minibase 适配底层操作系统和硬件, 上层业务直接对接 minibase。
 

私有化带来的挑战

挑战 1:版本管理

传统 SaaS 服务只需要部署维护一套产品供全部客户使用,因此产品只需要针对单个或几个服务更新,快速上线一个版本特性,而不需要考虑从零开始搭建一套产品。SaaS 服务的版本发布周期往往以周为单位,保持每周 1-2 个版本更新频率。但是,在私有化交付中,我们需要确定一个基线版本并且绑定每个服务的小版本号以确保相同版本下每套环境中的交付物等价,以减轻后续升级运维成本。通常,基线版本的发布周期往往以双月为单位。
版本发布周期
 
由于私有化和 SaaS 服务在架构、实现、基础底座上均存在不同,上述的发布节奏会带来一个明显的问题:
团队要投入大量的开发和测试人力集中在发版周期内做历史 Feature 的私有化适配、私有化特性的开发、版本发布的集成测试,挤占其他需求的人力排期。
为了将周期内集中完成的工作分散到 Feature 开发阶段,重新规范了分支使用逻辑、完善私有化流水线和上线流程,让研发和测试的介入时间前移。

解法:

1、分支逻辑
分支管理
 
SaaS 和私有化均基于 master 分支发布,非私有化版本周期内不特别区分 SaaS 和私有化。
私有化发布周期内单独创建对应版本的私有化分支,发布完成后向 master 分支合并。这样保证了 master 分支在任何情况下都应当能同时在 SaaS 环境和私有化环境中正常工作。
2、发布流水线
功能上线流程
发布流水线
 
内部搭建一套私有化预发布环境,建设了一套流水线,对 master 分支的 mr 会触发流水线同时在 SaaS 预发布环境和私有化预发布环境更新最新 master 分支代码,并执行自动化回归和人工回归测试。这样做的好处在于:
  • 推动了具体 Feature 的研发从技术方案设计层面考虑不同环境的 Diff 问题,减少了后期返工的成本
  • 测试同学的工作化整为零,避免短时间内的密集测试
  • 减少研发和测试同学的上下文切换成本,SaaS 和私有化都在 Feature 开发周期内完成

挑战2:性能优化

火山引擎 A/B 测试工具的报告计算是基于 ClickHouse 实现的实时分析。SaaS 采用多租户共用多个大集群的架构,资源弹性大,可以合理地复用不同租户之间的计算资源。
私有化则大部分为小规模、独立集群,不同客户同时运行的实验个数从几个到几百个不等,报告观测时间和用户习惯、公司作息相关,有明显的峰谷现象。因此实验报告产出延迟、实时分析慢等现象在私有化上更加容易暴露。

解法:

1、 实验报告体系
首先,介绍下火山引擎 A/B 测试产品的实验报告体系。以下图的实验报告为例:
从上往下看产出一个实验报告必要的输入包含:
  • 分析的日期区间及过滤条件
  • 选择合适的指标来评估实验带来的收益
  • 实验版本和对照版本
  • 报告类型, 例如:做多天累计分析、单天的趋势分析等
指标如何定义呢?
 
组成指标的核心要素包括:
  • 由用户行为产生的事件及属性
  • 预置的算子
  • 四则运算符
即对于一个用户的某几个行为按照算子的规则计算 value 并使用四则运算组合成一个指标。
由此,我们可以大概想象出一个常规的 A/B 实验报告查询是通过实验命中情况圈出实验组或对照组的人群,分析这类群体中在实验周期内的指标值。
由于 A/B 特有的置信水平计算需求,统计结果中需要体现方差等其他特殊统计值,所有聚合类计算如:求和、PV 数均需要聚合到人粒度计算。
2、 模型优化
如何区分用户命中哪一组呢?
集成 SDK 调用 A/B 分流方法的同时会上报一条实验曝光事件记录用户的进组信息,后续指标计算认为发生在进组之后的事件受到了实验版本的影响。举个例子:
进入实验版本 1 的事件 A 的 PV 数是 2,UV 数是 1,转化为查询模型是:
上述模型虽然最符合直觉,但是存在较多的资源浪费:
  • 曝光事件和普通事件存储在一张事件表中量级大
  • 曝光事件需要搜索第一条记录,扫描的分区数会随着实验时间的增加而增加
  • 曝光事件可能反复上报,计算口径中仅仅第一条曝光为有效事件
针对上述问题对计算模型做出一些优化,把曝光事件转化为属性记录在用户表中,新的模型变化为:
这么做带来的优点是:
  • 用户表不存在时间的概念,数据增长=新用户增速,规模可控
  • 用户表本身会作为维度表在原模型中引入,这类情况下减少一次 join 运算 模型优化后经测试 14 天以上实验指标多天累计报告查询时长减少 50%以上,且随实验时长增加提升。
3、 预聚合
私有化部署实施前会做前期的资源预估,现阶段的资源预估选择了“日活用户”和“日事件量”作为主要输入参数。这里暂时没有加入同时运行的实验数量是因为:
一是,我们希望简化资源计算的模型。
二是,同时运行的实验数量在大多数情况下无法提前预知。
但是该公式会引入一个问题:相同资源的集群在承载不同数量级的实验时计算量相差较大。实验数量少的场景下,当下数据处理架构轻量化,计算逻辑后置到查询侧,,指标计算按需使用,大大减轻了数据流任务的压力。
但是假设集群中同时运行 100 个实验,平均每个实验关注 3 个指标加上实验的进组人数统计,在当前查询模型下每天至少扫描事件表 100*(3+1)次,如果再叠加使用自定义过滤模板等预计算条件,这个计算量会被成倍放大,直到导致查询任务堆积数据产出延迟。
重新观察实验报告核心元素以及指标构成能发现:
  • 指标、报告类型、实验版本是可枚举且预先知晓的
  • 实验命中和人绑定,版本对比先划分出进入对照组和实验组的人,然后做指标比较
  • 基于假设检验的置信水平计算需要按人粒度计算方差
  • 现有的指标算子均可以先按人粒度计算(按....去重除外)
是否能够通过一次全量数据的扫描计算出人粒度的所有指标和实验版本?
答案是可以的:扫描当天的事件数据,根据实验、指标配置计算一张人粒度的指标表 user_agg。
通过 user_agg 表可以计算出指标计算需要的 UV 数、指标的统计值、指标的方差。如果对 user_agg 表的能力做进一步拓展,几乎可以代替原始表完成实验报告中 80%以上的指标计算,同时也很好地支持了天级时间选择切换、用户属性标签过滤等。
修改后的指标计算模型
 
通过经验数据,一个用户平均每天产生的事件量在 100-500 条不等,聚合模型通过少数几次对当天数据的全表扫描得到一张 1/100-1/500 大小的中间表,后续的指标计算、用户维度过滤均可以使用聚合表代替原始表参与运算。当然考虑到聚合本身的资源开销,收益会随着运行实验数增加而提高,而实验数量过少时可能会造成资源浪费,是否启用需要在两者之间需求平衡点。

挑战3:稳定性

私有化服务的运维通道复杂、运维压力大,因此对服务的可用性要求更加严格。A/B 测试稳定性要求最高的部分是分流服务,直接决定了线上用户的版本命中情况。
 
分流服务本身面向故障设计, 采用降级的策略避免调用链路上的失败影响全部实验结果,牺牲一部分实时性使用多级缓存保障单一基础设施离线的极端情况下分流结果依然稳定。
 
分流服务总体架构
 
我们将分流服务作为一个整体,一共使用了 3 级存储,分别是服务内存、Redis 缓存、关系型数据库。实验变动落库的同时,将变动消息写入消息队列,分流服务消费消息队列修改内存和 Redis 缓存中的实验配置,保证多节点之间的一致性和实时性。同时分流服务开启一个额外协程定期全量更新实验配置数据作为兜底策略,防止因为消息队列故障导致的配置不更新;将 Redis 视作 Mysql 的备组件,任意失效其中之一,这样分流服务即使重启依然可以恢复最新版本的分流配置,保障客户侧分流结果的稳定。
 

总结

火山引擎 A/B 测试(DataTester)脱胎于字节跳动内部工具,集成了字节内部丰富的业务场景中的 A/B 测实验经验;同时它又立足于 B 端市场,不断通过 ToB 市场的实践经验沉淀打磨产品来更好为内外部客户创造价值。
 
本文是火山引擎 A/B 测试(DataTester)团队在当前面向 ToB 客户的私有化实践中的实践分享,文中所遇到的私有化问题的破解过程也是这一产品不断打磨成熟,从 0-1 阶段走向 1-N 阶段的过程。
 
点击跳转 火山引擎DataTester官网 了解更多
 

还原火山引擎 A/B 测试产品——DataTester 私有化部署实践经验的更多相关文章

  1. 华为云对Kubernetes在Serverless Container产品落地中的实践经验

    华为云容器实例服务,它基于 Kubernetes 打造,对最终用户直接提供 K8S 的 API.正如前面所说,它最大的优点是用户可以围绕 K8S 直接定义运行应用. 这里值得一提是,我们采用了全物理机 ...

  2. 火山引擎MARS-APM Plus x 飞书 |降低线上OOM,提高App性能稳定性

    通过使用火山引擎MARS-APM Plus的memory graph功能,飞书研发团队有效分析定位问题线上case多达30例,线上OOM率降低到了0.8‰,降幅达到60%.大幅提升了用户体验,为飞书的 ...

  3. 工作流引擎在vivo营销自动化中的应用实践 | 引擎篇03

    作者:vivo 互联网服务器团队- Cheng Wangrong 本文是<vivo营销自动化技术解密>的第4篇文章,分析了在营销自动化业务引入工作流技术的背景和工作流引擎的介绍,同时介绍了 ...

  4. 史上最全存储引擎、索引使用及SQL优化的实践

    史上最全存储引擎.索引使用及SQL优化的实践 1 MySQL的体系结构概述 2. 存储引擎 2.1 存储引擎概述 2.2 各种存储引擎特性 2.2.1 InnoDB 2.2.2 MyISAM 3. 优 ...

  5. 阿里巴巴如何进行测试提效 | 阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...

  6. C#脚本引擎 CS-Script 之(三)——如何部署

    本文不但介绍了CS-Script如何部署,还介绍了CS-Script的部署后面的原理,并用一个框图详细介绍了部署中的各种细节. 一.获取资源 1.从官网上下载编译好的csscript资源:cs-scr ...

  7. 使用C#动态生成Word文档/Excel文档的程序测试通过后,部署到IIS服务器上,不能正常使用的问题解决方案

    使用C#动态生成Word文档/Excel文档的程序功能调试.测试通过后,部署到服务器上,不能正常使用的问题解决方案: 原因: 可能asp.net程序或iis访问excel组件时权限不够(Ps:Syst ...

  8. 学习笔记TF022:产品环境模型部署、Docker镜像、Bazel工作区、导出模型、服务器、客户端

    产品环境模型部署,创建简单Web APP,用户上传图像,运行Inception模型,实现图像自动分类. 搭建TensorFlow服务开发环境.安装Docker,https://docs.docker. ...

  9. springboot测试、打包、部署

    本文使用<springboot集成mybatis(一)>项目,依次介绍springboot测试.打包.部署. 大多数朋友是做后端的,也就是为其他系统或者前端UI提供Rest API服务. ...

  10. 心知天气数据API 产品的高并发实践

    心知天气数据API 产品的高并发实践 心知天气作为国内领先的商业气象服务提供商,天气数据API 产品从公司创立以来就一直扮演着很重要的角色.2009 年API 产品初次上线,历经十年,我们不断用心迭代 ...

随机推荐

  1. Leetcode刷题笔记(双指针)

    1.何为双指针 双指针主要用来遍历数组,两个指针指向不同的元素,从而协同完成任务.我们也可以类比这个概念,推广到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,可以称之为滑动窗口 ...

  2. 从源码分析 MGR 的流控机制

    Group Replication 是一种 Shared-Nothing 的架构,每个节点都会保留一份数据. 虽然支持多点写入,但实际上系统的吞吐量是由处理能力最弱的那个节点决定的. 如果各个节点的处 ...

  3. Shading-JDBC、ShadingSphere、ShardingProxy 使用详解

    ShadingSphere ​ShardingSphere是一款起源于当当网内部的应用框架,2015年在当当网内部诞生,2016年由主要开发人员张亮带入京东数科,在国内经历了当当网.电信翼支付.京东数 ...

  4. element-ui select可搜索下拉框无法在IOS或Ipad调起小键盘输入法

    参考:https://segmentfault.com/q/1010000021748033 原因:常规select是可以调起小键盘的.但是element-ui的select其实是input.并且这个 ...

  5. spring boot+vue前后端项目的分离(我的第一个前后端分离项目)

    文章目录 1.前端vue的搭建 2.后端项目的构建 pom文件中引入的jar包 yml文件用来配置连接数据库和端口的设置 application.property进行一些整合 controller层( ...

  6. Codeforces Round #553 (Div. 2)/codeforces1151

    CodeForces1151 Maxim and Biology 解析: 题目大意 每次可以使原串中的一个字符\(+1/-1\),\(Z + 1\to A, A -1\to Z\),求至少修改多少次可 ...

  7. k8s运维之pod排错

    k8s运维之pod排错 K8S是一个开源的,用于管理云平台中多个主机上的容器化应用,Kubernetes的目标是让部署容器化变得简单并且高效 K8S的核心优势: 1,基于yaml文件实现容器的自动创建 ...

  8. 从ObjectPool到CAS指令

    相信最近看过我的文章的朋友对于Microsoft.Extensions.ObjectPool不陌生:复用.池化是在很多高性能场景的优化技巧,它能减少内存占用率.降低GC频率.提升系统TPS和降低请求时 ...

  9. Python基础指面向对象:2、动静态方法

    面向对象 一.动静态方法 在类中定义的函数有多种特性 1.直接在类中定义函数 ​ 再类中直接定义函数,默认绑定给对象,类调用时有几个参数就要传几个参数,对象调用时该函数的第一个参数默认为对象 # 定义 ...

  10. 小菜鸡的学习笔记---<正则表达式(1)>

    正则表达式学习笔记(1) (纯新手学习笔记,大佬绕路 QAQ) 一.简介 正则表达式就是一种文本模式用来匹配一系列满足特定条件的字符串,可以对比一下数学里面的表达式,比如我们要用一个表达式表示一串数字 ...