如何构建用于确保在高峰时段能够正常运行的自动化工作负载模型
如果你曾经花费两天时间从APM工具中提取数据,只是为了回答“在我的负载测试中应该使用多少个虚拟用户?”这个问题,那么这个教程非常适合你。 通过学习这个教程,你将了解到如何在不到五分钟的时间内,直接从生产环境中的实时数据中计算出工作负载模型中所需的各个数值,而无需进行任何估算。 我们的应用场景: 每年,在黑色星期五之前的几周,性能工程师和运维人员都会面临同样的问题:有人需要为高峰期的负载测试建立工作负载模型,而且时间非常紧迫。 通常的做法是登录APM工具,导出CSV文件,在电子表格中对数据进行处理,然后根据这些数据对用户行为进行推测。这个过程需要花费数天的时间,还需要多个人参与,但最终得到的结果
如果你曾经花费两天时间从APM工具中提取数据,只是为了回答“在我的负载测试中应该使用多少个虚拟用户?”这个问题,那么这个教程非常适合你。
通过学习这个教程,你将了解到如何在不到五分钟的时间内,直接从生产环境中的实时数据中计算出工作负载模型中所需的各个数值,而无需进行任何估算。
我们的应用场景:
每年,在黑色星期五之前的几周,性能工程师和运维人员都会面临同样的问题:有人需要为高峰期的负载测试建立工作负载模型,而且时间非常紧迫。
通常的做法是登录APM工具,导出CSV文件,在电子表格中对数据进行处理,然后根据这些数据对用户行为进行推测。这个过程需要花费数天的时间,还需要多个人参与,但最终得到的结果往往还是不准确。
这个教程会向你介绍一种自动化方法,这种方法能够完全取代上述流程,让你直接通过查询工具获取所需的数据。我会使用New Relic (NRQL)和Dynatrace (USQL)来演示每一步操作,但实际上,任何能够提供会话数据和事务数据的APM平台都可以使用这种方法。
我还开发了一个名为“高峰工作负载分析器”的Java Spring Boot工具,它可以自动执行所有这些查询步骤,如果你想直接看到结果,也可以直接使用这个工具。
目录
先决条件
在开始学习本教程之前,您需要满足以下要求:
拥有 New Relic 或 Dynatrace 账户,并且已为您的应用程序激活浏览器和/或 APM 监控功能。
已安装 Java 11 或更高版本。
已安装 Maven 3.6 或更高版本。
需要拥有至少 30 天的生产环境流量数据,这些数据应涵盖某个高峰使用时段,例如去年的黑色星期五。
在本教程中会涉及到两个重要的概念,提前了解这些概念非常重要:
每秒请求数(RPS): 指您的应用程序在 1 秒内接收到的 HTTP 请求数量。这一指标是进行负载测试时的关键参考依据。
会话: 指某个用户从访问应用程序的第一个页面开始,直到离开该应用程序为止的整个访问过程。会话的数量和持续时间是计算同时在线用户数量时所依赖的基础数据。
手动负载建模存在的问题
为了理解这种方法的价值,我们有必要先了解典型的手动负载建模流程到底是怎样的:
| 手动操作步骤 | 所需人员 | >典型耗时 | >出错风险 |
|---|---|---|---|
| 登录 APM 工具,选择正确的应用程序,设置时间范围,并处理时区相关问题。 | SRE / 性能工程师 | 30–60 分钟 | 中等风险。可能会选错应用程序或时区设置。 |
| 手动滚动流量图表,以便找出业务最繁忙的那一天。 | SRE / 性能工程师 | 45–90 分钟 | 高风险。容易错过真正的高峰时段。 |
| 将每小时的数据导出为 CSV 文件,然后在 Excel 中进行分析以确定高峰使用时间。 | 性能工程师 | 1–2 小时 | 高风险。可能存在数据导出限制或分析错误。 |
| 从 APM 的交易记录中手动筛选出最频繁发生的交易操作。 | 性能工程师 + 开发人员 | 2–3 小时 | 高风险。没有采用任何权重计算方法。 |
| 通过与开发人员和产品负责人进行交流,重新梳理用户的使用流程。 | 性能工程师 + 商业分析师 + 开发人员 | 4–8 小时 | 风险非常高。结果很大程度上取决于主观判断。 |
| 使用手动公式根据会话数量来估算同时在线用户数。 | 性能工程师 | 1–2 小时 | 高风险。Little 定律在实际情况中很少被应用。 |
| 根据 SLA 文档或团队对过去事件的经验来设定 SLA 阈值。 | 性能工程师 + 架构师 | 1–2 小时 | 中等风险。文档内容往往容易过时。 |
| 编写负载建模文档并获取相关人员的签字确认。 | 性能工程师 + 管理人员 | 3–4 小时 | 中等风险。需要经过多次修改才能完成。 |
| 总计 | 2–4 人 | 13–22 小时 | 整体而言,风险非常高 |
上述所估算的 13–22 小时时间,并没有包括来回审核、等待 APM 授权所需的时间,也没有包括几乎每个团队都会遇到的“因为时间设置错误,需要重新进行操作”的情况。
在实际操作中,大多数组织会花费相当于一个完整迭代周期的时间来构建工作负载模型,但在进行负载测试时才会发现,这些模型中的场景权重设置仍然是错误的。
除了耗费大量开发时间外,手工制作的工作负载模型还会带来直接的业务风险:如果模型低估了高峰时期的流量需求,就会导致资源配置不足;而如果模型基于错误的用户使用流程假设来构建,那么负载测试的资源就会被浪费在那些影响较小的业务场景上。
这两种情况都会意味着,你在“黑色星期五”这类高峰促销活动前的准备工作实际上都是建立在猜测的基础上,而这些风险往往要等到最糟糕的时刻才会显现出来。
自动化方法:有哪些变化?
本文介绍的方法用直接且可重复执行的观测查询来替代上述所有手工操作步骤。以下是采用自动化方法后同样的活动列表:
| 自动化任务 | 所需人员 | 耗时 | >准确性 |
|---|---|---|---|
| 使用“高峰工作负载分析工具”:输入时间范围、选择应用程序名称,然后点击“运行”。 | 任何工程师均可操作 | 设置只需2分钟 | 结果完全准确,数据驱动 |
| 应用程序会自动执行高峰日的流量分析查询。 | 自动化流程 | 自动化流程 | 结果完全准确,数据来源于实时监测数据 |
| 应用程序会自动执行高峰时段及具体高峰时间的流量分析查询。 | 自动化流程 | 自动化流程 | 结果完全准确,时间间隔最小为1分钟 |
| 应用程序会自动组合多种场景进行综合分析。 | 自动化流程 | 自动化流程 | 结果完全准确,符合实际业务分布情况 |
| 应用程序会根据会话数据自动计算用户数量。 | 自动化流程 | 自动化流程 | 准确性很高,计算方法基于数学公式 |
| 应用程序会自动生成用户使用流程及各场景的权重设置。 | 自动化流程 | 自动化流程 | 结果完全准确,数据来源于会话记录 |
| 应用程序会生成交互式的HTML仪表板以及可导出的JSON报告。 | 自动化流程 | 自动化流程 | 准确性很高,所有数据均可追溯 |
| 总计: | 1人 | 不到5分钟 | 准确性很高,一切基于客观数据 |
使用“高峰工作负载分析工具”,原本需要13到22个人小时才能完成的分析工作,现在只需一名工程师在5分钟内就能完成。这样一来,每个高峰准备周期所需的时间减少了99%,而且还会自动生成完整的分析仪表板和JSON报告。整个过程中不需要编写查询语句、使用电子表格或进行手工计算。
在本文的第一部分中,我们介绍了“高峰工作负载分析工具”这一应用程序;后续章节则会详细说明其技术实现细节:该工具在每一步会执行哪些具体的查询操作、应用了哪些计算公式,以及各项决策背后的逻辑依据。
这份文档既为那些希望了解该工具内部工作机制的工程师提供了技术参考,同时也为那些喜欢直接手动执行查询操作的团队提供了实用的操作指南。
1. 峰值工作负载分析工具
峰值工作负载分析工具是一款基于Java Spring Boot开发的应用程序,它能够通过一个命令完整地执行自动化工作负载建模流程。
该工具可直接与New Relic或Dynatrace连接,自动完成全部六个查询步骤,计算并发用户数、分析用户行为轨迹,并生成交互式实时监控面板,同时还能输出可导出的JSON格式数据,完全无需手动编写查询语句。
1.1 快速入门
# 1. 构建项目
mvn clean package
# 2. 启动Web服务器
java -jar target/peak-workload-analyzer-1.0.0.jar
# 3. 打开浏览器
open http://localhost:8080
# 4> 选择数据提供方:New Relic或Dynatrace
# 5> 输入API登录凭据
# 6> 选择分析对象并设置时间范围
# 7> 点击“开始分析”
1.2 该工具的自动执行流程
| 自动执行的步骤 | 对应的方法论环节 | 输出结果 | 对应的文档章节 |
|---|---|---|---|
| 执行高峰日的查询 | 第1步 | 高峰日期 | 第3章 |
| 执行高峰时段的查询 | 第2步 | 高峰时段 | 第4章 |
| 计算峰值分钟数并得出每秒请求数 | 第3步 | 目标每秒请求数 | 第5章 |
| 执行综合场景分析查询 | 第4步 | 各场景的权重百分比 | 第6章 |
| 通过会话数公式计算并发用户数 | 第5步 | 并发用户数量 | 第7章 |
| 分析活跃会话情况及用户池上限 | 第6步 | 用户池情况 | 第8章 |
| 生成交互式HTML监控面板及可导出的JSON报告 | 输出结果 | HTML监控面板与JSON数据 | 第9章 |
1.3 输出文件
output/
├── peak-analysis-report.json # 结构化JSON格式的各类指标数据
├── peak-analysis-report.html # 交互式监控面板(包含12个可视化组件)
├── user-journeys.json # 最常见的用户行为流程及权重百分比
└── logs/
└── analysis.log
GitHub仓库链接: 峰值工作负载分析工具。您可以克隆该仓库进行学习,或将其作为参考实现方案使用。
如果您更喜欢直接手动执行查询操作,而不是使用这款工具,那么从第3章开始的每一节内容都会详细说明该工具具体执行了哪些操作,并附有解释逻辑及预期结果的注释。
2. 方法论概述
自动化工作负载建模流程共包含六个步骤。用户首先指定一个时间范围,随后系统会逐步细化查询条件,最终确定最糟糕的情况所在。
下图展示了这六个阶段及其主要输出结果。
| 阶段 | 主要指标 | 次要指标 | 用途 |
|---|---|---|---|
| 高峰日 | 每自然日的总请求量 | 唯一会话数、平均响应时间 | 用于后续所有测试场景的基准数据计算 |
| 高峰小时 | 每小时内的请求量分布 | 每小时P50/P95/P99延迟值 | 负载测试的时间范围 |
| 高峰分钟 | 任意60秒时间窗口内的最大请求量 | 高峰日每秒请求数 = 总请求量 / 60 | 负载测试的目标每秒请求数 |
| 混合测试场景 | 各类交易类型的占比 | 各测试场景的P95延迟值、用户流失率 | 用于调整负载测试场景的权重 |
| 并发用户数 | (每小时会话数 × 平均会话时长)/ 3600 | 会话时长、每会话浏览页面数 | 负载测试引擎中的并发用户数量 |
| 活跃会话数 | 高峰分钟时的唯一会话数 | 新访问用户与重复访问用户的比例、跳出率 | 总并发用户池规模 |
2.2 增长因子的应用
通过生产环境的实时数据,你可以了解去年的高峰流量情况,但今年的峰值几乎肯定会更高。
增长因子是一种乘数,你需要用它来根据预期增长幅度调整负载测试的规模。这样,你测试的就是流量未来的发展趋势,而不是过去的实际情况。
根据你的流量变化趋势来选择合适的增长因子乘数值:
1.2倍: 保守估计——适用于已建立的平台或成熟的市场环境
1.3倍: 中等程度预测——适用于正在积极获取新用户或进入新市场的场景
1.5倍: 乐观估计——适用于最近发布了新产品或正在进行营销活动的情形
2.0倍: 极限情况——用于检测基础设施的承载能力极限
满负荷测试的目标计算公式如下:负载测试目标每分钟请求次数 = 峰值时刻的每分钟请求次数 × 增长系数 × 安全缓冲系数(1.1)
这个1.1的安全缓冲系数会在根据增长情况调整后的目标数值基础上再增加10%,这样就能考虑到在高峰时段出现的流量突发情况,因为普通的统计数据无法反映这些情况。
3. 第一步 – 确定高峰日
这个查询会汇总你在历史数据窗口内每个工作日收到的总请求量。其中请求量最大的那一天就被认定为高峰日,后续的所有分析都会以这一天作为基准。
用户需要提供开始日期和结束日期,这些日期应涵盖上一年你所在业务的高峰期。例如:2025年11月15日至2025年12月15日。
3.1 New Relic – NRQL
New Relic会将你的应用程序产生的各种监控数据存储为事件信息,你可以使用它的NRQL查询语言来对这些数据进行分析。
要找出高峰日,你需要对整个历史数据窗口内的数据进行处理,然后按工作日汇总请求量。
New Relic能够收集两种相关的数据:浏览器数据(如页面浏览次数,即真实用户在使用浏览器时所经历的操作)以及APM数据(如交易处理记录,即服务器实际处理的操作内容)。
下面的两个查询分别针对这两种数据来源进行检测,因为从用户的角度来看最繁忙的日子,应该与从服务器的角度来看最繁忙的日子是一致的;如果两者之间存在差异,那就需要进一步调查了。
3.1.1 每日浏览器页面浏览次数
-- 第一步a:确定高峰日——浏览器页面浏览数据
-- 执行方式:New Relic One > 数据查询 > 查询构建器
SELECT
count(*) AS 总页面浏览次数,
uniqueCount(session) AS 不重复会话数,
average(duration) AS 平均响应时间(毫秒),
percentile(duration, 95) AS 第95百分位响应时间(毫秒)
FROM PageView
WHERE appName = '你的应用名称'
FACET dateOf(timestamp)
SINCE '2025-11-15 00:00:00'
UNTIL '2025-12-15 23:59:59'
LIMIT 60
-- 注意:不要使用ORDER BY语句——因为uniqueCount(session)会导致PageView数据无法按顺序排序。
-- 在查询构建器中点击total_page_views列标题即可进行降序排序。
3.1.2 每日APM交易记录数
-- 第一步b:确定高峰日——APM交易记录数据(服务器端/单页应用)
SELECT
count(*) AS APM交易记录数,
rate(count(*), 1分钟) AS 平均每分钟交易次数,
average(duration) AS 平均响应时间(秒),
percentile(duration, 95) AS 第95百分位响应时间(秒),
filter(count(*), WHERE error IS TRUE) AS 错误交易记录数
FROM Transaction
WHERE
appName = '你的应用名称'
AND transactionType = 'Web'
FACET dateOf(timestamp)
SINCE '2025-11-15 00:00:00'
UNTIL '2025-12-15 23:59:59'
LIMIT 60
3.2 Dynatrace - USQL
Dynatrace也是从会话层面来解决这个问题的。它的用户会话查询语言(USQL)可以用来查询用户会话数据,其中每一行代表一次完整的用户访问记录。与直接统计单个请求量不同,这种方法是通过汇总每天的会话数量以及用户在这些会话中的总操作次数,来确定最繁忙的那一天。
下面的查询按照日历日期对会话进行分组,并根据总操作次数对结果进行排序,从而将使用量最高的那一天显示在最顶端。
// 第一步——Dynatrace USQL:确定用户会话中使用量最高的一天
SELECT
DATE(startTime) AS calendar_day,
COUNT(*) AS session_count,
SUM(userActionCount) AS total_actions,
AVG(duration) AS avg_session_ms
FROM usersession
WHERE
startTime > '2025-11-15T00:00:00'
AND startTime < '2025-12-15T23:59:59'
AND applicationType = 'BROWSER'
GROUP BY DATE(startTime)
ORDER BY total_actions DESC
下面的仪表板展示了由“高峰负载分析器”生成的查询结果。顶部的汇总卡片确认了使用量最高的那一天及其主要指标;条形图显示了整个30天周期内的请求量,其中使用量最高的一天被特别标出;表格则列出了排名前五的天数,这样你就可以清楚地看到这一天的使用量与周围日子相比究竟有多高。
4. 第二步——深入分析高峰时段
针对使用量最高的那一天,这个查询将流量划分成1小时的间隔。其中使用量最大的那个小时就是你的高峰时段,这也决定了你的负载测试所使用的时间范围。
4.1 New Relic – NRQL
现在你已经知道了使用量最高的那一天,下一步就是进一步确定这一天中哪个小时的使用量最大。下面的查询利用NRQL的TIMESERIES函数,将这一天的流量划分成1小时的间隔,这样你就可以清楚地看到一天之内负载量的变化情况。
第一个查询是基于服务器端的交易数据进行的,而第二个查询则使用了BrowserInteraction事件数据。对于那些单页应用程序来说,这类数据尤为重要,因为在这些应用中,大多数用户活动都是在不需要加载整个页面的情况下发生的。
-- 第二步a:高峰时段——服务器端交易量
SELECT
count(*) AS requests_per_hour,
rate(count(*), 1 minute) AS avg_rpm_within_hour,
average(duration) AS avg_response_sec,
percentile(duration, 50, 95, 99) AS latency_pct
FROM Transaction
WHERE
appName = 'your-app-name'
AND transactionType = 'Web'
TIMESERIES 1 hour
SINCE '2025-11-28 00:00:00'
UNTIL '2025-11-28 23:59:59'
-- 第二步b:对于单页应用程序——BrowserInteraction是关键的事件类型
SELECT
count(*) AS interactions,
uniqueCount(session) AS concurrent_sessions,
average(duration) AS avg_interaction_ms,
filter(count(*), WHERE category = 'Route change') AS navigations
FROM BrowserInteraction
WHERE appName = 'your-app-name'
TIMESERIES 1 hour
SINCE '2025-11-28 00:00:00'
UNTIL '2025-11-28 23:59:59'
4.2 Dynatrace – USQL
Dynatrace会将高峰时段的会话按小时进行划分,并根据用户操作的总次数对这些会话进行排序。最繁忙的时间段就是你的高峰小时。
由于USQL是在会话层面进行数据处理的,因此它还能提供每小时的会话数量以及P95会话时长这些数据,这些信息有助于确认:在请求量最多的那个小时,用户的参与度也是最高的。
// 第二步——使用Dynatrace USQL分析高峰小时的用户会话情况
SELECT
DATETIME(startTime, 'HH:00', 'yyyy-MM-dd HH:mm') AS peak_hour,
COUNT(*) AS session_count,
SUM(userActionCount) AS total_actions,
AVG(duration) AS avg_session_ms,
PERCENTILE(duration, 95) AS p95_session_ms
FROM usersession
WHERE
startTime > '2025-11-28T00:00:00'
AND startTime < '2025-11-28T23:59:59'
AND applicationType = 'BROWSER'
GROUP BY DATETIME(startTime, 'HH:00', 'yyyy-MM-dd HH:mm')
ORDER BY total_actions DESC
5. 第三步——分析高峰分钟
你的基础设施必须能够应对高峰分钟这一最繁忙的60秒时间段。这个数据可以帮助你确定负载测试时的RPS目标值。
计算公式: 目标RPS = 高峰分钟的请求量 / 60
5.1 New Relic – NRQL
New Relic没有内置的60秒时间间隔统计功能,因此你需要通过执行一个持续1分钟的时间序列查询来找出高峰分钟。这个查询会返回该小时内每一分钟的请求量,其中最高的那个数值就是你的高峰分钟。将这个数值除以60,就可以得到负载测试的基准RPS目标值。
-- 第三步a:在高峰小时内进一步分析高峰分钟的具体情况
-- 将“11:00:00 / 11:59:59”替换为你实际的高峰时间段
SELECT
count(*) AS requests_per_minute,
uniqueCount(session) AS active_sessions_per_min,
rate(count(*), 1 second) AS rps,
percentile(duration, 95) AS p95_latency
FROM Transaction
WHERE
appName = 'your-app-name'
AND transactionType = 'Web'
TIMESERIES 1 minute
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
-- 第三步b:获取最高的1分钟请求量
-- peak_rps就是你的负载测试基准目标值(在应用扩展系数之前)
SELECT
max(count(*)) AS peak_minute_requests,
max(rate(count(*), 1 second)) AS peak_rps
FROM Transaction
WHERE
appName = 'your-app-name'
AND transactionType = 'Web'
TIMESERIES 1 minute
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
第3步的关键结果:你现在已经确定了自己的峰值每秒请求数目标。例如:如果高峰时段的每分钟请求数为4,800次,那么基准值就是80 RPS。考虑到1.3倍的增长率以及1.1倍的安全缓冲系数,你的负载测试的最高目标值应为114 RPS。
5.2 Dynatrace – USQL
Dynatrace也是通过将高峰时段内的会话按分钟为单位进行分组,并根据请求量对它们进行排序来得到相同的结果。其中请求量最多的那分钟会被排在最顶端。由于USQL是在会话层面进行数据处理的,因此统计结果反映的是在该分钟内启动的会话数量,你也可以用同样的方法将这些会话数量转换成每秒请求数目标。
-- 第3a步:确定高峰时段的每分钟会话数量
-- 将会话按1分钟的间隔进行分组——请求量最多的那个时间段就是高峰时段
SELECT
DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm') AS peak_minute,
COUNT(*) AS session_count,
SUM(userActionCount) AS total_actions,
AVG(duration) AS avg_session_ms,
PERCENTILE(duration, 95) AS p95_session_ms
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm')
ORDER BY session_count DESC
-- 最顶行的数据就是你的高峰时段。
-- session_count表示的是会话数量,并非请求次数——关于如何计算每秒请求数,请参见下面的第3b步。
-- 第3b步:根据高峰时段内的并发用户数量来计算每秒请求数
--
-- USQL是在会话层面进行数据处理的,而非请求层面。
-- 每秒请求数的计算公式为:并发用户数量 = (该分钟内的会话数量 × 平均会话持续时间) / 60
-- 预计的每秒请求数 = 并发用户数量 / 平均响应时间
--
-- 如果你想获得更准确的每秒请求数数据,可以使用Dynatrace界面中的服务指标:
-- 进入“服务” > [你的服务名称] > “指标” > “1分钟内的请求次数”即可查看相关数据。
SELECT
DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm') AS peak_minute,
COUNT(*) AS session_count,
AVG(duration) / 1000 AS avg_duration_sec,
(COUNT(*) * (AVG(duration) / 1000)) / 60 AS concurrent_users_in_minute,
COUNT(*) / 60 AS sessions_per_second
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm')
ORDER BY session_count DESC
LIMIT 1
-- LIMIT 1只会返回高峰时段的那行数据。
-- concurrent_users_in_minute表示的是该60秒时间窗口内的并发用户数量。
-- sessions_per_second表示的是会话到达率,并非HTTP每秒请求数。

6. 第四步 – 构建场景组合
查询高峰时段各类URL和事务的实际分布情况。这样就能得到基于实际数据的场景权重,而不仅仅是估算值。
6.1 New Relic – NRQL
此步骤会查询用户在高峰时段实际进行了哪些操作,因此你所设定的场景权重是基于真实流量得出的,而非猜测结果。
New Relic提供了三种方式来获取这些数据。第一种查询方式是按事务数量对各类操作进行排序,从而确定哪些服务器端操作最为常见;第二种则是统计用户实际访问的URL,这反映了浏览器端的使用情况;第三种方法是通过“漏斗图”分析用户会话在各个关键环节中的流动情况以及哪些环节会导致会话中断。综合这些数据,你就能决定在负载测试中应包含哪些场景,以及为每个场景分配多大的权重。
-- 第4a步:场景组合 --- APM事务分布
SELECT
count(*) AS hit_count,
percentage(count(*), WHERE name IS NOT NULL) AS pct_of_total,
average(duration) AS avg_ms,
percentile(duration, 95) AS p95_ms
FROM Transaction
WHERE
appName = 'your-app-name'
AND transactionType = 'Web'
FACET name
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
LIMIT 20
ORDER BY hit_count DESC
-- 第4b步:浏览器视角 --- 用户访问最多的路由
SELECT
count(*) AS views,
uniqueCount(session) AS unique_sessions,
average(duration) AS avg_load_ms
FROM PageView
WHERE
appName = 'your-app-name'
AND pageUrl NOT LIKE '%/static/%'
AND pageUrl NOT LIKE '%/api/%'
FACET pageUrl
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
LIMIT 20
-- 注:省略了ORDER BY views DESC的排序指令 --- 因为uniqueCount(session)已经可以确保结果按访问次数降序排列。
-- 在查询构建器中点击“views”列标题即可实现降序排序。
-- 第4c步:漏斗图分析 --- 用户在各个环节中的行为轨迹及中断情况
SELECT
funnel(session,
WHERE pageUrl LIKE '%/' AS '首页',
WHERE pageUrl LIKE '%/category/%' AS '分类浏览',
WHERE pageUrl LIKE '%/search%' AS '搜索',
WHERE pageUrl LIKE '%/product/%' AS '产品详情',
WHERE pageUrl LIKE '%/cart%' AS '购物车',
WHERE pageUrl LIKE '%/checkout%' AS '结账',
WHERE pageUrl LIKE '%/confirmation%' AS '订单确认'
) AS checkout_funnel
FROM PageView
WHERE appName = 'your-app-name'
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
6.2 Dynatrace – USQL
Dynatrace版本则是根据用户的操作行为来生成场景组合的,而不是依据页面URL。它将高峰时段的各种操作按名称分类,并根据操作频率进行排序,因此最常见的用户操作会排在最前面。这些操作频率就成为了你的场景权重,其计算方式与New Relic通过事务和URL数量来得出权重的方式相同。
// 高峰时段最常见的用户操作名称 --- Dynatrace USQL
SELECT
userActionName,
COUNT(*) AS action_count,
AVG(duration) AS avg_duration_ms,
PERCENTILE(duration, 95) AS p95_ms
FROM useraction
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY userActionName
ORDER BY action_count DESC
LIMIT 206.3 示例场景组合结果
当上述查询结果被合并后,完成后的场景组合效果如下所示。每一行代表一种用户流程,其中包含了该流程在总流量中所占的比例、相应的RPS目标值以及平均响应时间和P95响应时间。这些百分比会在负载测试中作为各场景的权重使用,而“RPS”这一列则说明了应通过每种用户流程发送多少请求量。
| 场景/用户流程 | 访问次数 | 负载占比% | 目标RPS | 平均响应时间(毫秒) | P95服务水平协议指标 |
|---|---|---|---|---|---|
| 首页 → 浏览分类 | 42,840 | 28% | 23.0 | 320 | < 800毫秒 |
| 搜索 → 产品列表 | 35,200 | 23% | 18.9 | 450 | < 1,200毫秒 |
| 产品详情页 | 29,600 | 19% | 15.6 | 280 | < 700毫秒 |
| 加入购物车 | 18,400 | 12% | 9.8 | 190 | < 500毫秒 |
| 购物车 → 开始结账 | 12,800 | 8% | 6.6 | 520 | < 1,500毫秒 |
| 结账 → 支付 | 8,760 | 6% | 4.9 | 1,200 | < 3,500毫秒 |
| 订单确认 | 4,980 | 4% | 3.3 | 240 | < 600毫秒 |
7. 第五步 – 同时在线用户数
同时在线用户数是指在给定时间窗口内系统中活跃存在的用户数量。当使用会话级数据来进行计算时(New Relic Browser或Dynatrace RUM提供的数据最为可靠),正确的计算公式为:
同时在线用户数 = (每小时会话数 × 平均会话持续时间(秒))/ 3600
这个公式的依据是“并发性”的定义:如果一个会话持续D秒,且每小时有S个新会话被创建,那么在任何时刻,同时存在的会话数量应为(S × D)/ 3600。这里的除数3600用于将每小时会话数转换为每秒的新会话生成率。
示例:高峰时段有4,280个会话,平均每个会话持续444秒,因此任何时刻同时在线的用户数为529人。如果考虑增长因素,529 × 1.3 = 688个虚拟用户。
为什么不用RPS乘以平均响应时间来计算呢? RPS乘以平均响应时间的公式(基于事务层面的Little定律)用于计算同时在进行中的请求数量,这种计算方法对于确定服务器线程池的大小非常有用。而上述会话级公式则更适用于负载测试中虚拟用户数的估算,因为虚拟用户代表的是完成整个使用流程的完整用户,而不仅仅是单个HTTP请求。
最终来说,结合使用这两种计算方法才是最佳选择:用事务层面的并发性数据来评估基础设施规模,用会话层面的并发性数据来确定虚拟用户数。
7.1 New Relic – NRQL
<此步骤会将会话数据转换为负载测试引擎实际所需要的虚拟用户数量。>New Relic提供了两种查看方式。第一种查询方法会根据不同的操作结果来应用并发用户计算公式,因此你可以了解到每种场景(如转化成功、购物车被放弃、页面跳转等)分别需要多少并发用户。第二种查询方法则会将整个高峰时段的数据都纳入计算范围,从而得出一个总的并发用户数。这个数值可以用来验证你在下一步计算中得出的并发用户上限是否合理。
-- 第5a步:并发用户数 = (每小时会话数 × 平均会话时长(秒))÷ 3600
-- 按操作结果进行分组统计(而不是按会话次数分组,因为那样每个会话只会被计算一次)
-- uniqueCount(session)用于统计每个结果类别中的不同会话数量
SELECT
uniqueCount(session) AS hourly_sessions,
average(sessionDuration) AS avg_session_duration_sec,
(uniqueCount(session) * average(sessionDuration)) / 3600 AS concurrent_users
FROM PageView
WHERE appName = 'your-app-name'
FACET
CASE
WHEN latest(pageUrl) LIKE '%/confirmation%' THEN 'converted'
WHEN latest(pageUrl) LIKE '%/payment%' THEN 'payment_drop'
WHEN latest(pageUrl) LIKE '%/checkout%' THEN 'checkout_drop'
WHEN latest(pageUrl) LIKE '%/cart%' THEN 'cart_abandon'
WHEN latest(pageUrl) LIKE '%/product/%' THEN 'browse_exit'
ELSE 'early_exit'
END AS journey_outcome
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
-- 第5b步:整个高峰时段内的总并发用户数
-- 计算公式:(总会话数 × 平均会话时长(秒))÷ 3600
SELECT
uniqueCount(session) AS hourly_sessions,
average(sessionDuration) AS avg_session_duration_sec,
(uniqueCount(session) * average(sessionDuration)) / 3600 AS concurrent_users_formula,
uniqueCount(session) / 60 AS sessions_per_minute
FROM PageView
WHERE appName = 'your-app-name'
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
-- 示例输出:
-- hourly_sessions = 4,280
-- avg_session_duration_sec = 444
-- concurrent_users_formula = (4280 × 444) ÷ 3600 ≈ 528.2 → 取整为529
-- 如果考虑1.3倍的增长率,则并发用户数为529 × 1.3 = 688
7.2 Dynatrace – USQL
Dynatrace版本也使用相同的计算公式,但有一点需要注意:其中的时间长度是以毫秒为单位的,因此在计算之前需要将其除以1000才能转换为秒。该查询会返回整个高峰时段内的并发用户数,这个数值可以直接用来确定你的并发用户池规模应该设置多少。
// 并发用户数 = (每小时会话数 × 平均会话时长(秒))÷ 3600
// Dynatrace中记录的时间长度已经是毫秒单位,因此直接除以1000即可
SELECT
COUNT(*) AS hourly_sessions,
AVG(duration) / 1000 AS avg_session_duration_sec,
(COUNT(*) * AVG(duration) / 1000) / 3600 AS concurrent_users
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
-- 按不同的操作结果进行分组统计:
SELECT
COUNT(*) AS hourly_sessions,
AVG(duration) / 1000 AS avg_session_duration_sec,
(COUNT(*) * AVG(duration) / 1000) / 3600 AS concurrent_users
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY
CASE WHEN userActions.name[userActionCount - 1] LIKE '%confirmation%' THEN 'converted'
WHEN userActions.name[userActionCount - 1] LIKE '%cart%' THEN 'cart_abandon'
ELSE 'other' END
8. 第六步 – 活动会话数与总虚拟用户数量
高峰时段内的活动会话数代表了在该时间段内存在的总会话数量。这一数据可以作为配置虚拟用户池时的上限参考;而第五步中的并发用户数计算结果则能帮助我们估算同时有多少用户处于活跃状态。
在配置负载测试时,请结合使用这两个数值:
第五步得出的并发用户数:预计同时处于活跃状态的虚拟用户数量。
第六步得出的活动会话总数:高峰时段内的总会话数量。
8.1 New Relic – NRQL
这一步骤有助于确定虚拟用户池的上限:即高峰时段内活跃的独特会话总数。New Relic通过`uniqueCount(session)`这一指标提供了这一数据,同时还提供了更详细的会话信息,以便您根据这些数据来配置测试环境。
第一个查询返回的是原始的活动会话数量;其他查询则会将这些会话数据进一步细分,区分新用户与复访用户,并统计会话的深度。这些信息有助于您在负载测试场景中设定更为真实的思考时间与导航路径。
-- 第六步a:高峰时段的完整会话信息
-- total_active_sessions表示虚拟用户池的上限
-- 注意:sessionDuration和sessionPageViews是浏览器代理提供的属性,
-- 需要在您的应用中安装New Relic浏览器代理才能获取这些数据。
SELECT
uniqueCount(session) AS distinctSessions_in_peak_hour,
average(sessionDuration) AS avg_session_duration_sec,
percentile(sessionDuration, 50, 90) AS session_duration pct,
average(sessionPageViews) AS avg_pages_per_session,
filter(uniqueCount(session), WHERE sessionPageViews = 1) AS bounce_sessions,
filter(uniqueCount(session), WHERE sessionPageViews >= 5) AS engagedSessions
FROM PageView
WHERE appName = 'your-app-name'
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
-- 第六步b:新用户与复访用户的区分——这一数据会影响负载测试中的缓存预热效果。
-- nr.customAttribute.isNewUser是一个自定义属性,需要通过浏览器API进行设置:
-- newrelic.setCustomAttribute("isNewUser", true/false)
-- 如果没有安装该代理,可以使用nr.session(首次访问的用户被视为新用户)或省略此查询。
SELECT
uniqueCount(session) AS session_count,
average(duration) AS avg_page_load_ms
FROM PageView
WHEREappName = 'your-app-name'
FACET nr.customAttribute.isNewUser
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
-- 第六步c:高峰时段内每分钟活跃的会话数量
-- 通过这个数据可以了解整个小时内的流量分布情况。
-- 最高的数值代表高峰时段同时活跃的会话数。
SELECT
uniqueCount(session) AS active_sessions
FROM PageView
WHERE appName = 'your-app-name'
TIMESERIES 1 minute
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
8.2 Dynatrace – USQL
Dynatrace会将所有会话属性直接存储在usersession实体中,因此无需进行任何自定义配置。以下查询所产生的会话信息与前面使用的NRQL查询得到的结果相同,此外还包含了一些Dynatrace默认提供的额外字段。
// 步骤6a --- Dynatrace USQL:高峰时段的完整会话信息
// total_sessions表示你的虚拟用户池的最大容量
SELECT
COUNT(*) AS total Sessions,
AVG(duration) / 1000 AS avg_duration_sec,
AVG(userActionCount) AS avg_actions_per_session,
(COUNT(*) * (AVG(duration) / 1000)) / 3600 AS concurrent_users,
(COUNT(*) * (AVG(duration) / 1000)) / 3600 * 1.3 AS vus_1_3x,
(COUNT(*) * (AVG(duration) / 1000)) / 3600 * 1.3 * 1.1 AS vus_with_buffer,
SUM(CASE WHEN userActionCount = 1 THEN 1 ELSE 0 END) AS bounce_sessions,
SUM(CASE WHEN userActionCount >= 5 THEN 1 ELSE 0 END) AS engaged Sessions
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
// 步骤6b --- 新用户与复访用户的比例(内置字段,无需自定义配置)
// newUser是usersession实体中的一个布尔型字段
SELECT
SUM(CASE WHEN(newUser = TRUE THEN 1 ELSE 0 END) AS new_users,
SUM(CASE WHEN(newUser = FALSE THEN 1 ELSE 0 END) AS returning_users,
COUNT(*) AS total_sessions,
AVG(duration) / 1000 AS avg_duration_sec,
AVG(userActionCount) AS avg_actions
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
// 步骤6c --- 高峰时段每分钟的会话数量
// ORDER BY minute_slot ASC可以保证数据在折线图中的显示顺序是正确的
SELECT
DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm') AS minute_slot,
COUNT(*) AS active_sessions
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY DATETIME(startTime, 'HH:mm', 'yyyy-MM-dd HH:mm')
ORDER BY minute_slot ASC
// 步骤6d --- 会话的复杂度:每个会话包含多少个操作/页面
// 这个信息有助于分析负载测试脚本中用户的操作行为分布
SELECT
CASE
WHEN userActionCount = 1 THEN "1次操作(跳出页面)"
WHEN userActionCount BETWEEN 2 AND 3 THEN "2-3次操作"
WHEN userActionCount BETWEEN 4 AND 6 THEN "4-6次操作"
WHEN userActionCount >= 7 THEN "7次以上操作(用户持续参与测试)"
END AS depth_bucket,
COUNT(*) AS session_count
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY depth_bucket
ORDER BY session_count DESC
9. 最终的工作负载模型
在完成全部六个步骤后,工作负载模型中的每一个数值都可以直接对应到某个具体的查询结果,而不是估算值。
9.1 总结参数
此表格将六步分析过程中产生的所有数据汇总到一个工作负载模型中。左侧列显示的是根据去年峰值计算得出的数值,经过增长调整后的列则应用了您选择的乘数,而“来源查询”列则指明了每个数值具体的来源步骤,因此任何审查该模型的人都可以将其追溯到实际的遥测数据。
| 参数 | 示例值(去年峰值) | 示例值(增长调整后) | 来源查询 |
|---|---|---|---|
| 高峰日 | 2025年11月28日 | (相同参考数据) | 步骤1 NRQL/USQL |
| 高峰时段 | 11:00 – 12:00 | (相同参考数据) | 步骤2 NRQL/USQL |
| 高峰分钟每秒请求数 | 82次/秒 | 107次/秒 | 步骤3 NRQL/USQL |
| 总活跃会话数(虚拟用户池) | 4,280个 | 5,564个 | 步骤6 NRQL/USQL |
| 主要场景数量 | 7个 | 7个 | 步骤4 NRQL/USQL |
| 测试时长 | 60分钟 | 60分钟 | 步骤2 NRQL/USQL |
9.2 场景虚拟用户分配
此表格根据步骤4中确定的权重,将总的虚拟用户池分配到各个具体场景中。每行数据都包含了该场景的负载百分比、目标每秒请求数、同时运行的虚拟用户数量以及P95服务水平协议指标,这些信息足以让您直接在负载测试工具中配置相应的测试场景。
| 场景 | 示例负载百分比 | 目标每秒请求数 | 。同时运行的虚拟用户数量 | >P95服务水平协议指标 |
|---|---|---|---|---|
| 首页 → 浏览 | 28% | 23.0 | 1,558 | < 800毫秒 |
| 搜索 → PLP | 23% | 18.9 | 1,280 | < 1,200毫秒 |
| 产品详情页 | 19% | 15.6 | 1,057 | < 700毫秒 |
| 加入购物车 | 12% | 9.8 | 668 | < 500毫秒 |
| 购物车 → 结账 | 8% | 6.6 | 445 | < 1,500毫秒 |
| 结账 → 支付 | 6% | 4.9 | 334 | < 3,500毫秒 |
| 订单确认页面 | 4% | 3.3 | 222 | < 600毫秒 |
10. 用户使用流程——从登录页面到退出页面
了解用户从访问的第一个页面到离开的最后一个页面所经历的全部使用流程,是负载测试中最重要的洞察力来源。
本节并非针对抽象的“交易”过程进行建模,而是展示了如何通过一系列经过优化的查询语句,重建每个会话的具体路径:包括进入来源、导航步骤、结束节点以及最终结果。这些方法不仅能生成单个会话的详细记录,还能统计出整个使用流程中的路径次数。
FUNNEL()查询(第4步)与按会话分析的FACET查询具有不同的用途。
FUNNEL()可以统计访问了每个环节的会话数量,但无法确定某个会话是从哪个环节退出系统的。
FACET查询能够显示每个会话的进入页面和离开页面,但每条记录仅表示一个会话,而不是生成一个计数矩阵。因此需要通过单独的聚合查询(7B)来统计有多少个会话使用了相同的进入/离开路径组合。
10.1 用户旅程图
完整的电子商务购物流程共包含五个阶段,每个阶段又分为若干个步骤。在负载测试中,必须针对每个阶段分别进行建模分析,因为它们具有不同的负载特征、响应时间特点以及用户流失风险。
| 阶段 | 步骤 | :高峰时段的会话数量 | >用户流失风险 | >负载测试优先级 |
|---|---|---|---|---|
| 获取信息阶段 | 入口途径 → 主页 | 28,410个会话进入此阶段 | 13%的会话在到达主页后立即离开 | 中等风险 |
| 探索产品阶段 | 浏览/搜索 → 产品详情页 | 24,716个会话 → 17,330个会话 | 30%的会话在进入购物车页面之前离开 | >高风险 |
| 形成购买意向阶段 | 加入购物车 → 查看购物车内容 | 13,637个会话 → 8,580个会话 | 37%的会话会放弃购物车中的商品 | >非常关键 |
| 完成购买阶段 | 结账 → 支付 → 评价 | 5,054个会话 → 4,088个会话 | 7%的支付操作会失败 | >非常关键 |
| 交易完成阶段 | 订单确认 → 交易后流程 | 3,706个会话完成了交易确认 | 风险较低——会话在此阶段结束 | >低风险 |
10.2 四种查询链
要获得完整的分析结果,需要使用四种查询。每种查询都有不同的分析目的,并且用于构建负载模型中的不同部分。
| 查询类型 | 名称 | >返回的数据内容 | >用途 |
|---|---|---|---|
| 7A | 按会话记录的详细信息 | 每个会话对应一条记录,包含进入页面、离开页面、访问时长、浏览过的页面以及是否完成购买的标志 | 用于单个会话的分析、异常值检测及样本调试 |
| 7B | 进入页面与离开页面的组合统计矩阵 | 每个进入/离开路径组合对应一条记录,用于统计使用该路径的会话数量——这就是热力图的数据来源 | 用于分析各路径的使用频率,找出导致用户流失的主要环节 |
| 7C | 包含结果分类的按会话记录 | 每个会话对应一条记录,其中结果会被分为“完成购买”“放弃购物车”“结账失败”“支付失败”等类别 | 在进行聚合分析之前,用于对数据进行分析和分组 |
| 7D | 用于构建负载模型的结果统计信息 | 每个结果类别对应一条记录,包含该类别的会话数量、占总数的百分比、平均访问时长及平均浏览页面数——这些数据直接用于计算用户价值权重 | 用于为负载模型中的各种场景分配权重,是最重要的查询类型 |
10.3 查询7A——会话记录分析
此查询会为每个会话返回一行数据。它能够准确显示用户每次进入和离开页面的具体位置、会话持续的时间、访问的页面数量,以及是否完成了转化操作。需要注意的是,该查询本身无法生成热力图中的单元格计数数据,为此需要使用查询7B。
-- 查询7A:每个会话对应一行数据
-- 用途:用于分析单个会话的行为、进行调试或检测异常情况
-- 无法生成热力图中的单元格计数——该功能需通过查询7B实现
SELECT
session,
earliest(pageUrl) AS entry_page,
latest(pageUrl) AS exit_page,
count(pageUrl) AS pages_visited,
max(timestamp) - min(timestamp) AS session_duration_ms,
filter(count(*), WHERE pageUrl LIKE '%/confirmation%') AS converted
FROM PageView
WHERE appName = 'your-app-name'
FACET session
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
LIMIT 1000
-- 当在"FACET session"中使用多种聚合函数时,不支持按"session_duration_ms"列进行排序。
-- 建议在查询构建器界面中按照"session_duration_ms"列进行排序。
查询7A的示例输出:
| 会话ID | 进入页面 | 离开页面 | 。访问的页面数量 | >会话持续时间(毫秒) | >是否完成转化 |
|---|---|---|---|---|---|
| sess_a3f8c2 | / | /confirmation | 8 | 862,000 | 1(是) |
| sess_b7d1e9 | /category/electronics | /cart | 5 | 545,000 | 0(否) |
| sess_c2a4f1 | / | /cart | 4 | 348,000 | 0(否) |
| sess_d9e3b7 | /search?q=shoes | /confirmation | 6 | 693,000 | 1(是) |
| sess_e1f5a2 | /product/jacket | /product/jacket | 1 | 45,000 | 0(否) |
注意:“session_duration_ms”这一列的计算方法是max(timestamp) - min(timestamp),它表示的是用户在本次会话中首次访问页面与最后一次访问页面之间的时间差,而非响应时间。以示例中的sess_a3f8c2为例,862,000毫秒意味着整个会话持续了大约14分钟22秒。
10.4 查询7B——进入页面与离开页面的关联矩阵(即热力图数据)
这个查询用于生成热力图中的单元格计数数据。它通过同时对earliest(pageUrl)和latest(pageUrl)进行聚合操作,将会话按照用户进入的页面和离开前的最后访问页面来进行分组。count(*)这一函数则用于统计每种进入页面与离开页面组合对应的会话数量。
-- 查询7B:生成热力图单元格计数数据
-- 用途:构建路径频率矩阵、识别用户行为中出现次数最多的转折点
-- 正是这个查询产生了热力图中的数值
SELECT
count(*) AS session_count
FROM PageView
WHERE appName = 'your-app-name'
FACET
earliest(pageUrl) AS entry_page,
latest(pageUrl) AS exit_page
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
LIMIT 100
ORDER BY session_count DESC
查询7B的输出示例:
| 进入页面 | 离开页面 | 会话数 | )说明 |
|---|---|---|---|
| / | /cart | 1,840 | 从首页进入购物车但未继续操作的会话数最多 |
| /category | /cart | 2,100 | 在浏览分类页面后直接进入购物车的会话——这类会话数量最多 |
| /product | /confirmation | 1,620 | 直接通过产品详情页完成购买的会话——这些用户的购买意愿最强 |
| / | /checkout | 820 | 进入结账页面但在付款前退出的会话数 |
| /search | /cart | 980 | 在搜索结果页面后放弃继续操作的会话数 |
| / | /confirmation | 280 | 从首页开始到完成购买的完整会话流程 |
| / | (离开页面) | 954 | 从首页立即离开网站的会话数 |
如何解读热力图中的数据:
行代表记录了最早访问页面的页面;列代表记录了最后离开页面的页面。单元格值表示具有相同进入和离开页面组合的会话数。这个数值并非指会话持续时间、响应时间或请求次数。
例如:行“/”列“/cart”表示有1,840个会话从首页进入购物车,但之后没有继续操作。
10.5 查询7C——按会话结果分类
查询7C在查询7A的基础上添加了CASE语句,根据用户的离开页面将每个会话归类到相应的结果类别中。这是进行数据汇总之前的中间步骤,它允许你在汇总之前仔细分析每个结果类别中的具体会话情况。
-- 查询7C:按会话结果分类
-- 用途:针对不同结果类别进行分析,查看每个结果的详细会话数据
-- 中间步骤——先运行查询7D获取汇总数据
SELECT
session,
earliest(pageUrl) AS entry_page,
latest(pageUrl) AS exit_page,
count(pageUrl) AS pages_visited,
max(timestamp) - min(timestamp) AS session_duration_ms,
filter(count(*), WHERE pageUrl LIKE '%/confirmation%') AS converted,
CASE
WHEN latest(pageUrl) LIKE '%/confirmation%' THEN 'converted'
WHEN latest(pageUrl) LIKE '%/payment%' THEN 'payment_drop'
WHEN latest(pageUrl) LIKE '%/checkout%' THEN 'checkout_drop'
WHEN latest(pageUrl) LIKE '%/cart%' THEN 'cart_abandon'
WHEN latest(pageUrl) LIKE '%/product/%' THEN 'browse_exit'
ELSE 'early_exit'
END AS journey_outcome
FROM PageView
WHEREappName = 'your-app-name'
FACET session
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
LIMIT 1000
10.6 查询7D——工作负载模型的结果统计(最重要部分)
在负载测试中,查询7D是这一章节中最有价值的工具。它将所有会话数据分为六类,并分别计算每类的数量、平均耗时以及平均页面数。“占总数的百分比”这一数值直接对应于您在k6或JMeter配置中设定的虚拟用户权重。
-- 查询7D:工作负载模型的结果统计
-- 用途:场景权重分配——%total对应于负载测试中的虚拟用户权重
-- 这个查询用实际生产数据替代了主观评估结果
SELECT
count(*) AS session_count
FROM PageView
WHERE appName = 'your-app-name'
FACET
CASE
WHEN latest(pageUrl) LIKE '%/confirmation%' THEN 'converted'
WHEN latest(pageUrl) LIKE '%/payment%' THEN 'payment_drop'
WHEN latest(pageUrl) LIKE '%/checkout%' THEN 'checkout_drop'
WHEN latest(pageUrl) LIKE '%/cart%' THEN 'cart_abandon'
WHEN latest(pageUrl) LIKE '%/product/%' THEN 'browse_exit'
ELSE 'early_exit'
END AS journey_outcome
SINCE '2025-11-28 11:00:00'
UNTIL '2025-11-28 11:59:59'
查询7D的输出结果,这些数据直接用于分配负载测试场景中的虚拟用户权重:
| 结果类型 | 会话数量 | :占总数的百分比 | 平均耗时 | )平均页面数 | >负载测试场景用途 |
|---|---|---|---|---|---|
| browse_exit | 7,214 | 25.4% | 3分钟08秒 | 2.8页 | 仅用于浏览的场景——虚拟用户权重为25% |
| cart_abandon | 5,380 | 18.9% | 5分钟12秒 | 4.1页 | 用于放弃购物车的场景——虚拟用户权重为19%,主要测试购物车API |
| early_exit | 4,694 | 16.5% | 0分钟52秒 | 1.1页 | 用于用户立即离开的场景——虚拟用户权重为16%,用户的思考时间极短 |
| checkout_drop | 4,396 | 15.5% | 8分钟44秒 | 5.9页 | 用于放弃结账流程的场景——虚拟用户权重为15%,主要测试结算页面 |
| converted | 3,706 | 13.1% | 14分钟20秒 | 8.2页 | 完整购买流程场景——虚拟用户权重为13%,属于最关键的路径 |
| payment_drop | 3,020 | 10.6% | 11分钟02秒 | 7.1页 | 用于用户放弃付款流程的场景——虚拟用户权重为11%,主要测试支付API |
10.7 Dynatrace——其对应的USQL查询语句
Dynatrace在路径分析方面具有显著优势:usersession实体本身就存储了用户会话期间的所有操作序列。通过数组索引即可获取第一个和最后一个操作,完全不需要使用子查询或双重FACET分析。
// Dynatrace的USQL查询语句:按会话记录分析用户行为路径及结果
// usersession实体直接存储了完整的操作序列
SELECT
sessionId,
userActions.name[0] AS entry_action,
userActions.name[userActionCount - 1] AS exit_action,
COUNT(userActions) AS total_actions,
duration AS session_ms,
CASE WHEN userActions.name[userActionCount - 1]
LIKE '%confirmation%' THEN 'converted'
ELSE 'not_converted' END AS outcome
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
ORDER BY duration DESC
LIMIT 500
// Dynatrace USQL:热图统计——无需子查询
// userActions.name[0]表示第一个操作,[-1]表示最后一个操作
SELECT
userActions.name[0] AS 进入操作,
userActions.name[userActionCount - 1] AS 离开操作,
COUNT(*) AS 会话次数
FROM usersession
WHERE
startTime > '2025-11-28T11:00:00'
AND startTime < '2025-11-28T11:59:59'
AND applicationType = 'BROWSER'
GROUP BY
userActions.name[0],
userActions.name[userActionCount - 1]
ORDER BY session_count DESC
LIMIT 50
11. 结论
如果你已经完整地按照本教程进行了操作,那么你现在就拥有一个工作负载模型,在这个模型中,每一个数值(每秒请求数目标值、虚拟用户数量、场景权重、测试时长)都对应着针对真实流量的具体观测查询结果。
这种可追溯性正是让负载测试具有可信度的关键:你可以清楚地说明为什么选择114次每秒请求数而不是随意猜测为100次,也可以明确说明为什么你的结账场景会分配到15%的虚拟用户资源,而不是在会议中有人随意估算出的数值。
下一步是从GitHub上克隆Peak Workload Analyzer工具,将其配置为你自己的New Relic或Dynatrace账户,然后使用它来分析去年的高峰时段数据。测试结果将会告诉你,当前的负载测试配置是否是根据真实流量数据设定的,还是仅仅基于某次规划会议中的估算得出的。
核心原则:在你的负载测试配置中,每一个数值都应该能够追溯到针对真实生产数据的查询结果。如果你无法找到能够证明某个虚拟用户数量、每秒请求数目标值或场景权重合理性的观测数据,那么这个数值就只是个猜测而已。这种方法能够彻底消除在准备高峰负载测试时出现的随意猜测行为。
11.1 快速参考:完整的查询序列
| 步骤 | 目的 | New Relic (NRQL) | Dynatrace (USQL) | 输出结果 |
|---|---|---|---|---|
| 1 | 高峰日 | PageView/Transaction维度,dateOf(timestamp)字段 | usersession,GROUP BY DATE(startTime),ORDER BY total_actions DESC | 高峰日期 |
| 2 | 高峰时段 | Transaction维度,1小时时间序列 | usersession,GROUP BY DATETIME(startTime,'HH:00',...),ORDER BY total_actions DESC | 高峰时段 |
| 3 | 高峰分钟/每秒请求数 | Transaction维度,1分钟时间序列 | usersession,GROUP BY DATETIME(startTime,'HH:mm',...),ORDER BY session_count DESC | 高峰分钟数+每秒请求数 |
| 4 | 场景组合分析 | Transaction维度,name字段;PageView维度,pageUrl字段 | useraction维度,GROUP BY userActionName,ORDER BY action_count DESC | 各场景的权重百分比 |
| 5 | 每个场景的虚拟用户数量 | (uniqueCount(session) × average(sessionDuration)) / 3600,Journey_outcome维度 | (COUNT(*) × AVG(duration)/1000) / 3600 | 每个场景的虚拟用户数量 |
| 6 | 总虚拟用户资源池 | uniqueCount(session) | COUNT(), AVG(duration)/1000, (COUNT() × AVG(duration)/1000)/3600,FROM usersession | 虚拟用户资源的最大值上限 |
| 7A | 每个会话的详细记录 | SELECT session, earliest/latest(pageUrl), count(pageUrl) FROM PageView维度,session字段 | SELECT userId, userActions.name[0], userActions.name[userActionCount-1] FROM usersession | 每个会话对应1行记录 |
| 7B | 路径矩阵(热图显示) | count(*),FACET earliest(pageUrl), latest(pageUrl),ORDER BY session_count DESC | GROUP BY userActions.name[0], userActions.name[userActionCount-1] | 热图单元格中的数据数量 |
| 7C | 每个会话的数据及结果分类 | SELECT session, earliest/latest(pageUrl), CASE(latest(pageUrl)) AS journey_outcome FROM PageView维度,session字段 | SELECT userId, userActions.name[userActionCount-1], CASE(...) AS journey_outcome FROM usersession | 每个会话对应1行记录,并标明结果分类 |
| 7D | 不同结果的虚拟用户权重分布 | count(*),FACET CASE(latest(pageUrl)) AS journey_outcome | GROUP BY full CASE expression,ORDER BY session_count DESC | 各场景的权重分配比例 |
相关文章
大规模产品实验:Airbnb、Netflix、Lyft和Uber是如何针对基于大语言模型的AI功能进行因果分析的
对于基于大语言模型的AI功能而言,因果推断已不再是理论上的概念。Airbnb、Netflix、Lyft和Uber都发布了详细的工程博客文章,详细说明了他们是如何衡量产品变更对用户行为的因果影响的。 他们所使用的技术方法(如差异分析法、回归不连续性分析以及双重稳健估计等)都是标准工具。 值得关注的是,这些团队是如何在大规模应用中运用这些技术的:在哪些情况下这些方法在实际操作中会失效,他们又是如何通过补充措施来确保估算结果的可靠性,以及他们是如何将这些数据与实际的产品决策联系起来的。 如果你正在开发基于大语言模型的功能,并且是根据用户点赞率和会话时长来做出产品决策的,那么这些文章一定会改变你对测量
阅读全文
在大型语言模型应用中,当你的两个模型都出现错误时,如何通过双重鲁棒性估计方法来进行产品测试与优化?
六个月前,你们推出的这款人工智能产品开始采用“用户主动选择参与”的模式。你们进行了倾向性分析,并考虑了用户的参与程度以及查询的准确性等因素,最终发现任务完成率确实提高了8个百分点。这一数据被纳入了季度业务报告中,大家都对此感到满意。 然而,严谨的数据科学家难免会提出一些棘手的问题:你们有多确定这个倾向性模型已经考虑到了所有可能影响结果的因素?如果遗漏了某些因素,那么逻辑回归模型得出的选择概率就会不准确;又或者,如果结果回归模型的设定本身就有误——因为任务完成率与查询准确性之间的关系并非线性的,线性模型根本无法准确反映这一关系——那又会怎样呢? 你们有两个模型,但并不确定哪个是正确的,而这两个模
阅读全文
人工智能评估工程:从零开始构建一款可用于生产环境的大型语言模型评估平台【完整使用手册】
一个令人印象深刻的演示与一个值得信赖的系统之间的差距,其实是通过各种评估来衡量的。 我想先讲一个目前正在数百个工程团队中发生的真实案例。 有一个团队为法律研究开发了一个RAG应用程序。他们用40个精心挑选的问题对该程序进行了测试,结果看起来很不错,于是便向合作方展示了这个系统。合作方对它印象深刻,随后便决定将其正式投入使用。 然而在系统投入生产三周后,一名法律助理发现其中一个答案错误地引用了某项法规。工程团队查看了相关数据,发现“准确性得分”为0.91,这个数值看起来是正常的;他们还检查了答案的相关性,结果也符合标准。 但他们忽略了一个重要的指标:即“上下文完整性”。这个指标用于判断系统是否检
阅读全文
Flutter前端系统设计:在人工智能时代,如何像资深工程师一样思考
系统设计长期以来一直被视为后端领域的问题。 如果你问一群Flutter工程师“系统设计到底意味着什么”,他们中的大多数人会提到服务器架构:负载均衡器、数据库以及微服务。 但如果你让他们设计一个分布式缓存系统或画出一个消息队列的示意图,他们会犹豫不决。而当你要求他们为社交Feed应用开发Flutter客户端时,他们就会立刻打开新文件开始编写组件代码。 这种差距确实存在,不过正在迅速缩小。 随着Flutter应用程序变得越来越复杂——它们具备了实时功能、离线支持、多平台兼容性,同时还包含需要维护的人工智能生成代码——在编写任何一个组件之前所做出的架构决策,其重要性已经与后端架构相当了。 在那些以产
阅读全文