导读:随着业务的发展,业务上报的埋点数据会越来越多,杂乱的埋点数据不仅会消耗计算和存储成本,造成巨大的成本浪费,也无法有效的应用于业务,给业务带去数据价值,因此埋点数据的治理就很有必要。今天分享的主题是在字节跳动应用的埋点成本治理实践,本次分享从如下几个方面来介绍:
埋点在字节跳动广泛应用,因此数据规模也非常庞大,峰值流量达到1亿+/秒,增量数据达到10万亿/天。为处理这些数据,HDFS的存储增量达到10+PB/天。
庞大的数据量会给日常运维造成很多问题,如机器资源问题、成本问题、运维问题、SLA 保障问题。


为了控制新增,我们增加埋点上报管控的机制。在过去,业务上报埋点是自由的;增加了埋点上报管控后,则需要先将上报信息登记到“允许上报”列表中,只有该列表中的埋点才能够正常上报。为了让上报管控机制生效, 我们在数据链路中的 SDK 上报、实时 ETL 两个环节分别增加了对应的处理。这两个环节可以形成互补作用:
为了让业务能动态地维护和管理“允许上报”列表,我们提供了平台化的功能:业务在字节内部可以通过流量平台 ByteIO 做埋点的录入、登记、状态管理。上报管控的机制可以实现直接管控流量上报,这也是后续开展治理的基础。
为了定义无用埋点,我们会分析对比各个埋点的价值、成本,如果某个埋点的成本很高,而价值很低,那么它就是需要优先被治理的。① 埋点的成本直接与上报量相关:如果埋点的上报量越高,对它投入的计算和存储成本就越高。② 埋点的价值则从三个维度进行分析:
如果在这三个维度上某个埋点的使用非常少,那么我们认为它的价值就是略低的。为了降低无用埋点的上报,我们支持业务通过 ByteIO 平台筛选无用埋点,并且发起治理;最终确认下线的埋点将不再允许上报。通过无用埋点下线这一机制,在 2021 年节省了近亿元成本。
为了让埋点分级机制生效,首先需要把埋点分级信息发送给实时 ETL,实时 ETL 会根据该元数据信息对收集到的埋点数据增加等级标注,之后数据再整体流向下游。当下游拿到打上等级标注的数据后,会根据等级标注的信息再区分 TTL 和 SLA 的保障。
以下图数仓中的处理为例,可以看到实时 topic 里的数据已经带上等级标注信息了(priority 参数),数仓要做的是根据不同的分级结果将 topic 中的数据分发到对应的 dump 目录,再由不同的任务产出、加载到对应的分区中。
通过这一套埋点分级的处理,我们可以针对优先级不同的埋点数据提供不同的 SLA 和 TTL 保障,同时可以达到平衡计算和存储资源的目的。以任务为例,P0 的任务可以用高优的队列、专线的资源,在 dump 产出的时候就进行产出;而 P2 的任务可能就用低优的队列、混部的资源, 在错峰的时间产出。通过这样的方式,计算资源就实现了向 P0 任务倾斜。再以分区为例,P0 分区可能保持更长的 TTL,比如说保存一年以上,而 P2 可能只保存 90 天左右。通过对 P2 分区进行更频繁的删除,有限的存储资源也是向 P0 的分区倾斜的。业务可以通过 ByteIO 平台的功能直接对埋点分级信息进行管理。而通过埋点分级这套机制,我们节省了 100+PB 的 HDFS 存储。
业务可以在 ByteIO 平台配置埋点是否需要采样及采样比例。通过埋点采样的机制,在 2022 年已经节省了 3000+万的成本。
针对问题二,具体分享一些心得。作为中台,我们需要向业务侧提供明确的 3W1H,而 3W1H 中的治理什么(WHAT)、怎么治理(HOW),从前面的“治理策略”部分可以大致总结出:治理的对象是无用的、不重要的、可采样的埋点,治理的方式是采用上述的策略和工具。
为了证明这一点(WHY&WHEN),我们向业务提供了一组明确的观测指标。
在推动治理的过程中也发现,虽然提供了指标,也提供了策略,但业务很难定期的、主动的去观测相关指标,并发起治理。经过了解后发现这主要和工作模式有关系,如果把依赖业务主动的指标观测变成由系统自动的监测并发起治理,业务也可以接受。因此我们就逐步建设和推广了自动治理的机制。自动治理的主要思想是由系统自动监测指标变化,并且自动筛选可能需要治理的埋点,之后推送给业务,再由各个埋点的负责人来确认对应埋点是否需要治理。基于这个机制,我们可以逐步迈向治理常态化的目标。在自动治理机制中,面向不同的业务场景,又分出了两种模式:监督式和无监督式。监督式的自动治理适合规模比较大一点的业务,这类业务有成本上的考虑,对治理的成果也比较关注。所以我们允许业务自定义监测规则,并且可以指派明确的治理监督人监督治理的进度和成果。监督人在这个过程中可以进行一些拉群、催办、成果 review 等等操作。监督式治理目前在字节内部主要应用于抖音、头条等业务,平均每两个月会进行一次治理,在 2022 年已经节省了 4000 万元的成本。无监督式自动治理适合广泛存在的小业务,这类业务结构较简单,可以完全托管给系统、使用统一规范进行治理。无监督式自动治理目前在字节内部主要落地应用于一些小的业务,它实现的一个效果是将这部分业务的平均无用埋点占比从 60% 降到了 20%,并且维持在一个比较稳定的状态。
另外,分享一些在埋点使用情况分析上的思考。在“治理策略”部分提到,为了让业务降低无用埋点的上报,我们需要对埋点的使用情况进行分析。其中,UBA 查询因为可以直接对接特定系统,相对来说比较容易获取。而离线和实时的使用分析,则需要通过一些分析手段,去获取对应的使用情况、并进行血缘建设。
在字节的埋点数据使用过程中,离线和实时数据的传播有一定的相似性。如下图,其中每一个节点可以认为是一个离线 hive 表或实时 topic,节点之间存在明确的上下游关系。数据从根节点开始,一层层的向下传递,最终传递到各层级的节点中。除了节点间的传播外,数据也可以从节点中取出直接进行消费,比如对 hive 表的直接查询、对 topic 的直接消费等。节点间的传递、对节点的直接查询/消费,构成了整体的数据传播链路。在这个传播链路中,埋点数据最原始的形式是根节点的一行记录。假使有一条下图所示的 ETL,查询范围是「app in ('X','Y') and event in ('a','b')」,它就能够明确的表示出这部分埋点会传播到该下游节点。这个明确的范围对埋点使用情况分析以及埋点治理来说是非常重要的信息,所以需要尽可能获得。然而实际上并不总有这么理想的 ETL 和节点,更多的是:明确范围的 ETL 不在第一层,可能在第二层或第三层;或者不是直接出现这么完整的条件,而可能是多层组装之后才出现,如在第一层 ETL 中指定了 app 限制而第二层 ETL 指定了 event 限制。针对这些复杂多样的情况,理想的分析结果是:无论这个明确范围出现在了哪一层的节点、以及它是如何出现的,我们都可以分析出对应信息。
综上,为了达成完整的使用情况分析,需要达到:能够解析出各个层级 hive 表和 topic 里包含的埋点,以及各个层级 hive 表和 topic 被查询消费的埋点。为了达到上述目标,实施方法里需要包含两个要素:第一,能够解析 ETL/查询/消费里和埋点相关的逻辑;第二,能够结合 hive 表/topic 的上下游关系,将解析做逐层的传播,得到最终各个层级的结果。目前我们初步具备了这一能力,在当前的基础上接下来会做进一步的细化。
第二,根据业务现状推荐个性化的治理方案。不同的业务有各自独特的业务特性,数据规模也不一致,导致的结果就是数据表现形式也不一样。未来希望根据业务的数据表现情况,自动诊断业务当前面临的最主要问题,基于此为其推荐个性化、高收益的治理方案。
第三,拓展治理范围。当前的数据治理方案更多着眼于高成本数据的治理,后续会考虑对异常数据、低质量数据进行治理。例如:治理体积过大、流量增长不合理的异常数据,降低日常运维中遇到的问题;治理低质量数据,减少下游数据产出问题,整体提高数据的质量。
以上介绍的埋点成本治理是数据治理的重要组成部分,主要在字节跳动内部应用。目前,字节跳动也将沉淀的数据治理经验,通过火山引擎大数据研发治理套件 DataLeap 对外提供服务。作为一站式数据中台套件,DataLeap 汇集了字节内部多年积累的数据集成、开发、运维、治理、资产、安全等全套数据中台建设的经验,助力 ToB 市场客户提升数据研发治理效率、降低管理成本,欢迎大家来体验。很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭9年前。我正在创建一个Sinatra应用程序,它采用上传的CSV文件并将其内容放入哈希中。当我像这样在我的app.rb中引用这个散列时:hash=extract_values(path_to_filename)我不断收到此错误消息:undefinedmethod`bytesize'forHash:0x007fc5e28f2b90#object_idfile:utils.rblocation:bytesiz
如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。
我正在使用Devise在Rails应用程序中,并希望通过API公开一些模型数据,但应该像应用程序一样限制对API的访问。$curlhttp://myapp.com/api/v1/sales/7.json{"error":"Youneedtosigninorsignupbeforecontinuing."}很明显。在这种情况下是否有访问API的最佳实践?我更喜欢一步验证+获取数据,但这只是为了让客户的工作更轻松。他们将使用JQuery在客户端提取数据。感谢您提供任何信息!凡妮莎 最佳答案 我建议您按照以下帖子中的选项2:使用APIke
我正在开发一个Rails2.3.1网站。在整个网站中,我需要一个用于在各种页面(主页、创建帖子页面、帖子列表页面、评论列表页面等)上创建帖子的表单——只要说这个表单需要在由各种Controller)。这些页面中的每一个都显示在相应的Controller/操作中检索到的各种其他信息。例如,主页列出了最新的10篇文章、从数据库中提取的内容等。因此,我已将帖子创建表单移动到它自己的部分中,并将该部分包含在所有必要的页面中。请注意,部分POST中的表单到/questions(路由到PostsController::create——这是默认的Rails行为)。我遇到的问题是当Posts表单没有正