22 - Traces - 观察应用程序的效能瓶颈 (6/6) - 透过真实使用者监控 RUM 来改善使用者体验

Traces - 观察应用程序的效能瓶颈 系列文章


本篇学习重点

  • 认识 Elastic APM Agent 当中,针对使用者体验出发而设计的 RUM Agent。
  • 如何使用 APM RUM Agent。
  • 透过 Kibana 如何使用 RUM Agent 所收集资料的简介。

什麽是 Elastic APM RUM Agent

真实使用者监控 (RUM, Real User Monitoring) 要解决的问题

Elastic 推出 RUM,最重要的一个目的,就是从效能的角度改善使用者体验

而改善使用者体验的方式,也就是贴近使用者端,了解使用者行为动作中发生的事,其中包含:

  • 使用者打开页面时,分别在 Frontend、Backend 端各占多少时间?
  • 在前端画面显示时,第一个 content 被载入的时间、最大的 content 被载入的时间、跑比较久的 tasks 有哪些,并且花费多少时间。
  • 开启页面的 OS、浏览器版本、地理位置…等资讯,能在进行优化时,当成优先顺序或是做法上的参考。
  • 当有 Error 发生时,能主动收集更多对於盘查问题发生原因有帮助的内容。

RUM Agent 收集了哪些东西

RUM Agent 使用浏览器依照 W3C 提出规范的一些与 Timing 相关 API,来收集 Web 页面的效能数据,包含以下四种 Timing APIs:

当中收集的资讯如下:

  • 页面载入时的各项 Metrics 数据。(DNS 查询时间、TCP 连线建立时间、TTFB, Time to first byte...等)
  • 载入前端页面资源 (JS, CSS, images, fonts, etc.) 的时间。
  • 对後端发送的 API 请求的 Metrics 数据。
  • 在 SPA, Single page application 页面中的浏览行为
  • 使用者互动的行为,例如会产生网路存取的点击行为。
  • 以使用者为出发点的载入效能 User-centric Metrics [5]。(例如:LCP、FID、CLS、Long Tasks、User Timing...等)
  • 页面相关的资讯。(URL、Referr)
  • 网路连结相关的资讯。
  • JavaScript error。
  • 支援 Distributed tracing
  • 针对收集到的数据,能进行细部检视的 Breakdown metrics 资讯。

补充:所谓 LCP、FID、CLS 的定义如下 [6]:

  • LCP (Largest Contentful Paint):最大内容完成绘制的时间,较佳的体验会是在 2.5s 内完成。
  • FID (First Input Delay):首次输入的延迟,最好在 100m 以内。
  • CLS (Cumulative Layout Shift):累计版面配置转移,例如动态注入的内容,或是没定位好的图片载入,分数应该在 0.1 以内。

21-web-vitals

使用 APM RUM Agent

首先在 APM Server 启用 RUM

首先要在 APM Server 端启用 RUM,在 apm-server.yml 中,定义相关的设定:

apm-server.rum.enabled: true
apm-server.auth.anonymous.rate_limit.event_limit: 300
apm-server.auth.anonymous.rate_limit.ip_limit: 1000
apm-server.auth.anonymous.allow_service: [your_service_name]
apm-server.rum.allow_origins: ['*']
apm-server.rum.allow_headers: ["header1", "header2"]
apm-server.rum.library_pattern: "node_modules|bower_components|~"
apm-server.rum.exclude_from_grouping: "^/webpack"
apm-server.rum.source_mapping.enabled: true
apm-server.rum.source_mapping.cache.expiration: 5m
apm-server.rum.source_mapping.index_pattern: "apm-*-sourcemap*"

  • apm-server.rum.enabled:设定为 true 以启用 RUM。
  • apm-server.auth.anonymous.*:由於 RUM 是从 Client 端直接存取 APM Server,所以要设定相关的 anonymouse 设定。
  • 以及其他 apm-server.rum.* 相关的设定,细节可参考 APM Server - Configure RUM [7]。

在 Web 专案安装 APM RUM Agent

使用 React、Vue、Angular

如果是使用 React, Vue, Angular 这些前端的框架进行开发,可以直接使用 APM RUM 已经准备好的套件。

  • React
npm install @elastic/apm-rum-react --save
  • Vue
npm install --save @elastic/apm-rum-vue
  • Angular
npm install @elastic/apm-rum-angular --save

并且参考 官方文件 - Framework-specific integrations 的范例说明。

一般安装

一般安装 APM RUM Agent 的方式有两种:

  1. 使用 script tag 来宣告以及初始化 ( <version> 要改成指定的版本):
<script src="https://<your-cdn-host>.com/path/to/elastic-apm-rum.umd.min-<version>.js" crossorigin></script>
<script>
  elasticApm.init({
    serviceName: '<instrumented-app>',
    serverUrl: '<apm-server-url>',
  })
</script>
  1. 使用 NPM 安装套件:
npm install @elastic/apm-rum --save

并且在应用程序中,将 APM 初始化:

import { init as initApm } from '@elastic/apm-rum'

const apm = initApm({

  // Set required service name (allowed characters: a-z, A-Z, 0-9, -, _, and space)
  serviceName: '',

  // Set custom APM Server URL (default: http://localhost:8200)
  serverUrl: 'http://localhost:8200',

  // Set service version (required for sourcemap feature)
  serviceVersion: ''
})

另外大部份的环境中,APM Server 不会和 APM Agent 安装的网站应用程序放在相同的网域的位置 (origin),所以要记得设定 CORS (Cross-Origin Resource Sharing) [8],避免浏览器因为安全性限制而阻挡 APM Agent 对 APM Server 传送资讯。

Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Origin: [request-origin]

产生及设定 SourceMap

要产生 SourceMap 之前,要先取得或先定义好 Web 专案的版本号 serviceVersion,这是为了让不同版本之间的 SourceMap 能有效的对应到正确版本的 js 档,所以会使用 serviceVersion 来当作比对的条件之一。

不同的前端打包或自动化工具会有不同的方式,如果是使用 WebPack 的话,会要加入类似於下方的宣告:

const webpack = require('webpack')
const serviceVersion = require("./package.json").version 
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
  entry: 'app.js',
  output: {
    filename: 'app.min.js',
    path: './dist'
  },
  devtool: 'source-map',
  plugins: [
    new webpack.DefinePlugin({'serviceVersion': JSON.stringify(serviceVersion)}),
    new TerserPlugin({
      sourceMap: true
    })
  ]
}

再针对产生出来的 SourceMap app.min.js.map 档,透过 APM Server 的 /assets/v1/sourcemaps API,上传到 APM Server 中。

以下是 CURL 的范例:

SERVICEVERSION=`node -e "console.log(require('./package.json').version);"` && \ 
curl http://localhost:8200/assets/v1/sourcemaps -X POST \
    -F sourcemap="@./dist/app.min.js.map" \
    -F service_version="$SERVICEVERSION" \
    -F bundle_filepath="http://localhost/app.min.js" \
    -F service_name="myService"
    -H "Authorization: ApiKey <token>"

另外也可以考虑将 SourceMap 上传的动作,当作一个标准的 Deployment 步骤,可以透过 Configuration Management 的工具,例如:Ansible、Pupet、Chef...等,或是在 Node.js 里在启动时直接上传。

透过 Kibana 来运用 RUM 收集的资讯

当资料透过 APM Agents 收集进入 Elasticsearch 之後,我们可以直接从 Kibana \ Observability \ User Experience 的功能选单进入专门针对 RUM 建立的 Dashboard。

21-kibana-user-experience

这部份主要是针对 Overview 来检视,若是要观看详细的资讯,其实 RUM Agent 所收集的资料,也会是 APM 当中的其中一个 Services,所以我们到 Kibana > Observability > APM > Services 中,可以看到以 RUM 收集到的前端服务,进而可以追纵到特定页面的载入行为,也能查看所有发生的 Errors,以及对应到 Logs。

21-Kibana-RUM

同时使用 Elastic Observibility 最优势的地方就是整合性,RUM 的资料透过和我们的 Distributed Tracing 整合,我们还能看到过程中後端服务执行的内容及每个 Span 处理,甚至是下了哪些 SQL 指令以及所花费的时间。

21-Kibana-RUM-distributed-tracing

参考资料

  1. W3C Navigation Timeing API
  2. W3C Resource Timing API
  3. W3C Paint Timing API
  4. W3C User Timing API
  5. 官方文件 - APM Agents - User-centric Metrics
  6. Web Vitals
  7. 官方文件 - APM Server - Configure RUM
  8. MDN Configure CORS

查看最新 Elasticsearch 或是 Elastic Stack 教育训练资讯: https://training.onedoggo.com
欢迎追踪我的 FB 粉丝页: 乔叔 - Elastic Stack 技术交流
不论是技术分享的文章、公开线上分享、或是实体课程资讯,都会在粉丝页通知大家哦!


<<:  Day 22: 人工智慧在音乐领域的应用 (AI作曲-基因演算法五 基於规则(Rule-Based)的Fitness Function)

>>:  作业系统的修课经验

#22 数据中中的特徵相关性(1)

特徵列的研究主要应用於预测活动。举例来说,在金融分析中,透过两档股票价格波动的相关,来判断他们之间的...

[Day 4] lock-free and CAS

前言 昨天聊到原子操作时提到了2个名词, 有些人可能不熟, 会在今天简单说明。明天会有相应的实作。 ...

【Day1】: STM32前言

教学宗旨 这个教学是for第一次接触STM32的人,对於已经能够熟练使用STM32的大大可能帮助不大...

[D08] placeholder

写在前面 placeholder placeholder placeholder placehold...

[机派X] Day 6 - Linux 没网路,我要怎麽发铁人赛的文章

引言 今天是机派X系列文章的第六天。 昨天介绍了 Linux 的权限管理机制以及一些相关指令,今天要...