Skip to content

性能监控

前端项目的整体稳定性是怎么保证的?

  • 稳定性,要站在Leader 角度,做了贡献
    • 性能采集、异常采集、用户行为埋点SDK开发
    • 数据上报协议
    • 数据统计清洗与加工
    • 可视化

异常和性能的监控SDK内核如何实现?

  • 重点介绍SDK实现细节
    • 性能、异常指标设计
    • 上报逻辑,图片、sendbacon、fet&h
    • 用户自定义指标数据

性能指标

核心性能

加载性能全称描述
FPFirst Paint 首次绘制页面任意像素被渲染所花费的时间
FCPFirst Contentful Paint 首次内容绘制页面开始渲染任何文本、图片、svg的时间
LCPLargest Contentful Paint 最大内容绘制页面中最大的文本或图片元素渲染完成的时间
TTFBTime to First Byte 首字节时间浏览器发送请求到收到第一个字节的时间
交互性能全称描述理想值
INPInteraction to Next Paint
交互到下一次绘制
用户交互(如点击按钮)
到界面响应的时间
<200ms< 200ms
TBTTotal Blocking Time
总阻塞时间
从 FCP 到 之间
主线程被阻塞的时间总和
<200ms< 200ms
CLSCumulative Layout Shift
累计布局偏移
页面意外的布局移动得分
影响用户体验
<0.1< 0.1
TTITime to Interactive
补充性能定义
DNS 查询时间从发起请求到 DNS 查询完成的时间
资源加载时间所有静态资源(如图片、CSS、JS)的下载时长
长任务 (Long Task)主线程运行超过 50ms 的任务
performance 性能
js
performance = {
  "timeOrigin": 1756781433903.2,
  "timing": {
    "connectStart": 1756781433904,
    "secureConnectionStart": 0,
    "unloadEventEnd": 1756781433937,
    "domainLookupStart": 1756781433904,
    "domainLookupEnd": 1756781433904,
    "responseStart": 1756781433924,
    "connectEnd": 1756781433904,
    "responseEnd": 1756781433932,
    "requestStart": 1756781433915,
    "domLoading": 1756781433941,
    "redirectStart": 0,
    "loadEventEnd": 1756781434694,
    "domComplete": 1756781434693,
    "navigationStart": 1756781433903,
    "loadEventStart": 1756781434694,
    "domContentLoadedEventEnd": 1756781434671,
    "unloadEventStart": 1756781433937,
    "redirectEnd": 0,
    "domInteractive": 1756781434123,
    "fetchStart": 1756781433904,
    "domContentLoadedEventStart": 1756781434671
  },
  "navigation": {
    "type": 1,
    "redirectCount": 0
  }
}

异常指标及其监控

运行时异常

采用window.onerror监听,代码如下,此时我输出一个未定义的变量,查看捕获的异常

js
window.onerror = function (msg, source, line, col, error) {
  const {name, message, stack} = error;
  console.log({
    '错误信息': msg,
    '错误文件': source,
    '错误行号': line,
    '错误列号': col,
    '错误对象': {
      name,
      message,
      stack
    }
  });
  return true;
};
error 异常结果
js
let error = {
  '错误信息': 'Uncaught ReferenceError: a is not defined',
  '错误文件': 'http://localhost:3001/web-vite-vue3/src/pages/main.vue?t=1756783123513',
  '错误行号': 23,
  '错误列号': 34,
  '错误对象': {}
};

promise reject异常

js
window.addEventListener('unhandledrejection', function (e) {
  console.log('Promise 错误:', e.reason);
});

请求异常

重写fetch

js
const originFetch = window.fetch;
window.fetch = function (...args) {
  return originFetch(...args).then((response) => {
    if (!response.ok) {
      throw new Error('请求异常', response.status);
    }
    return response;
  });
};

资源加载异常

js
window.addEventListener('error', function (e) {
  if (e.target != window) {
    console.log('静态资源错误:', e);
  }
});

用户行为埋点

  • 无痕埋点(事件冒泡和捕获)
  • 可视化埋点
  • 手动埋点

捕获所有的点击事件的链路xPath

js
window.onclick = (e) => {
  const {target} = e;
  console.dir('target', target);
  const paths = e.path || e.composedPath();
  const xPath = paths.map(item => item.tagName).join('/');
  console.log('xPath', xPath);
};

数据上报

  • image上报
  • fetch请求上报
  • sendBeacon上报
js
const baseUrl = 'http://localhost:3001/api/report';

const reportMessage = (message) => {
  const img = new Image();
  img.src = `${baseUrl}?message=${message}`;
};

完整开发流程

docker容器编排

如果你是windows电脑,先安装docker desktop ,下载安装之后一直下一步,完整完成之后重启电脑。项目地址在GitHub

创建docker-compose.yml文件,内容如下:用到了kafka和clickhouse

yml
version: '1'
services:
  modify-kafka:
    image: bitnami/kafka:3.9.0
    container_name: modify-kafka
    ports:
      - "9092:9092"
      - "9093:9093"
    environment:
      - KAFKA_CFG_NODE_ID=1
      - KAFKA_CFG_PROCESS_ROLES=broker,controller
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@modify-kafka:9093
      - KAFKA_CFG_LISTENERS=PLAINTEXT://modify-kafka:9092,CONTROLLER://modify-kafka:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT
      - ALLOW_PLAINTEXT_LISTENER=true


  modify-clickhouse:
    image: bitnami/clickhouse:25.3.1
    container_name: modify-clickhouse
    ports:
      - "8123:8123"
      - "9000:9000"
    environment:
      - CLICKHOUSE_DB=default
      - CLICKHOUSE_USER=default
      - CLICKHOUSE_PASSWORD=default

networks:
  default:
    name: modify-network
    driver: bridge

补充:技术选型 kafka + clickhouse

kafka是一个高吞吐、分布式、可持久化的消息队列系统,非常适合埋点这类高并发、低延迟、高可靠的数据采集场景

  • ✅ 优势:
    • 高吞吐量:每秒可处理百万级消息,适合埋点这种高频小数据包场景
    • 持久化与可靠性:数据写入磁盘,支持副本机制,保证不丢失
    • 解耦生产者与消费者:前端/日志服务只需把数据丢进 Kafka,后端可以异步消费处理
    • 支持多消费者组:不同业务系统(如实时分析、离线数仓、监控告警)可以同时消费同一份数据
    • 削峰填谷:前端埋点流量可能突发(如大促),Kafka 可以缓冲流量,避免后端服务被打垮
  • ❌ 劣势:
    • 需要维护集群(不过现在有云服务如 Confluent、阿里云 Kafka 等)
    • 不适合复杂查询或直接分析

ClickHouse 是一个列式存储、面向 OLAP(在线分析处理)的数据库,特别适合对海量数据做快速聚合查询

  • ✅ 优势:
    • 极快的查询性能:对聚合查询(如 UV、PV、留存、漏斗)响应速度极快(秒级甚至毫秒级)
    • 高压缩比:列式存储 + 高效压缩算法,节省存储成本
    • 高吞吐写入:适合批量写入埋点数据(通过 Kafka 消费写入)
    • 适合宽表设计:可将用户属性、事件属性打平成宽表,便于分析
    • 支持实时分析:数据写入后几乎可立即查询,适合实时看板
  • ❌ 劣势:
    • 不支持事务和更新(适合 append-only 场景)
    • 不适合高并发点查(如单条用户记录查询)
    • 数据更新/删除成本高(但埋点场景通常不需要修改历史数据)

服务启动与停止

通过docker-compose启动与停止,其中-f指定配置文件,-p指定项目名

json
{
  "scripts": {
    "docker:start": "docker-compose -f build/docker-compose.yml up -d",
    "docker:stop": "docker-compose -f build/docker-compose.yml down",
    "docker:start:group": "docker-compose -f build/docker-compose.yml -p tracking-point up -d",
    "docker:stop:group": "docker-compose -f build/docker-compose.yml -p tracking-point down"
  }
}

测试连接

webstrom当中下载一个kafka插件,安装完成后重启,在views->Tool Windows -> Kafka,直接通过localhost:9092进行测试连接

clickhouse用数据库连接工具测试连接即可。

By Modify.