HarmonyOS开发网络性能监控:请求耗时分析
看不见的性能问题,用数据说话
一、背景与动机:为什么需要网络性能监控?
用户反馈:"App好慢啊!"
你问:"哪里慢?"
用户:"就是慢!"
没有监控数据,你永远不知道慢在哪里:
- 是DNS解析慢?
- 是TCP连接慢?
- 是服务器响应慢?
- 还是数据解析慢?
网络性能监控要解决的就是这个问题:
- 定位瓶颈:精确到每个阶段的耗时
- 发现问题:自动检测异常请求
- 优化依据:用数据指导优化
- 质量保障:持续监控线上性能
性能监控的关键指标
| 指标 | 说明 | 重要性 |
|---|---|---|
| DNS耗时 | 域名解析时间 | ⭐⭐⭐ |
| TCP耗时 | 连接建立时间 | ⭐⭐⭐ |
| TLS耗时 | HTTPS握手时间 | ⭐⭐⭐ |
| 首字节时间(TTFB) | 服务器响应时间 | ⭐⭐⭐⭐⭐ |
| 内容传输时间 | 数据下载时间 | ⭐⭐⭐⭐ |
| 总耗时 | 完整请求时间 | ⭐⭐⭐⭐⭐ |
二、核心原理:请求生命周期追踪
每个HTTP请求都有完整的生命周期,我们需要追踪每个阶段:
时间计算:
- DNS耗时 = TCP开始时间 - 请求开始时间
- TCP耗时 = TLS开始时间 - TCP开始时间
- TLS耗时 = 请求发送时间 - TLS开始时间
- TTFB = 首字节时间 - 请求发送时间
- 传输耗时 = 请求结束时间 - 首字节时间
- 总耗时 = 请求结束时间 - 请求开始时间
三、代码实战:完整性能监控系统
示例1:性能指标定义
// network/monitor/types.ets
/**
* 请求性能指标
*/
export interface RequestMetrics {
/** 请求ID */
requestId: string;
/** 请求URL */
url: string;
/** HTTP方法 */
method: string;
// 时间戳(毫秒)
/** 请求开始时间 */
startTime: number;
/** DNS解析完成时间 */
dnsTime?: number;
/** TCP连接完成时间 */
tcpTime?: number;
/** TLS握手完成时间 */
tlsTime?: number;
/** 请求发送完成时间 */
sendTime?: number;
/** 首字节到达时间 */
firstByteTime?: number;
/** 响应接收完成时间 */
receiveTime?: number;
/** 数据解析完成时间 */
parseTime?: number;
/** 请求结束时间 */
endTime?: number;
// 耗时(毫秒)
/** DNS解析耗时 */
dnsDuration?: number;
/** TCP连接耗时 */
tcpDuration?: number;
/** TLS握手耗时 */
tlsDuration?: number;
/** 请求发送耗时 */
sendDuration?: number;
/** 等待首字节耗时(TTFB) */
ttfb?: number;
/** 内容传输耗时 */
downloadDuration?: number;
/** 数据解析耗时 */
parseDuration?: number;
/** 总耗时 */
totalDuration?: number;
// 其他信息
/** HTTP状态码 */
statusCode?: number;
/** 响应大小(字节) */
responseSize?: number;
/** 请求大小(字节) */
requestSize?: number;
/** 是否命中缓存 */
fromCache?: boolean;
/** 是否成功 */
success?: boolean;
/** 错误信息 */
error?: string;
}
/**
* 性能统计报告
*/
export interface PerformanceReport {
/** 时间范围 */
timeRange: {
start: number;
end: number;
};
/** 请求数量 */
totalRequests: number;
/** 成功请求数 */
successRequests: number;
/** 失败请求数 */
failedRequests: number;
/** 平均耗时 */
avgDuration: number;
/** P50耗时 */
p50Duration: number;
/** P95耗时 */
p95Duration: number;
/** P99耗时 */
p99Duration: number;
/** 平均TTFB */
avgTtfb: number;
/** 总传输大小 */
totalBytes: number;
/** 按URL分组统计 */
urlStats: Map<string, UrlStats>;
}
/**
* URL统计
*/
export interface UrlStats {
url: string;
count: number;
avgDuration: number;
maxDuration: number;
minDuration: number;
errorRate: number;
}
/**
* 性能告警配置
*/
export interface PerformanceAlertConfig {
/** 慢请求阈值(毫秒) */
slowThreshold?: number;
/** 失败率阈值 */
errorRateThreshold?: number;
/** TTFB阈值 */
ttfbThreshold?: number;
/** 告警回调 */
onAlert?: (alert: PerformanceAlert) => void;
}
/**
* 性能告警
*/
export interface PerformanceAlert {
type: 'slow' | 'error' | 'ttfb';
message: string;
metrics: RequestMetrics;
timestamp: number;
}示例2:性能追踪器
// network/monitor/PerformanceTracker.ets
import { RequestMetrics, PerformanceAlert, PerformanceAlertConfig } from './types';
/**
* 性能追踪器
* 追踪单个请求的性能指标
*/
export class PerformanceTracker {
private metrics: RequestMetrics;
private alertConfig: PerformanceAlertConfig;
constructor(
requestId: string,
url: string,
method: string,
alertConfig?: PerformanceAlertConfig
) {
this.metrics = {
requestId,
url,
method,
startTime: Date.now(),
success: false
};
this.alertConfig = alertConfig || {};
}
/**
* 标记DNS解析完成
*/
markDnsComplete(): void {
this.metrics.dnsTime = Date.now();
this.metrics.dnsDuration = this.metrics.dnsTime - this.metrics.startTime;
}
/**
* 标记TCP连接完成
*/
markTcpComplete(): void {
this.metrics.tcpTime = Date.now();
this.metrics.tcpDuration = this.metrics.tcpTime -
(this.metrics.dnsTime || this.metrics.startTime);
}
/**
* 标记TLS握手完成
*/
markTlsComplete(): void {
this.metrics.tlsTime = Date.now();
this.metrics.tlsDuration = this.metrics.tlsTime -
(this.metrics.tcpTime || this.metrics.dnsTime || this.metrics.startTime);
}
/**
* 标记请求发送完成
*/
markSendComplete(requestSize?: number): void {
this.metrics.sendTime = Date.now();
this.metrics.sendDuration = this.metrics.sendTime -
(this.metrics.tlsTime || this.metrics.tcpTime || this.metrics.startTime);
this.metrics.requestSize = requestSize;
}
/**
* 标记首字节到达
*/
markFirstByte(): void {
this.metrics.firstByteTime = Date.now();
this.metrics.ttfb = this.metrics.firstByteTime -
(this.metrics.sendTime || this.metrics.tlsTime || this.metrics.startTime);
}
/**
* 标记响应接收完成
*/
markReceiveComplete(responseSize?: number): void {
this.metrics.receiveTime = Date.now();
this.metrics.downloadDuration = this.metrics.receiveTime -
(this.metrics.firstByteTime || this.metrics.sendTime || this.metrics.startTime);
this.metrics.responseSize = responseSize;
}
/**
* 标记数据解析完成
*/
markParseComplete(): void {
this.metrics.parseTime = Date.now();
this.metrics.parseDuration = this.metrics.parseTime -
(this.metrics.receiveTime || this.metrics.firstByteTime || this.metrics.startTime);
}
/**
* 标记请求成功
*/
markSuccess(statusCode: number): void {
this.metrics.endTime = Date.now();
this.metrics.statusCode = statusCode;
this.metrics.success = true;
this.metrics.totalDuration = this.metrics.endTime - this.metrics.startTime;
this.checkAlert();
}
/**
* 标记请求失败
*/
markFailed(error: string): void {
this.metrics.endTime = Date.now();
this.metrics.error = error;
this.metrics.success = false;
this.metrics.totalDuration = this.metrics.endTime - this.metrics.startTime;
this.checkAlert();
}
/**
* 标记缓存命中
*/
markCacheHit(): void {
this.metrics.fromCache = true;
this.metrics.endTime = Date.now();
this.metrics.totalDuration = this.metrics.endTime - this.metrics.startTime;
}
/**
* 获取性能指标
*/
getMetrics(): RequestMetrics {
return this.metrics;
}
/**
* 检查是否需要告警
* @private
*/
private checkAlert(): void {
if (!this.alertConfig.onAlert) return;
// 检查慢请求
if (this.alertConfig.slowThreshold && this.metrics.totalDuration) {
if (this.metrics.totalDuration > this.alertConfig.slowThreshold) {
this.alertConfig.onAlert({
type: 'slow',
message: `慢请求: ${this.metrics.url} 耗时 ${this.metrics.totalDuration}ms`,
metrics: this.metrics,
timestamp: Date.now()
});
}
}
// 检查TTFB
if (this.alertConfig.ttfbThreshold && this.metrics.ttfb) {
if (this.metrics.ttfb > this.alertConfig.ttfbThreshold) {
this.alertConfig.onAlert({
type: 'ttfb',
message: `TTFB过高: ${this.metrics.url} TTFB ${this.metrics.ttfb}ms`,
metrics: this.metrics,
timestamp: Date.now()
});
}
}
// 检查失败
if (!this.metrics.success) {
this.alertConfig.onAlert({
type: 'error',
message: `请求失败: ${this.metrics.url} ${this.metrics.error}`,
metrics: this.metrics,
timestamp: Date.now()
});
}
}
}示例3:性能监控管理器
// network/monitor/PerformanceMonitor.ets
import { RequestMetrics, PerformanceReport, UrlStats, PerformanceAlertConfig } from './types';
import { PerformanceTracker } from './PerformanceTracker';
/**
* 性能监控管理器
* 汇总和分析性能数据
*/
export class PerformanceMonitor {
private metrics: RequestMetrics[] = [];
private maxRecords: number = 1000; // 最大记录数
private alertConfig: PerformanceAlertConfig;
private enabled: boolean = true;
constructor(config?: PerformanceAlertConfig & { enabled?: boolean; maxRecords?: number }) {
this.alertConfig = config || {};
this.enabled = config?.enabled ?? true;
this.maxRecords = config?.maxRecords ?? 1000;
}
/**
* 创建性能追踪器
*/
createTracker(url: string, method: string): PerformanceTracker {
const requestId = this.generateRequestId();
return new PerformanceTracker(requestId, url, method, this.alertConfig);
}
/**
* 记录性能指标
*/
record(metrics: RequestMetrics): void {
if (!this.enabled) return;
this.metrics.push(metrics);
// 超过最大记录数,移除旧记录
if (this.metrics.length > this.maxRecords) {
this.metrics.shift();
}
// 记录日志
this.logMetrics(metrics);
}
/**
* 生成性能报告
*/
generateReport(timeRange?: { start: number; end: number }): PerformanceReport {
// 过滤时间范围
let filteredMetrics = this.metrics;
if (timeRange) {
filteredMetrics = this.metrics.filter(m =>
m.startTime >= timeRange.start && m.startTime <= timeRange.end
);
}
// 计算统计指标
const durations = filteredMetrics
.filter(m => m.totalDuration !== undefined)
.map(m => m.totalDuration!);
const ttfbs = filteredMetrics
.filter(m => m.ttfb !== undefined)
.map(m => m.ttfb!);
const report: PerformanceReport = {
timeRange: timeRange || {
start: filteredMetrics[0]?.startTime || Date.now(),
end: filteredMetrics[filteredMetrics.length - 1]?.endTime || Date.now()
},
totalRequests: filteredMetrics.length,
successRequests: filteredMetrics.filter(m => m.success).length,
failedRequests: filteredMetrics.filter(m => !m.success).length,
avgDuration: this.average(durations),
p50Duration: this.percentile(durations, 50),
p95Duration: this.percentile(durations, 95),
p99Duration: this.percentile(durations, 99),
avgTtfb: this.average(ttfbs),
totalBytes: filteredMetrics.reduce((sum, m) => sum + (m.responseSize || 0), 0),
urlStats: this.groupByUrl(filteredMetrics)
};
return report;
}
/**
* 获取慢请求
*/
getSlowRequests(threshold: number): RequestMetrics[] {
return this.metrics.filter(m =>
m.totalDuration !== undefined && m.totalDuration > threshold
);
}
/**
* 获取失败请求
*/
getFailedRequests(): RequestMetrics[] {
return this.metrics.filter(m => !m.success);
}
/**
* 清空记录
*/
clear(): void {
this.metrics = [];
}
/**
* 启用/禁用监控
*/
setEnabled(enabled: boolean): void {
this.enabled = enabled;
}
/**
* 按URL分组统计
* @private
*/
private groupByUrl(metrics: RequestMetrics[]): Map<string, UrlStats> {
const groups = new Map<string, RequestMetrics[]>();
for (const m of metrics) {
const existing = groups.get(m.url) || [];
existing.push(m);
groups.set(m.url, existing);
}
const stats = new Map<string, UrlStats>();
groups.forEach((items, url) => {
const durations = items
.filter(m => m.totalDuration !== undefined)
.map(m => m.totalDuration!);
const errorCount = items.filter(m => !m.success).length;
stats.set(url, {
url,
count: items.length,
avgDuration: this.average(durations),
maxDuration: Math.max(...durations),
minDuration: Math.min(...durations),
errorRate: errorCount / items.length
});
});
return stats;
}
/**
* 计算平均值
* @private
*/
private average(values: number[]): number {
if (values.length === 0) return 0;
return values.reduce((sum, v) => sum + v, 0) / values.length;
}
/**
* 计算百分位数
* @private
*/
private percentile(values: number[], p: number): number {
if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b);
const index = Math.ceil((p / 100) * sorted.length) - 1;
return sorted[Math.max(0, index)];
}
/**
* 生成请求ID
* @private
*/
private generateRequestId(): string {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* 记录日志
* @private
*/
private logMetrics(metrics: RequestMetrics): void {
const logLevel = metrics.success ? 'info' : 'warn';
console[logLevel](`[PerformanceMonitor] ${metrics.method} ${metrics.url}`, {
totalDuration: metrics.totalDuration,
ttfb: metrics.ttfb,
statusCode: metrics.statusCode,
success: metrics.success
});
}
}示例4:性能监控拦截器
// network/monitor/PerformanceInterceptor.ets
import { Interceptor, RequestConfig, Response } from '../types';
import { PerformanceMonitor } from './PerformanceMonitor';
import { PerformanceTracker } from './PerformanceTracker';
/**
* 性能监控拦截器
* 自动追踪所有请求的性能
*/
export class PerformanceInterceptor implements Interceptor {
private monitor: PerformanceMonitor;
constructor(monitor: PerformanceMonitor) {
this.monitor = monitor;
}
/**
* 请求拦截:创建性能追踪器
*/
async beforeRequest(config: RequestConfig): Promise<RequestConfig> {
// 创建性能追踪器
const tracker = this.monitor.createTracker(
config.url,
config.method || 'GET'
);
// 保存到配置中
(config as any).__performanceTracker = tracker;
return config;
}
/**
* 响应拦截:记录性能指标
*/
async afterResponse<T>(response: Response<T>): Promise<Response<T>> {
const tracker: PerformanceTracker = (response.config as any).__performanceTracker;
if (!tracker) {
return response;
}
try {
// 标记首字节到达
tracker.markFirstByte();
// 标记响应接收完成
const responseSize = this.estimateSize(response.data);
tracker.markReceiveComplete(responseSize);
// 标记数据解析完成
tracker.markParseComplete();
// 标记成功
tracker.markSuccess(response.status);
// 记录到监控器
const metrics = tracker.getMetrics();
this.monitor.record(metrics);
} catch (error) {
console.error('[PerformanceInterceptor] 记录性能失败:', error);
}
return response;
}
/**
* 错误处理
*/
handleError(config: RequestConfig, error: any): void {
const tracker: PerformanceTracker = (config as any).__performanceTracker;
if (tracker) {
tracker.markFailed(error.message || 'Unknown error');
const metrics = tracker.getMetrics();
this.monitor.record(metrics);
}
}
/**
* 估算数据大小
* @private
*/
private estimateSize(data: any): number {
if (!data) return 0;
if (typeof data === 'string') {
return data.length * 2; // UTF-16
}
if (data instanceof Uint8Array) {
return data.length;
}
try {
return JSON.stringify(data).length * 2;
} catch {
return 0;
}
}
}示例5:性能报告可视化
// components/PerformanceReportPanel.ets
import { PerformanceMonitor } from '../network/monitor/PerformanceMonitor';
import { PerformanceReport } from '../network/monitor/types';
/**
* 性能报告面板
* 可视化展示性能数据
*/
@Component
export struct PerformanceReportPanel {
@State monitor: PerformanceMonitor | null = null;
@State report: PerformanceReport | null = null;
@State loading: boolean = false;
aboutToAppear() {
this.loadReport();
}
/**
* 加载性能报告
*/
async loadReport() {
if (!this.monitor) return;
this.loading = true;
try {
// 生成最近1小时的报告
const end = Date.now();
const start = end - 60 * 60 * 1000;
this.report = this.monitor.generateReport({ start, end });
} catch (error) {
console.error('加载报告失败:', error);
} finally {
this.loading = false;
}
}
build() {
Column() {
// 标题
Row() {
Text('性能报告')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button('刷新')
.type(ButtonType.Capsule)
.height(32)
.onClick(() => {
this.loadReport();
})
}
.width('100%')
.padding(16)
if (this.loading) {
LoadingProgress()
.width(48)
.height(48)
} else if (this.report) {
// 概览卡片
this.overviewCard();
// 耗时分布
this.durationChart();
// URL统计
this.urlStatsList();
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
/**
* 概览卡片
*/
@Builder
overviewCard() {
Column() {
Row() {
this.statItem('总请求', this.report!.totalRequests.toString());
this.statItem('成功', this.report!.successRequests.toString());
this.statItem('失败', this.report!.failedRequests.toString());
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
Row() {
this.statItem('平均耗时', `${this.report!.avgDuration.toFixed(0)}ms`);
this.statItem('P95耗时', `${this.report!.p95Duration.toFixed(0)}ms`);
this.statItem('P99耗时', `${this.report!.p99Duration.toFixed(0)}ms`);
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.margin({ top: 16 })
Row() {
this.statItem('平均TTFB', `${this.report!.avgTtfb.toFixed(0)}ms`);
this.statItem('总流量', this.formatBytes(this.report!.totalBytes));
this.statItem('', '');
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.margin({ top: 16 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ left: 16, right: 16, top: 8 })
}
/**
* 统计项
*/
@Builder
statItem(label: string, value: string) {
Column() {
Text(value)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#4A90E2')
Text(label)
.fontSize(12)
.fontColor('#999999')
.margin({ top: 4 })
}
.alignItems(HorizontalAlign.Center)
}
/**
* 耗时分布图
*/
@Builder
durationChart() {
Column() {
Text('耗时分布')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
// 简化示例:使用条形图展示
Row() {
this.barItem('P50', this.report!.p50Duration, this.report!.p99Duration);
this.barItem('P95', this.report!.p95Duration, this.report!.p99Duration);
this.barItem('P99', this.report!.p99Duration, this.report!.p99Duration);
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.margin({ top: 16 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ left: 16, right: 16, top: 16 })
}
/**
* 条形项
*/
@Builder
barItem(label: string, value: number, maxValue: number) {
Column() {
Text(`${value.toFixed(0)}ms`)
.fontSize(12)
.fontColor('#666666')
Column()
.width(40)
.height((value / maxValue) * 100)
.backgroundColor('#4A90E2')
.borderRadius(4)
.margin({ top: 4, bottom: 4 })
Text(label)
.fontSize(12)
.fontColor('#999999')
}
.alignItems(HorizontalAlign.Center)
}
/**
* URL统计列表
*/
@Builder
urlStatsList() {
Column() {
Text('URL统计')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
List() {
ForEach(Array.from(this.report!.urlStats.values()), (stats: any) => {
ListItem() {
this.urlStatsItem(stats);
}
})
}
.width('100%')
.height(200)
.margin({ top: 16 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ left: 16, right: 16, top: 16, bottom: 16 })
}
/**
* URL统计项
*/
@Builder
urlStatsItem(stats: any) {
Row() {
Column() {
Text(stats.url)
.fontSize(14)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(`请求${stats.count}次 | 失败率${(stats.errorRate * 100).toFixed(1)}%`)
.fontSize(12)
.fontColor('#999999')
.margin({ top: 4 })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
Text(`${stats.avgDuration.toFixed(0)}ms`)
.fontSize(14)
.fontColor('#4A90E2')
}
.width('100%')
.padding({ top: 8, bottom: 8 })
.border({ width: { bottom: 1 }, color: '#EEEEEE' })
}
/**
* 格式化字节数
*/
private formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes}B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
}
}示例6:性能数据上报
// network/monitor/PerformanceReporter.ets
import { PerformanceReport, RequestMetrics } from './types';
/**
* 性能数据上报器
* 将性能数据上报到服务器
*/
export class PerformanceReporter {
private reportUrl: string;
private batchSize: number = 50;
private batch: RequestMetrics[] = [];
private timer: number = -1;
constructor(reportUrl: string) {
this.reportUrl = reportUrl;
}
/**
* 启动定时上报
*/
start(interval: number = 60000): void {
this.timer = setInterval(() => {
this.flush();
}, interval);
console.info(`[PerformanceReporter] 启动定时上报,间隔: ${interval}ms`);
}
/**
* 停止定时上报
*/
stop(): void {
if (this.timer !== -1) {
clearInterval(this.timer);
this.timer = -1;
}
// 最后一次上报
this.flush();
}
/**
* 添加性能数据
*/
add(metrics: RequestMetrics): void {
this.batch.push(metrics);
// 达到批次大小,立即上报
if (this.batch.length >= this.batchSize) {
this.flush();
}
}
/**
* 立即上报
*/
async flush(): Promise<void> {
if (this.batch.length === 0) return;
const data = [...this.batch];
this.batch = [];
try {
await this.send(data);
console.info(`[PerformanceReporter] 上报成功: ${data.length}条`);
} catch (error) {
console.error('[PerformanceReporter] 上报失败:', error);
// 上报失败,放回队列
this.batch = [...data, ...this.batch];
}
}
/**
* 发送数据
* @private
*/
private async send(data: RequestMetrics[]): Promise<void> {
// 使用原生HTTP发送,避免循环依赖
const http = await import('@ohos.net.http');
const httpRequest = http.createHttp();
try {
await httpRequest.request(this.reportUrl, {
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: {
appId: 'your-app-id',
timestamp: Date.now(),
metrics: data
}
});
} finally {
httpRequest.destroy();
}
}
}四、踩坑与注意事项
坑1:性能监控影响性能
问题:监控本身也有开销,可能影响请求性能。
解决:异步记录 + 采样:
// 采样:只监控10%的请求
if (Math.random() < 0.1) {
tracker = this.monitor.createTracker(url, method);
}
// 异步记录
setTimeout(() => {
this.monitor.record(metrics);
}, 0);坑2:内存占用过大
问题:记录太多性能数据,内存占用过大。
解决:限制记录数 + 定期清理:
// 限制最大记录数
if (this.metrics.length > this.maxRecords) {
this.metrics.shift(); // 移除最旧的
}
// 定期清理(保留最近1小时)
const oneHourAgo = Date.now() - 60 * 60 * 1000;
this.metrics = this.metrics.filter(m => m.startTime > oneHourAgo);坑3:时间戳不精确
问题:Date.now() 精度只有毫秒,无法测量微秒级耗时。
解决:使用 performance.now()(如果支持):
// 使用高精度时间
const start = performance?.now() || Date.now();
// ...
const duration = (performance?.now() || Date.now()) - start;坑4:上报失败丢失数据
问题:上报失败后,数据丢失。
解决:本地缓存 + 重试:
// 上报失败,存入本地
if (error) {
await localCache.save('failed-reports', data);
}
// 下次启动时重试
const failedReports = await localCache.get('failed-reports');
if (failedReports.length > 0) {
await reporter.send(failedReports);
}五、HarmonyOS 6 适配要点
1. HiChecker 性能检测
// HarmonyOS 6 提供HiChecker检测卡顿
import { hiChecker } from '@kit.PerformanceAnalysisKit';
// 开启卡顿检测
hiChecker.enableRule(hiChecker.RULE_CHECK_SLOW_BLOCK);
// 监听卡顿事件
hiChecker.on('slowBlock', (info) => {
console.warn('检测到卡顿:', info);
// 上报卡顿信息
});2. HiTrace 链路追踪
// HarmonyOS 6 提供分布式链路追踪
import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
// 开始追踪
const traceId = hiTraceMeter.startTrace('http-request', 1);
// 设置追踪信息
hiTraceMeter.setTraceParams(traceId, {
url: request.url,
method: request.method
});
// 结束追踪
hiTraceMeter.finishTrace(traceId);3. 实时性能监控
// HarmonyOS 6 支持实时性能监控
import { profiler } from '@kit.ProfilerKit';
// 开始性能采集
profiler.start({
cpu: true,
memory: true,
network: true
});
// 获取性能快照
const snapshot = await profiler.getSnapshot();
console.log('CPU使用率:', snapshot.cpu.usage);
console.log('内存使用:', snapshot.memory.used);
console.log('网络流量:', snapshot.network.bytes);六、总结一下下
性能监控是应用的"体检报告",让性能问题无处遁形:
| 监控维度 | 关键指标 | 优化方向 |
|---|---|---|
| DNS | DNS耗时 | DNS预解析、HTTPDNS |
| 连接 | TCP/TLS耗时 | 连接复用、HTTP2 |
| 传输 | TTFB、下载耗时 | CDN、压缩、缓存 |
| 解析 | 解析耗时 | 数据格式、流式解析 |
| 整体 | 总耗时、成功率 | 全链路优化 |
记住几个原则:
- ✅ 监控要全面,覆盖所有请求
- ✅ 数据要精确,追踪每个阶段
- ✅ 告警要及时,发现问题立即通知
- ✅ 上报要可靠,失败不丢数据
- ✅ 开销要小,监控不影响性能
💡 最佳实践提示:建议在开发环境开启详细监控,生产环境只监控关键指标和采样数据,平衡监控效果和性能开销。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。