少儿科教频道

admin · 2010-12-01

  

  本文档的标的是将 Sentry SDK 中机能监控效力的演化置于高低文中。咱们起首总结了何如将机能监控增添到 Sentry 和 SDK, 而后咱们叙论 identified issues(已肯定的成绩) 汲取的教训经验以及管理这些成绩的步骤。

   先容

  早正在 2019 岁首,Sentry 就先河考试向 SDK 增添跟踪效力。 Python 和 JavaScript SDK 是计划和开拓第一个观念的测试平台。观念验证于 2019 年 4 月 29 日 揭晓, 并于 2019 年 5 月 7 日交付给 Sentry。 Python 和 JavaScript 是不言而喻的采用,由于它们许诺咱们实验检测 Sentry 本身的后端和前端。

   https://github.com/getsentry/sentry-python/pull/342 https://github.com/getsentry/sentry-javascript/pull/1918 https://github.com/getsentry/sentry-python/releases/tag/0.7.13 https://github.com/getsentry/sentry/pull/12952

  请防卫,上述使命与 OpenCensus 和 OpenTracing 归并酿成 OpenTelemetry 是同期间的。 Sentry 的 API 和 SDK 告终鉴戒了 OpenTelemetry 1.0 以前版本的灵感,并联络了咱们本身的设法主意。比方,咱们的 Span 状况列外与 2019 年终独揽正在 OpenTelemetry 楷模中能够找到的般配。

   https://medium.com/opentracing/a-roadmap-to-convergence-b074e5815289 https://github.com/getsentry/relay/blob/55127c75d4eeebf787848a05a12150ee5c59acd9/relay-co妹妹on/src/constants.rs#L179-L181

  运用 API 后,机能监控援手随后扩大到其余 SDK。Sentry 的机能监控 管理计划于 2020 年 7 月集体可用。 OpenTelemetry 的跟踪楷模 1.0 版于 2021 年 2 月揭晓。

   https://blog.sentry.io/2020/07/14/see-slow-faster-with-performance-monitoring https://medium.com/opentelemetry/opentelemetry-specification-v1-0-0-tracing-edition-72dd08936978

  咱们最初的告终重用了咱们现有的失误讲演机制:

   Event type 扩大了新字段。这象征着咱们能够减削工夫并急迅先河向 Sentry 发送事务,而不是计划和告终全新的摄取管道,这一次,不是 error,而是一种新的 transaction 事务范例。 https://develop.sentry.dev/sdk/event-payloads/ 因为咱们只是发送一种新型事务,所以也重用了 SDK 传输层。 因为咱们同享摄取管道(ingestion pipeline),这象征着咱们同享存储以及产生正在完全事务上的解决的很众个人。

  咱们的告终演化成清楚夸大 Transaction 和 Span 之间的差别。个人原由是重用 Event 接口的副效用。

  Transaction 与客户发作了杰出的共识。他们许诺超过外现代码中的要紧使命块,比方涉猎器页面加载或 http 任事器央浼。客户能够检查和涉猎 transaction 列外,而正在 transaction 中,span 为更细粒度的使命单位供给细致的工夫调度。

  鄙人一节中,咱们将叙论此刻模子的少许短处。

   已肯定的成绩

  固然同一 SDK 架构(hub、client、scope) 和 transaction ingestion 模子的重用有其长处,但教训提醒了少许咱们将其分为两类的成绩。

   https://develop.sentry.dev/sdk/unified-api/

  第一组与 scope 宣称相合,素质上是肯定 此刻 scope 是甚么的才干。用户代码中的手动检测以及 SDK 集成中的自愿检测都必要此操纵。

  第二组是与用于将 transaction 数据从 SDK 发送到 Sentry 的 wire 格局联系的成绩。

   Scope 宣称

  该成绩由 getsentry/sentry-javascript#3751 跟踪。

   https://github.com/getsentry/sentry-javascript/issues/3751

  Unified SDK 架构 根本上是基于每一个并发单位存正在一个 hub,每一个 hub 有一堆 client 和 scope 对。

   https://develop.sentry.dev/sdk/unified-api/

  Client 保全修设并负担经由过程 transport 向 Sentry 发送数据,而 scope 保全附加到传失事务(比方 tag 和 breadcrumb)的高低文数据。

  每一个 hub 都明确此刻的 scope 是甚么。它永远是货仓顶部的 scope。困苦的个人是 per unit of concurrency(每单元并发) 有一个 hub。

  比方,JavaScript 是存在事务轮回和异步代码实践的单线程。没有模范的手腕来承载跨异步移用使命的高低文数据。所以,关于 JavaScript 涉猎器操纵次序,惟有一个全部 hub 同享受于同步和异步代码。

  相像的景况闪现正在 Mobile SDK 上。用户祈望高低文数据(比方 tags、current user 是甚么、 breadcrumbs 以及存储正在 scope 上的其余讯息)能够从任何线程得回和树立。所以,正在这些 SDK 中,惟有一个全部 hub。

  正在这两种景况下,当 SDK 务必解决 reporting errors 时,扫数都绝对较好。跟着跟踪 transaction 和 span 的卓殊职守,scope 变得不对适存储此刻的 span,由于它局部了并发 span 的存正在。

  关于涉猎器 JavaScript,一个或者的管理计划是运用 Zone.js,Angular 框架的一个人。合键挑衅是它推广了包的巨细,而且或者会有意中影响终极用户操纵次序,由于它对 JavaScript 运转时引擎的要害个人举办了山公修补(monkey-patches)。

   https://github.com/angular/angular/blob/master/packages/zone.js/README.md

  当咱们考试为手动检测创修更浅易的 API 时,scope 宣称成绩变得尤为明明。这个设法主意是公然一个 Sentry.trace 函数,该函数将隐式宣称 tracing 和 scope 数据, 并援手同步和异步代码的深度嵌套。

  举个例子,假定有人思衡量探索 DOM 树必要众长工夫。Tracing(跟踪) 此操纵将如下所示:

  

awaitSentry.trace({op:dom,description:WalkDOMTree,},async()=>awaitwalkDomTree());

 

  运用 Sentry.trace 效力,用户正在增添计时数据时没必要忧郁保存对无误 transaction 或 span 的援用。用户能够正在 walkDomTree 函数中自正在创修子 Span,Span 将正在无误的宗旨布局中排序。

  现实 trace 函数的告终绝对浅易 (参睹存在示例告终的 PR)。但是,认识异步代码和全部集成中确当前 span 是一个尚未克制的挑衅。

   https://github.com/getsentry/sentry-javascript/pull/3697/files#diff-f5bf6e0cdf7709e5675fcdc3b4ff254dd68f3c9d1a399c8751e0fa1846fa85dbR158

  如下两个示例归纳了 scope 宣称成绩。

  无奈肯定此刻 Span

  斟酌少许必要获取对此刻 span 的援用的自愿检测代码,正在这类景况下,手动 scope 宣称不成用。

  

//SDKcodefunctionfetchWrapper(/*...*/){/*...somecodeomittedforsimplicity...*/constparent=getCurrentHub().getScope().getSpan();//<1>constspan=parent.startChild({data:{type:fetch},description:`${method}${url}`,op:http.client,});try{//...//returnfetch(...);}finally{span.finish();}}window.fetch=fetchWrapper;//Usercodeasyncfunctionf1(){consthub=getCurrentHub();lett=hub.startTransaction({name:t1});hub.getScope().setSpan(t);try{awaitfetch(https://example.com/f1);}finally{t.finish();}}asyncfunctionf2(){consthub=getCurrentHub();lett=hub.startTransaction({name:t2});hub.getScope().setSpan(t);try{awaitfetch(https://example.com/f2);}finally{t.finish();}}Promise.all([f1(),f2()]);//runf1andf2concurrently

 

  正在下面的例子中,几个并发的 fetch 央浼触发了 fetchWrapper helper 的实践。行 <1> 务必可以遵循此刻的实践流程查看到差异的 span,招致如下两个 span 树:

  

t1

 

  这象征着,当 f1 运转时,parent 务必援用 t1,而当 f2 运转时,parent 务必是 t2。可怜的是,下面的完全代码都正在力争上逛地更新和读取单个 hub 实例,所以查看到的 span 树不是肯定性的。比方,了局或者失误地为:

  

t1t2

 

  行为无奈无误肯定此刻 span 的副效用, fetch 集成的外现告终(和其余)正在JavaScript 涉猎器 SDK 当选择创修 flat transactions, 个中完全子 span 都是 transaction 的直接子代(而不是存在合意的众级树布局)。

   https://github.com/getsentry/sentry-javascript/blob/61eda62ed5df5654f93e34a4848fc9ae3fcac0f7/packages/tracing/src/browser/request.ts#L169-L178

  请防卫,其余跟踪库也面对同样的挑衅。正在 OpenTelemetry for JavaScript 中有几个(正在怒放时)成绩与肯定父跨度和无误的高低文宣称(征求异步代码)联系:

   假如运用众个 TracerProvider 实例,则高低文显露 #1932

  https://github.com/open-telemetry/opentelemetry-js/issues/1932

   何如正在不传达 parent 的景况下创修嵌套 span #1963

  https://github.com/open-telemetry/opentelemetry-js/issues/1963

   嵌套的子 span 没有获得无误的父级 #1940

  https://github.com/open-telemetry/opentelemetry-js/issues/1940

   OpenTracing shim 不会变革高低文 #2016

  https://github.com/open-telemetry/opentelemetry-js/issues/2016

   Http Span 未链接/未树立父 Span #2333

  https://github.com/open-telemetry/opentelemetry-js/issues/2333

   互相抵触的数据宣称预期

  每当咱们增添后面叙论过的 trace 函数,或许只是考试运用 Zones 管理 scope 宣称时,就会闪现预期抵触。

  此刻的 span 与 tags、breadcrumbs 等沿途存储正在 scope 中的本相使数据宣称变得错乱, 由于 scope 的某些个人旨正在仅宣称到外部函数移用中(比方,tags), 而其别人估计会宣称回移用者(比方,breadcrumbs),越发是正在闪现 error 时。

  这是一个例子:

  

functiona(){trace((span,scope)=>{scope.setTag(func,a);scope.setTag(id,123);scope.addBreadcrumb(wasina);try{b();}catch(e){//HowtoreporttheSpanIDfromthespaninb?}finally{captureMessage(hellofroma);//tags:{func:a,id:123}//breadcrumbs:[wasina,wasinb]}})}functionb(){trace((span,scope)=>{constfail=Math.random()>0.5;scope.setTag(func,b);scope.setTag(fail,fail.toString());scope.addBreadcrumb(wasinb);captureMessage(hellofromb);//tags:{func:b,id:123,fail:?}//breadcrumbs:[wasina,wasinb]if(fail){throwError(bfailed);}});}

 

  正在下面的示例中,假如 error 正在移用货仓中冒泡,咱们希冀可以讲演 error 产生正在哪一个 span(经由过程援用 SpanID)。咱们希冀有面包屑来描画产生的扫数,不管哪一个 Zones 正正在实践, 咱们希冀正在外部 Zone 中树立一个 tag 来笼罩来自父 Zone 的同名 tag, 同时承受来自父 Zone 的完全其余 tag。每一个 Zone 都有本身的 "current span"。

  完全这些差异的祈望使得很难以一种能够会意的方法重用此刻的 scope 观念、面包屑的记载方法以及这些差异的观念何如互相效用。

  结果,值得防卫的是,正在不毁坏现有 SDK API 的景况下,重组 scope 管制的变动很或者无奈已毕。现有的 SDK 观念 — 如 hubs、scopes、breadcrumbs、user、tags 和 contexts — 都务必从新修模。

   Span 摄取模子

  斟酌由如下 span 树描画的跟踪:

  

F*├─B*│├─B│├─B│├─B││├─S*││├─S*│├─B│├─B││├─S*│├─B│├─B│├─B││├─S*whereF:spancreatedonfrontendserviceB:spancreatedonbackendserviceS:spancreatedonstorageservice

 

  此跟踪解释了 3 个被检测的任事,当用户单击网页上的按钮 (F) 时,后端 (B) 实践少许使命,而后必要对存储任事 (S) 举办屡次查问。位于给定任事进口点的 Span 标有 * 以呈现它们是 transaction。

  咱们能够经由过程这个例子来对比和会意 Sentry 的 span 摄取模子与 OpenTelemetry 和其余相像跟踪体系运用的模子之间的差别。

  正在 Sentry 的 span 摄取模子中,属于 transaction 的完全 span 务必正在单个央浼中沿途发送。这象征着正在扫数 B* transaction 时代,完全 B span 都务必保全正在内存中,征求鄙人逛任事(示例中的存储任事)上破费的工夫。

  正在 OpenTelemetry 的模子中,span 正在已毕时被沿途批解决,而且一朝 a) 批次中有肯定数目的 span 或 b) 过了肯定的工夫就会发送批次。正在咱们的示例中,这或者象征着前 3 个 B 跨度将沿途批解决并发送, 而第一个 S* 事件仍正在存储任事中举办。随后,其余 B span 将沿途批解决并正在已毕时发送,直到终极 B* transaction span 也被发送。

  固然 transaction 行为将 span 组合正在沿途并探寻 Sentry 中感兴致的操纵的一种方法特殊有效, 但它们现在存正在的办法会带来卓殊的认知承担。 SDK 保卫职员和终极用户正在编写检测代码时都务必认识并正在 transaction 或 span 之间举办采用。

  正在此刻的摄取模子中仍然肯定了接上去几节中的成绩,而且都与这类二分法相合。

  事件的杂乱 JSON 序列化

  正在 OpenTelemetry 的模子中, 完全跨度都效力一样的逻辑格局。用户和检测库能够经由过程将 key-value 属性附加就任何 span 来为其供给更众含意。 wire 合同运用 span 列外将数据从一个别系发送到另一个别系。

   https://github.com/open-telemetry/opentelemetry-proto/blob/ebef7c999f4dea62b5b033e92a221411c49c0966/opentelemetry/proto/trace/v1/trace.proto#L56-L235

  与 OpenTelemetry 差异,Sentry 的模子对两品种型的 span 举办了庄敬划分:transaction span(平常称为 transactions)和 regular span。

  正在内存中,transaction span 和 regular span 有一个差别:transaction span 有一个卓殊的属性,即 transaction name。

  不过,当序列化为 JSON 时,差别更大。 Sentry SDK 以直接相像于内存中的 span 的格局将老例 span 序列化为 JSON。比拟之下,transaction span 的序列化必要将其 span 属性映照到 Sentry Event (最初用于 report errors,扩大为特意用于 transactions 的新字段),并将完全子 span 行为列外嵌入 Event 中。

   Transaction Span 获取 Event 属性

  当 transaction 从其内存呈现转换为 Event 时, 它会得回更众无奈调配给 regular span 的属性, 比方 breadcrumbs, extra, contexts, event_id, fingerprint, release, environment, user 等。

   性命周期钩子

  Sentry SDK 为 error 事务公然了一个 BeforeSend hook,许诺用户正在将事务发送到 Sentry 以前点窜和/或丢掉事务。

  当引入新的 transaction 范例事务时,很疾就定夺此类事务不会经由过程 BeforeSend hook,合键有两个原由:

   防范用户代码依附 transaction 的双重办法(偶然看起来像一个 span,偶然像一个 event,如前几节所述); 为了防范现有的 BeforeSend 函数正在编写时只斟酌到 error 而滋扰 transaction,不管是不测地变革它们、所有丢掉它们,仍旧招致少许其余意思不到的副效用。

  但是,也很明明必要某种办法的 lifecycle hook,以许诺用户实践诸如更新 transaction 称号之类的操纵。

  咱们终极竣工了中央态度,即经由过程运用 EventProcessor(一种更通用的 BeforeSend 办法)来许诺变动/丢掉 transaction 事务。这经由过程正在数据分开 SDK 以前让用户登时访候他们的数据来管理成绩,但它也出缺点,它比 BeforeSend 运用起来更杂乱,而且还泄露了从未策动显露的 transaction 二元性。

  比拟之下,正在 OpenTelemetry 中,span 经由过程 span processor,这是两性情命周期钩子:一个是正在 span 先河时,一个是正在它下场时。

   嵌套事件

  Sentry 的摄取模子不是为任事中的嵌套 transaction 而计划的。Transaction 旨正在标识任事转换。

  正在实施中,SDK 无奈防范 transaction 嵌套。终极了局或者会让用户感觉讶异,由于每笔 transaction 都邑先河一棵新树。联系这些树的独一手腕是经由过程 trace_id。

  Sentry 的计费模子是针对每一个事务的,不管是 error 事务仍旧 transaction 事务。这象征着 transaction 中的 transaction 会天生两个可计麻烦务。

  正在 SDK 中,正在 transaction 中举办 transaction 将招致外部 span 被环绕它们的最内层 transaction 吞噬。正在这些景况下,创修 span 的代码只会将它们增添到两个 transaction 之一,从而招致另一个 transaction 中的检测空隙。

  Sentry 的 UI 并非旨正在以有效的方法解决嵌套 transaction。当检查任何一个 transaction 时,就宛如 transaction 中的完全其余 transaction 都不存正在(树视图上没有直接呈现其余 transaction)。有一个 trace view 效力来可视化同享一个 trace_id 的完全 transaction, 但 trace view 仅经由过程外现 transaction 而不是子 span 来供给跟踪的概述。假如不先访候某个 transaction,就无奈导航到 trace view。

  关于这类景况(伪代码),用户对 UI 中的祈望也存正在污染:

  

#ifdo_a_database_queryreturns10results,istheuser#-seeing11transactionsintheUI?#-billedfor11transactions?#-seespanswithincreate_thumbnailintheinnermosttransactiononly?withtransaction("index-page"):results=do_a_database_query()forresultinresults:ifresult["needs_thumbnail"]:withtransaction("create-thumbnail",{"resource":result["id"]}):create_thumbnail(result)

跨度不克不及存正在于事件以外

 

  Sentry 的追踪休会所有环绕着存正在于 transaction 中的 trace 个人。这象征着数据不克不及存正在于 transaction 以外,即便它存正在于 trace 中。

  假如 SDK 没有举办 transaction,则由 instrumentation 创修的 regular span 将所有损失。也便是说,这对 Web server 来讲不是甚么成绩,由于自愿检测的 transaction 跟着每一个传入央浼先河和下场。

  Transaction 的央求正在前端(涉猎器、搬动和桌面操纵次序)上越发存在挑衅性, 由于正在这些景况下,自愿检测的 transaction 不太牢靠地捕捉完全 span,由于它们正在自愿已毕以前只络续无限的工夫。

  正在 trace 以仅行为 span 而不是 transaction 举办检测的操纵先河的景况下,会闪现另一个成绩。正在咱们的 示例跟踪中,发作 trace 的第一个 span 是因为单击按钮。假如按钮点击 F* 被检测为老例的 span 而不是 transaction,则很或者不会捕捉来自前真个数据。但是,仍会捕捉 B 和 S span,招致不完善的踪影。

  正在 Sentry 的模子中,假如一个 span 不是一个 transaction 而且没有行为 transaction 的祖宗 span,那末该 span 将不会被摄取。反过去,这象征着正在良众景况下,跟踪损失了有助于调试成绩的要害讯息,特殊是正在前端,transaction 必要正在某个时间下场但实践或者会不绝。

  自愿和手动检测面对着定夺是先河 span 仍旧 transaction 的挑衅,斟酌到如下要素,定夺越发困苦:

  假如没有 transaction,则 span 损失。

  假如仍然存正在 transaction,则存正在嵌套事件成绩。

   缺乏 Web Vitals 衡量

  Sentry 的涉猎器用具征求 Web Vitals 衡量值。不过,由于这些衡量值是运用自愿检测的 transaction 行为载体发送到 Sentry 的,是以正在自愿 transaction 已毕后由涉猎器供给的衡量值将损失。

  这会招致 transaction 损失少许 Web Vitals 或对 LCP 等目标举办非终极衡量。

   前端事件络续工夫不牢靠

  由于完全的数据都务必正在一个 transaction 中。Sentry 的涉猎器 SDK 为每一个页面加载和每一个导航创修一个 transaction。这些 transaction 务必正在某个工夫下场。

  假如正在 transaction 已毕以前闭塞涉猎器选项卡并将其发送到 Sentry,则完全征求的数据都邑损失。所以,SDK 必要平均损失所稀有据的危险与征求不完善和或者不确凿的数据的危险。

  正在查看到结果一个营谋(比方传出的 HTTP 央浼)后闲暇了一段工夫后,Transaction 就已毕了。这象征着页面加载或导航 transaction 的络续工夫是一个相称大意的值,不愿定能刷新或与其余事件比拟,由于它不克不及确凿代外任何全部和可会意的进程的络续工夫。

  咱们经由过程将 LCP Web Vital 行为涉猎器的默许机能目标来应答这一局部。不过,如上所述,LCP 值或者会正在终极肯定以前发送,所以这不是理思的管理计划。

   内存缓冲影响任事器

  如前所述,此刻的摄取模子必要 Sentry SDK 来查看内存中的完善 span 树。以恒定的并发 transaction 流运转的操纵次序将必要大批的体系资本来征求和解决跟踪数据。Web 任事器是闪现此成绩的模范案例。

  这象征着记载 100% 的 span 和 100% 的 transaction 关于很众任事器端操纵次序来讲是不成行的,由于所发作的开支太高了。

   无奈批解决事件

  Sentry 的摄取模子不援手一次摄取众个事务。特殊是,SDK 不克不及将众个 transaction 批解决为一个央浼。

  所以,当众笔 transaction 险些同时已毕时,SDK 必要为每一个 transaction 收回稀少的央浼。这类动作正在最佳的景况下黑白常低效的,正在最坏的景况下是对资本(如收集带宽和CPU周期)的紧张且有成绩的损耗。

   兼容性

  Transaction Span 的出格解决与 OpenTelemetry 不兼容。运用 OpenTelemetry SDK 检测现有操纵次序的用户无奈轻松运用 Sentry 来获取和认识他们的数据。

  Sentry 确切为 OpenTelemetry Collector 供给了一个 Sentry Exporter,不过,因为此刻的摄取模子,Sentry Exporter 有一个合键的无误性局部。

  https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/sentryexporter#known-limitations

   总结

  经由过程正在 Sentry 中构修此刻的跟踪告终,咱们学到了良众。本文档试图搜捕很众已知的局部,以行为改日刷新的本原。

  追踪是一个杂乱的中心,克服这类杂乱性并非易事。

  第一组中的成绩 - 与 scope propagation(效用域宣称) 联系的成绩 - 是 SDK 及其计划方法特有的成绩。管理这些成绩将必要对完全 SDK 举办外部架构变动,征求从新计划面包屑等旧效力, 但举办此类变动是告终浅易易用的 tracing helper(如可正在任何高低文中使命并捕捉确凿牢靠的机能数据的 trace 函数)的先决前提。请防卫,此类变动险些确定象征着揭晓新的合键 SDK 版本,这会毁坏与现有版本的兼容性。

  第二组中的成绩 - 与 span ingestion model(跨度摄取模子) 联系的成绩要杂乱得众,由于为管理这些成绩所做的任何变动都邑影响产物的更众个人,而且必要众个团队的和谐勉力。

  假使云云,对 ingestion model 举办变动将对产物发作不成揣度的踊跃影响,由于如此做会降低服从,使咱们可以征求更大都据,并削减 instrumentation 的承担。

文章推荐:

2022 年中国人工智能行业发展现状与市场规模分析 市场规模超 3000 亿元

该来的总要来! 切尔西老板将彻底退出英国市场

雷神黑武士四代开售:i7搭RTX3060不到9千元

智慧城市中 5G 和物联网的未来