⚠️温馨提示: 文档中包含【1个】暂不支持的区域,请通过搜索关键字【暂不支持的文档区域】进行后续处理

monitor-microservice-notes.zip

很多同学可能第一次来,我分享了很多干货公开课,希望对你的技术成长有帮助!免费分享都在这里,需要 文档和配套视频找咨询老师 领取~

【飞书文档】备战金九银十,进阶大前端,涨薪全突破! 跳槽涨薪需求同学必看

【飞书文档】项目没有难点亮点?字节大佬带你前端项目弯道超车

【飞书文档】字节大佬带你弯道超车,深入剖析大厂面试真题~

【飞书文档】面试被算法干吐了?字节大佬带你突破极限,冲击 30K+ 必掌握算法与 WebAssembly 技术 冲刺年包 50W+ 同学必看


【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节【超详细内培版】

【飞书文档】高级前端专家如何做项目架构与工程化设计? 特邀字节大佬细数字节开源项目架构细节【超详细内培版】

【飞书文档】小小微前端,轻松拿捏,特邀字节大佬开讲微前端架构与源码剖析【内部培训版】 35K+ 同学必看

【飞书文档】高级前端专家如何做性能优化?特邀字节大佬细数飞书应用优化细节(二)【内部培训版】


【飞书文档】前端破局 AI 应用开发,特邀字节大佬分享字节系 AI 场景落地应用与 AI 引擎编排流程 探索前端新方向同学福音

【飞书文档】React18 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题

【飞书文档】Vue3 源码深度剖析,字节面试官教你轻松拿捏高级前端专家面试框架原理题

【飞书文档】Vite 构建过程与源码深度剖析,你怎么也想不到一线大厂工程化构建面试会问这么深!

【飞书文档】脚手架/CLI 工具原理与开发实践,特邀字节前端专家带你体悟大厂团队基建与研发工作流 团队基建必看

【飞书文档】Webpack 原理深度解读与面试专项突击,字节面试官带你手撕难缠打包构建面试原理题 工程化与构建原理深入


【飞书文档】冲击中大厂筹备与涨薪突击最优方案,特邀字节面试官带你体验大厂面试全流程

【飞书文档】字节面试专场——中厂在职学员冲击大厂 30K+,看看面试官如何评价 大厂模拟面试,问得很深慎看

  1. 全栈项目架构
  2. Kafka + Clickhouse + Flink 实时数据流经典架构设计
  3. 性能与异常指标采集
  • 初中级 】做过监控设计?那性能与异常监控指标怎么算的?
  • 中高级 】有设计过大型实时数据流相关系统吗,具体怎么做?
  • 专家级 】详细说明监控平台方案设计与落地,项目实践

初中级 】做过监控设计?那前端性能与异常监控指标怎么算?

性能监控那节,我们详细介绍了性能优化相关指标概念,这次我们来结合大厂监控平台实战,充分理解指标定义、计算与上报逻辑。

前端性能监控通过收集和分析用户端的性能数据来衡量和优化页面加载速度、交互响应时间等关键性能指标的过程。

为什么需要性能监控?

  • 提升用户体验:减少页面加载和响应时间,提高用户留存率。
  • 发现和优化性能瓶颈:及时发现影响性能的因素并进行优化。
  • 数据驱动决策:基于真实数据进行性能优化,而非依赖直觉。

常见的性能监控指标

页面加载时间(Page Load Time)

  • 定义 :从用户发出请求到页面完全加载完成的时间。
  • 计算方式
const pageLoadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
  • 意义 :页面加载时间是用户体验的核心指标之一。

首次内容绘制时间(First Contentful Paint, FCP)

  • 定义 :页面首次绘制出任何内容的时间。
  • 获取方法
new PerformanceObserver((entryList) => {
    const entries = entryList.getEntriesByName('first-contentful-paint');
    if (entries.length > 0) {
        const fcpTime = entries[0].startTime;
        console.log(`FCP: ${fcpTime}`);
    }
}).observe({ type: 'paint', buffered: true });
  • 意义 :FCP 直接反映页面开始展现内容的速度。

最大内容绘制时间(Largest Contentful Paint, LCP)

  • 定义 :页面中最大内容元素的渲染时间。
  • 获取方法
new PerformanceObserver((entryList) => {
    const entries = entryList.getEntries();
    const lastEntry = entries[entries.length - 1];
    const lcpTime = lastEntry.startTime;
    console.log(`LCP: ${lcpTime}`);
}).observe({ type: 'largest-contentful-paint', buffered: true });
  • 意义 :LCP 是衡量页面主要内容是否迅速加载的核心指标。

交互时间(Time to Interactive, TTI)

  • 定义 :页面从加载开始到可以响应用户交互的时间。
  • 计算方式
const timeToInteractive = performance.timing.domInteractive - performance.timing.navigationStart;
  • 意义 :TTI 直接关系到用户能够开始操作页面的时间。

资源加载时间

  • 定义 :每个静态资源(如图片、JS 文件)的加载时间。
  • 获取方法
const resources = performance.getEntriesByType('resource');
resources.forEach((resource) => {
    const loadTime = resource.responseEnd - resource.startTime;
    console.log(`${resource.name}: ${loadTime}`);
});
  • 意义 :资源加载时间影响整体页面加载性能,是优化的关键。

前端异常监控

前端异常监控指的是捕获并报告用户端发生的错误或异常,帮助开发者及时发现和修复问题。最经典的要数 sentry 了,有兴趣的同学呢,重点了解 sentry 的源码实现。

JavaScript 错误(JS Errors)

  • 定义 :运行时 JavaScript 错误。
  • 捕获方法
window.onerror = function (message, source, lineno, colno, error) {
    console.log(`Error: ${message}, Source: ${source}, Line: ${lineno}, Column: ${colno}, Error Object: ${error}`);
};

Promise 未处理拒绝(Unhandled Promise Rejection)

  • 定义 :未处理的 Promise 拒绝错误。
  • 捕获方法
window.addEventListener('unhandledrejection', function (event) {
    console.log(`Unhandled Rejection: ${event.reason}`);
});

资源加载错误

  • 定义 :静态资源加载失败错误。
  • 捕获方法
window.addEventListener('error', function (event) {
    if (event.target !== window) {
        console.log(`Resource Load Error: ${event.target.src || event.target.href}`);
    }
}, true);

接口请求失败(API Failure)

  • 定义 :API 请求失败或超时错误。
  • 捕获方法
fetch(url)
    .then(response => {
        if (!response.ok) {
            console.error(`API Failure: ${response.status} ${response.statusText}`);
        }
    })
    .catch(error => console.error(`Fetch Error: ${error}`));

统一上报数据格式

数据格式设计原则

  • 一致性 :所有监控数据应采用统一的格式,便于后续分析和展示。
  • 可扩展性 :数据格式设计应考虑未来的扩展需求,允许添加新字段。
  • 轻量化 :数据尽量精简,减少上报带来的性能影响。

数据格式示例

以下为一个仿照 Sentry 定义的统一性能与异常监控数据格式:

{
  "event_id": "unique-event-id",
  "timestamp": "2024-08-28T14:25:43.511Z",
  "platform": "javascript",
  "release": "project-release-version",
  "environment": "production",
  "user": {
    "id": "user-id",
    "username": "username",
    "email": "user@example.com",
    "ip_address": "user-ip-address"
  },
  "contexts": {
    "performance": {
      "page_load_time": 1234,
      "fcp": 678,
      "lcp": 1234,
      "tti": 2345,
      "resources": [
        {"name": "resource1.js", "load_time": 123},
        {"name": "image1.png", "load_time": 456}
      ]
    }
  },
  "exception": {
    "values": [
      {
        "type": "TypeError",
        "value": "Cannot read property 'x' of undefined",
        "stacktrace": {
          "frames": [
            {
              "filename": "https://example.com/script.js",
              "lineno": 42,
              "colno": 21,
              "function": "myFunction",
              "in_app": true
            }
          ]
        }
      }
    ]
  },
  "errors": [
    {
      "message": "Unhandled Promise Rejection: Error: Something went wrong",
      "source": "https://example.com/promise.js",
      "lineno": 10,
      "colno": 15,
      "errorObject": {
        "name": "Error",
        "message": "Something went wrong",
        "stack": "Error: Something went wrong\n    at promise.js:10:15"
      }
    },
    {
      "message": "Resource Load Error: https://example.com/image.png",
      "source": "image.png",
      "lineno": 0,
      "colno": 0
    }
  ],
  "breadcrumbs": [
    {
      "category": "ui.click",
      "message": "User clicked button",
      "level": "info",
      "timestamp": "2024-08-28T14:25:40.511Z"
    },
    {
      "category": "navigation",
      "message": "User navigated to /dashboard",
      "level": "info",
      "timestamp": "2024-08-28T14:25:43.511Z"
    }
  ]
}

数据上报

使用以下代码上报监控数据:

fetch

fetch('https://your-monitoring-service.com/api/events', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer your-api-key'
    },
    body: JSON.stringify(eventData) // eventData 是 JSON 数据
});

除此以外,还有以下上报方式:

  • ajax
  • 图片打点 image
  • navigator.sendBeacon
  • ws

【拓展】用户行为埋点与监控

埋点是一种通过在前端代码中添加特定标记或逻辑来记录用户行为、页面事件等数据的技术。埋点数据可以帮助开发者了解用户行为路径、页面功能使用情况等,为产品优化和用户体验提升提供数据支持。

常见埋点指标

  1. 页面浏览量(Page View, PV)

    • 定义 :用户每次加载页面时的计数。
    • 埋点方式 :在页面加载时触发埋点。
    // Example: 埋点触发
    sendTrackingData({
        event: 'page_view',
        url: window.location.href,
        timestamp: Date.now()
    });
    
  2. 独立访客数(Unique Visitor, UV)

    • 定义 :独立用户访问次数的计数。通常通过用户 ID 或 Cookie 进行识别。
    • 埋点方式 :在用户第一次访问时触发埋点。
    // Example: 获取用户 ID 并触发 UV 埋点
    const userId = getUserIdFromCookie();
    if (!userId) {
        setUserIdInCookie(generateNewUserId());
    }
    sendTrackingData({
        event: 'unique_visitor',
        userId: userId,
        timestamp: Date.now()
    });
    
  3. 点击事件(Click Event)

    • 定义 :用户点击页面元素(如按钮、链接)时的记录。
    • 埋点方式 :在用户点击特定元素时触发埋点。
    document.getElementById('buttonId').addEventListener('click', function() {
        sendTrackingData({
            event: 'click',
            elementId: 'buttonId',
            url: window.location.href,
            timestamp: Date.now()
        });
    });
    
  4. 表单提交(Form Submit)

    • 定义 :用户提交表单时的记录。
    • 埋点方式 :在表单提交时触发埋点。
    document.getElementById('formId').addEventListener('submit', function() {
        sendTrackingData({
            event: 'form_submit',
            formId: 'formId',
            url: window.location.href,
            timestamp: Date.now()
        });
    });
    
  5. 停留时间(Time on Page)

    • 定义 :用户在页面上停留的时间。
    • 埋点方式 :在页面加载和关闭时分别触发埋点,并计算时间差。
    const startTime = Date.now();
    window.addEventListener('beforeunload', function() {
        const timeSpent = Date.now() - startTime;
        sendTrackingData({
            event: 'time_on_page',
            timeSpent: timeSpent,
            url: window.location.href,
            timestamp: Date.now()
        });
    });
    

综合埋点数据协议设计

在之前的性能与异常监控数据格式的基础上,我们可以加入埋点数据,使数据协议更加完整和灵活。以下是包含埋点信息的综合数据协议设计:

{
  "event_id": "unique-event-id",
  "timestamp": "2024-08-28T14:25:43.511Z",
  "platform": "javascript",
  "release": "project-release-version",
  "environment": "production",
  "user": {
    "id": "user-id",
    "username": "username",
    "email": "user@example.com",
    "ip_address": "user-ip-address"
  },
  "contexts": {
    "performance": {
      "page_load_time": 1234,
      "fcp": 678,
      "lcp": 1234,
      "tti": 2345,
      "resources": [
        {"name": "resource1.js", "load_time": 123},
        {"name": "image1.png", "load_time": 456}
      ]
    },
    "exceptions": {
      "values": [
        {
          "type": "TypeError",
          "value": "Cannot read property 'x' of undefined",
          "stacktrace": {
            "frames": [
              {
                "filename": "https://example.com/script.js",
                "lineno": 42,
                "colno": 21,
                "function": "myFunction",
                "in_app": true
              }
            ]
          }
        }
      ]
    },
    "tracking": {
      "events": [
        {
          "event": "page_view",
          "url": "https://example.com",
          "timestamp": "2024-08-28T14:25:43.511Z"
        },
        {
          "event": "click",
          "elementId": "buttonId",
          "url": "https://example.com",
          "timestamp": "2024-08-28T14:26:00.511Z"
        },
        {
          "event": "form_submit",
          "formId": "formId",
          "url": "https://example.com",
          "timestamp": "2024-08-28T14:26:30.511Z"
        },
        {
          "event": "time_on_page",
          "timeSpent": 120000, 
          "url": "https://example.com",
          "timestamp": "2024-08-28T14:28:00.511Z"
        }
      ]
    }
  },
  "errors": [
    {
      "message": "Unhandled Promise Rejection: Error: Something went wrong",
      "source": "https://example.com/promise.js",
      "lineno": 10,
      "colno": 15,
      "errorObject": {
        "name": "Error",
        "message": "Something went wrong",
        "stack": "Error: Something went wrong\n    at promise.js:10:15"
      }
    },
    {
      "message": "Resource Load Error: https://example.com/image.png",
      "source": "image.png",
      "lineno": 0,
      "colno": 0
    }
  ],
  "breadcrumbs": [
    {
      "category": "ui.click",
      "message": "User clicked button",
      "level": "info",
      "timestamp": "2024-08-28T14:25:40.511Z"
    },
    {
      "category": "navigation",
      "message": "User navigated to /dashboard",
      "level": "info",
      "timestamp": "2024-08-28T14:25:43.511Z"
    }
  ]
}

中高级 】有设计过大型实时数据流相关系统吗,具体怎么做?

我设计过前端监控平台数据上报、消息队列处理(Kafka)直至数据落库 ClickHouse 完整环节

其中完整细节包括:

  1. 监控数据采集与上报
  2. 数据接收与消息队列(Kafka)机制
  3. 数据预处理(Flink/Spark)
  4. 数据存储(ClickHouse)
  5. 前端数据可视化与预警机制

前端监控数据上报

数据收集方式

在前端,我们需要采集用户行为、性能指标、异常日志等监控数据。这些数据可以通过以下方式收集:

  • AJAX 请求 :通过 fetchXMLHttpRequest 发送数据至后端。
  • sendBeacon :用于在页面卸载或关闭时上报数据,确保数据不丢失。
  • WebSocket :用于实时性要求较高的数据上报,保持前端和后端的长连接。

数据结构设计

上报的数据通常包含以下内容:

  • 事件类型 :如 clickerrorperformance 等。
  • 时间戳 :事件发生的时间,用于排序和分析。
  • 用户信息 :包括用户 ID、会话 ID、设备信息等。
  • 页面信息 :包括页面 URL、页面加载时间等性能指标。

示例 JSON 数据结构:

{
  "event_type": "click",
  "timestamp": "2024-08-28T14:25:43.511Z",
  "user": {
    "id": "user-id",
    "session_id": "session-id",
    "device": "device-info"
  },
  "page": {
    "url": "https://example.com",
    "referrer": "https://referrer.com"
  },
  "data": {
    "element_id": "buttonId",
    "x_position": 100,
    "y_position": 200
  }
}

数据上报到后端

前端通过上述方式收集数据后,将这些数据发送到后端的 API 接口或 Kafka 主题中。

fetch('https://your-server.com/api/monitoring', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(eventData)
});

数据接收与队列处理

接收层:Nginx 或 Node.js

后端 API 负责接收前端发送的监控数据,可以使用 Nginx 进行负载均衡和反向代理,将请求路由到多个 Node.js 服务器,确保系统的高可用性。

  • Nginx 反向代理 :Nginx 负责分发请求,支持高并发,适合大规模数据接入。
  • Node.js 服务器 :Node.js 提供灵活的 API 接口,处理接收到的数据。

数据队列:Kafka

接收到的数据通常直接推送到 Kafka 队列中进行缓冲处理,这样可以解耦数据接收与后续的处理逻辑。

Kafka 的作用

  • 高吞吐量 :Kafka 可以处理大量的监控数据,确保数据的实时性。
  • 数据持久化 :Kafka 会将数据持久化到磁盘,确保在消费者消费数据之前数据不会丢失。
  • 多消费者处理 :Kafka 支持多个消费者组,这允许我们对不同类型的数据进行并行处理。

Kafka 主题与分区

  • 主题 :可以根据数据类型(如性能数据、错误数据、用户行为数据等)创建不同的 Kafka 主题,确保数据分类处理。
  • 分区 :Kafka 的分区机制允许我们将同一主题的数据分布在多个分区上,提升处理性能。
const kafka = require('kafka-node');
const client = new kafka.KafkaClient({kafkaHost: 'localhost:9092'});
const producer = new kafka.Producer(client);

const payloads = [
    { topic: 'monitoring', messages: JSON.stringify(eventData), partition: 0 }
];

producer.send(payloads, function(err, data) {
    console.log(data);
});

数据处理与预处理

Kafka Consumer

Kafka 的消费者从队列中拉取数据,对数据进行清洗、过滤、聚合等预处理操作。

  • 数据清洗 :过滤掉无效或重复的数据,确保数据的准确性。
  • 数据聚合 :在消费过程中,可以对数据进行初步的聚合,如按用户 ID 聚合访问次数等。
  • 实时处理 :消费者可以将数据实时处理后推送到 ClickHouse,也可以进一步推送到其他处理层(如 Spark、Flink)进行更复杂的实时分析。
const Consumer = kafka.Consumer;
const consumer = new Consumer(client, [{ topic: 'monitoring', partition: 0 }], {autoCommit: true});

consumer.on('message', function(message) {
    const data = JSON.parse(message.value);
    processData(data); // 数据预处理逻辑
});

数据处理层:流式处理

可以使用流式处理引擎(如 Apache Flink 或 Spark Streaming)来处理和分析从 Kafka 消费的数据流。

  • Apache Flink :Flink 提供了低延迟的实时流处理,适合处理复杂的事件模式。
  • Spark Streaming :适合批处理与流处理结合的场景,能够处理大量数据的同时进行复杂分析。

通过流式处理引擎,系统能够在数据进入存储之前执行复杂的数据分析或事件检测。

数据存储:ClickHouse

数据写入 ClickHouse

处理后的数据最终会写入 ClickHouse 数据库中,以供查询和分析。

为什么选择 ClickHouse?

  • 高性能查询 :ClickHouse 采用列式存储和数据压缩技术,能够在处理大规模数据时提供高效的查询性能。
  • 实时分析 :ClickHouse 支持实时数据插入和查询,适合实时监控系统的需求。
  • 分布式架构 :ClickHouse 支持数据的分布式存储和查询,能够轻松扩展以处理更大规模的数据。

表结构设计

ClickHouse 的表结构设计需要考虑到数据的查询需求和性能优化。常见的做法是根据数据的维度和指标设计表结构,并创建适当的分区和索引。

示例表结构:

CREATE TABLE monitoring_data (
    event_type String,
    timestamp DateTime,
    user_id String,
    session_id String,
    device String,
    url String,
    referrer String,
    element_id String,
    x_position Int32,
    y_position Int32
) ENGINE = MergeTree()
ORDER BY (timestamp, event_type)
PARTITION BY toYYYYMM(timestamp)
  • ORDER BY :用于加速查询,特别是在时间范围查询和按事件类型查询时性能提升显著。
  • PARTITION BY :按月分区(或其他时间周期),以优化存储和查询性能。

数据插入操作

数据可以通过 Kafka 消费者或者直接从流式处理引擎推送到 ClickHouse,进行批量插入操作,确保系统的写入性能。

import clickhouse_driver

client = clickhouse_driver.Client('localhost')

client.execute('INSERT INTO monitoring_data (event_type, timestamp, user_id, session_id, device, url, referrer, element_id, x_position, y_position) VALUES', data_batch)

数据查询与分析

存储在 ClickHouse 的数据可以通过 SQL 查询进行分析,前端可以通过 REST API 或者直接使用 ClickHouse 提供的 HTTP 接口进行数据获取。

SELECT
    event_type,
    COUNT(*) AS event_count
FROM monitoring_data
WHERE timestamp >= now() - INTERVAL 1 HOUR
GROUP BY event_type
ORDER BY event_count DESC

前端数据展示与报警

前端展示

前端可以通过调用 REST API 或者直接查询 ClickHouse 数据库,获取需要展示的数据,并使用图表库(如 ECharts 或 D3.js)进行可视化展示。

  • 实时监控面板 :通过 WebSocket 或定时刷新机制,实时展示系统的性能指标、错误率等关键数据。
  • 历史数据分析 :通过查询 ClickHouse 的历史数据,生成趋势图、分布图等,帮助分析系统的长期表现。

报警机制

在数据分析的基础上,可以设置阈值或检测异常模式,当数据超出预设范围时,触发报警。

  • 定时任务 :可以定期查询 ClickHouse 数据库,检测是否有指标超出预警范围。
  • 实时报警 :通过流式处理系统(如 Flink)实时检测异常,直接触发报警(如发送邮件或消息通知)。

专家级全栈 】详细说明监控平台方案设计与落地,项目实践

整体架构设计

架构概述

监控平台的整体架构分为以下几个主要模块:

  1. 前端监控数据采集 :前端应用采集用户行为、性能指标、错误日志等数据,并通过多种方式上报至后端。
  2. 服务端数据接收与处理 :服务端使用 NestJS 作为核心框架,接收并处理前端上报的数据,同时将数据推送至 Kafka 进行进一步处理。
  3. 数据队列与流处理 :通过 Kafka 进行数据缓冲和流式处理,确保数据处理的实时性和高吞吐量。
  4. 数据存储与分析 :处理后的数据最终存储在 ClickHouse 中,用于实时查询和分析。
  5. 前端展示与报警 :通过可视化界面展示监控数据,并在必要时触发报警机制。

技术选型

  • 前端 :使用 JavaScript/TypeScript 编写的 SDK,负责采集和上报监控数据。
  • 后端 :NestJS 框架,使用 TypeScript 编写,提供 API 接口和数据处理逻辑。
  • 数据队列 :Kafka,用于高并发数据的缓冲和传输。
  • 数据存储 :ClickHouse,用于存储和快速查询大规模监控数据。
  • 流处理 :Apache Flink 或 Spark Streaming,用于实时数据处理和分析。

前端接入

前端 SDK 设计

为了让前端应用能够无缝接入监控平台,需要设计一个前端 SDK。这个 SDK 应该具备以下功能:

  • 自动采集性能指标 :包括页面加载时间、FCP、LCP、TTI 等。
  • 捕获 JavaScript 错误 :捕获运行时错误和未处理的 Promise 拒绝。
  • 用户行为追踪 :如点击、表单提交、页面停留时间等。
  • 数据上报 :通过 fetchsendBeacon 或 WebSocket 将数据上报到后端。

SDK 实现示例

class MonitoringSDK {
    private endpoint: string;

    constructor(endpoint: string) {
        this.endpoint = endpoint;
        this.init();
    }

    private init() {
        this.collectPerformanceData();
        this.setupErrorHandling();
    }

    private collectPerformanceData() {
        window.addEventListener('load', () => {
            const performanceData = {
                event_type: 'performance',
                timestamp: new Date().toISOString(),
                data: {
                    pageLoadTime: performance.timing.loadEventEnd - performance.timing.navigationStart,
                    fcp: performance.getEntriesByName('first-contentful-paint')[0]?.startTime || null,
                    lcp: performance.getEntriesByType('largest-contentful-paint')[0]?.startTime || null,
                    tti: performance.timing.domInteractive - performance.timing.navigationStart
                }
            };
            this.sendData(performanceData);
        });
    }

    private setupErrorHandling() {
        window.onerror = (message, source, lineno, colno, error) => {
            const errorData = {
                event_type: 'error',
                timestamp: new Date().toISOString(),
                data: {
                    message,
                    source,
                    lineno,
                    colno,
                    stack: error?.stack || ''
                }
            };
            this.sendData(errorData);
        };

        window.addEventListener('unhandledrejection', (event) => {
            const rejectionData = {
                event_type: 'unhandledrejection',
                timestamp: new Date().toISOString(),
                data: {
                    reason: event.reason,
                    stack: event.reason?.stack || ''
                }
            };
            this.sendData(rejectionData);
        });
    }

    private sendData(data: any) {
        navigator.sendBeacon(this.endpoint, JSON.stringify(data));
    }
}

// 使用示例
const monitoring = new MonitoringSDK('https://your-server.com/api/monitoring');

前端应用集成

将 SDK 集成到前端应用中非常简单。开发者只需在应用的入口文件(如 index.jsmain.ts )中引入并初始化 SDK。

import MonitoringSDK from './monitoring-sdk';

// 初始化 SDK
const monitoring = new MonitoringSDK('https://your-server.com/api/monitoring');

集成后,前端应用在用户访问页面时会自动开始采集和上报数据,而开发者几乎不需要做额外的工作

服务端实现(NestJS)

NestJS 服务端架构

NestJS 是一个基于 Node.js 的现代 Web 框架,采用模块化设计,非常适合构建复杂的企业级应用。在监控平台的服务端实现中,我们将 NestJS 用于以下几个关键部分:

  • API 接口 :提供数据接收接口,处理前端上报的数据。
  • 数据处理与转发 :处理并清洗数据,然后推送至 Kafka 进行异步处理。
  • 与数据库的交互 :在必要时直接与 ClickHouse 进行交互,执行数据查询。

实现数据接收与处理

数据接收模块

首先,我们定义一个控制器(Controller),用于接收前端上报的数据。

import { Controller, Post, Body } from '@nestjs/common';
import { MonitoringService } from './monitoring.service';

@Controller('monitoring')
export class MonitoringController {
  constructor(private readonly monitoringService: MonitoringService) {}

  @Post()
  async receiveData(@Body() data: any) {
    // 将数据传递给服务层处理
    await this.monitoringService.processData(data);
    return { status: 'success' };
  }
}

数据处理模块

在服务层,我们对接收到的数据进行处理,并将其推送至 Kafka。

import { Injectable } from '@nestjs/common';
import { Kafka } from 'kafkajs';

@Injectable()
export class MonitoringService {
  private kafkaProducer;

  constructor() {
    const kafka = new Kafka({
      clientId: 'monitoring-service',
      brokers: ['kafka:9092']
    });

    this.kafkaProducer = kafka.producer();
    this.kafkaProducer.connect();
  }

  async processData(data: any) {
    // 清洗数据或添加额外信息
    const enrichedData = {
      ...data,
      receivedAt: new Date().toISOString(),
      environment: process.env.NODE_ENV
    };

    // 推送数据到 Kafka 主题
    await this.kafkaProducer.send({
      topic: 'monitoring-events',
      messages: [{ value: JSON.stringify(enrichedData) }]
    });
  }
}

在这个模块中,我们使用了 kafkajs 来与 Kafka 交互。数据在处理后会推送到 Kafka 主题 monitoring-events ,供后续的流式处理或直接存储到 ClickHouse。

与 ClickHouse 的交互

在某些情况下,我们可能需要服务端直接与 ClickHouse 交互,执行复杂的查询或插入操作。我们可以使用 clickhouse-driver 与 ClickHouse 进行通信。

import { Injectable } from '@nestjs/common';
import { Client } from 'clickhouse';

@Injectable()
export class ClickhouseService {
  private client;

  constructor() {
    this.client = new Client({
      url: 'http://clickhouse-server:8123',
      basicAuth: {
        username: 'default',
        password: ''
      },
      debug: false,
    });
  }

  async insertData(data: any) {
    const query = `
      INSERT INTO monitoring_data (event_type, timestamp, user_id, session_id, device, url, referrer, element_id, x_position, y_position)
      VALUES ?
    `;

    await this.client.insert(query, [data]);
  }

  async queryData() {
    const query = `
      SELECT event_type, COUNT(*) AS event_count
      FROM monitoring_data
      WHERE timestamp >= now() - INTERVAL 1 HOUR
      GROUP BY event_type
      ORDER BY event_count DESC
    `;

    return await this.client.query(query).toPromise();
  }
}

这个服务可以根据需要被嵌入到不同的业务逻辑中,实现复杂的数据处理和查询。

数据流处理与分析

Kafka 消费者

在数据进入 Kafka 后,我们需要通过 Kafka 的消费者从队列中拉取数据,并对其进行实时处理。可以使用 Apache Flink 或 Spark Streaming 来处理这些数据。

import { Injectable, OnModuleInit } from '@nestjs/common';
import { Kafka } from 'kafk

ajs';

@Injectable()
export class KafkaConsumerService implements OnModuleInit {
  private kafkaConsumer;

  constructor() {
    const kafka = new Kafka({
      clientId: 'monitoring-consumer',
      brokers: ['kafka:9092']
    });

    this.kafkaConsumer = kafka.consumer({ groupId: 'monitoring-group' });
  }

  async onModuleInit() {
    await this.kafkaConsumer.connect();
    await this.kafkaConsumer.subscribe({ topic: 'monitoring-events', fromBeginning: true });

    this.kafkaConsumer.run({
      eachMessage: async ({ topic, partition, message }) => {
        const eventData = JSON.parse(message.value.toString());
        // 在这里处理数据,例如推送到 ClickHouse 或进行实时分析
        await this.processEventData(eventData);
      }
    });
  }

  async processEventData(data: any) {
    // 在这里进行数据的清洗、聚合等处理
    console.log(`Processing event: ${data.event_type}`);
    // 将数据推送到 ClickHouse
    // this.clickhouseService.insertData(data);
  }
}

前端展示与报警

实时监控面板

前端可以通过调用 REST API 或直接查询 ClickHouse 数据库,获取实时监控数据,并使用图表库(如 ECharts)进行可视化展示。

import axios from 'axios';
import { useEffect, useState } from 'react';

function MonitoringDashboard() {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const response = await axios.get('https://your-server.com/api/monitoring/dashboard');
      setData(response.data);
    };

    fetchData();
  }, []);

  return (
    <div>
      {/* 使用 ECharts 或其他图表库展示数据 */}
    </div>
  );
}

报警机制

在系统中,可以根据实时监控数据设置报警规则,当某个指标超出预设的阈值时,触发报警机制(如发送邮件或消息通知)。

// 定期任务或实时检测
function checkForAlerts(data) {
  if (data.errorCount > 100) {
    sendAlert('High error rate detected!');
  }
}

function sendAlert(message) {
  axios.post('https://alert-service.com/api/send', {
    message,
    recipients: ['admin@example.com']
  });
}

简历优化(30K+ 简历样板)

技能描述

  • 熟练掌握 HTML、CSS、JavaScript、Typescript 以及 OOP、FP、 AOP 等设计思想

  • 掌握样式体系构建与落地,对 css 预编译、css in js、module css 以及 utility-first CSS 有深入研究,并从零改良过样式体系以支持 SSR、SSG

  • 熟悉 React、Vue 相关技术栈,熟悉 React、Vue 及相关技术框架的实现原理

  • 掌握构建工具 Webpack、Vite 等,掌握编译工具 Babel,并深入理解其原理,并参与 Rspack 构建

  • 丰富的数据可视化经验,熟悉 Canvas、svg 开发范式,理解 Echarts、Antv 原理,能根据业务需求基于 d3、zrender 开发自定义渲染引擎

  • 丰富的跨端开发经验,熟练使用 Taro、Flutter、React-Native 开发跨端应用,对构建 hybird App 有丰富经验,深入理解跨端开发编译原理

  • 基于 Node.js 开发脚手架、打包构建优化工具及中间件服务

  • 掌握常用设计模式、算法与安全知识,追求开发高质量、高可维护性代码,追求极致产品体验

  • 团队管理经验,并在项目架构设计与性能优化方面具有丰富经验

  • 算法与编程技术

    • 精通各种算法题的分类及解决方法,包括排序与查找、数据结构、动态规划、贪心算法、回溯算法、分治算法、图论算法、数学算法等。
    • 重点掌握动态规划的基本概念、解题步骤和经典题目。
  • 3D 数字孪生平台开发经验

    • 熟练使用 WebGL 和 WebAssembly 技术,开发高效的 3D 渲染引擎。
    • 精通正射影像和倾斜摄影技术,具备 Tile 和模型(包括白膜和精模)的处理经验,能够使用 Blender 进行模型制作。
    • 熟悉材质、光效和粒子系统的实现与优化。
  • 全面性能优化能力

    • 具备打包构建优化经验,熟练使用 Webpack 进行模块打包,掌握 chunk、treeshaking、happypack、cache-loader 等优化技巧,并使用 Webpack Module Federation 进行模块联邦管理。
    • 精通资源优化,能够有效进行图片、字体压缩,管理请求队列,并通过 OSS 和 CDN 提升资源加载速度。
    • 具有应用性能优化经验,包括数据结构优化和应用模块更新。
    • 深入了解缓存机制,熟悉强缓存(Expiration、Cache-Control)、协商缓存(Etag)和策略缓存(Service-Worker)的配置与管理。

项目描述

这个环节至关重要,很多同学不重视,简历随便写一写就开始投递了,结果投出去几百份可能一家公司面试都没有,结果就在怀疑前端行情出问题了

STAR 法则:

  • 遇到了什么问题 question,需求
  • 怎么评估解决方案,方案对比,方案落地 react 状态管理(redux、mobx、jotai、recoil)Vue3 -> Pinia
  • 具体方案落地
  • 结果反思,细节优化思考

大家先看这段描述:

技术栈:Java、Vue2、echarts、WEui、BaiduMap、JavaScript 、HTTP数据库:MySQL管理工具:SVN

责任描述:

1)产品前端研发负责人,主要负责整体样式沟通,样式调配实现;门户、管理平台、移动端、智端、可视化等前端内容实现;

2)实现组织管理、人员管理、党员关系转接、待办通知、绩效考核(复杂功能算法实现)、发展党员(25个流程)、可视化等主体功能,兼容性优化、适配1920*1080屏幕以及响应式布局实现;

3)相关功能开发,包含前后端、数据库;

4)门户框架搭建、门户整体设计、后端接口、门户前端 UI 实现等;

5)微信小程序框架搭建、小程序页面设计及开发、知识图谱技术预演;

6 )项目经理工作辅助,包含需求沟通、UI设计沟通、交付材料项目经历整理、前端代码质量管理、部分功能设计。

深度优化一下

工作内容和成果

  • 架构设计 】参与智慧管理平台整体架构设计、技术选型与方案评审,担任全栈开发,完成相关核心模块
  • 企微开发 】对接企业微信生态,基于企微 SDK 完成平台支付、消息推送、机器人等功能开发
  • 可视化 】主导完成平台可视化渲染引擎(可视化图表的组件,数据协议)设计与开发,基于 echarts (svgRenderer、canvasRenderer 一千万行数据的表格渲染【不能使用 虚拟滚动 】 canvas table,chunk)封装业务图表库,服务于平台可视化场景
  • 地图开发 】使用百度地图 SDK,封装业务地图渲染器(MapRenderer),包含:地图撒点、地区数据下钻等功能
  • 小程序与App 】基于 uniapp 实现智慧党建用户端多端开发落地,产物编译为 H5、微信小程序两端应用
  • 团队基建 】推进团队业务组件库、图表库与基础库沉淀,完成 10+ 个业务组件沉淀,以此提升了团队协同开发效率
  • 优化 】设计产品响应式系统,基于 media query 设计响应式端点规则,适配不同端应用的展示
  • 自研 OA 打通 】...

STAR

【技术栈】

  • Java、Vue2、ECharts、WEui、BaiduMap、JavaScript、HTTP
  • 数据库 :MySQL
  • 管理工具 :SVN

【产品前端研发负责人】

  • 情境 (Situation) :担任产品前端研发负责人,负责门户、管理平台、移动端、智端、可视化等前端内容的实现。
  • 任务 (Task) :主要任务是与设计团队沟通,调配和实现整体样式,确保产品界面的一致性和用户体验。
  • 行动 (Action) :我协调设计与开发团队,定期召开样式沟通会,亲自进行样式的调配与实现,并负责不同平台和设备的前端内容开发。
  • 结果 (Result) :成功实现了多个平台的前端开发工作,提升了产品的用户体验和一致性,获得了团队和用户的高度评价。

【实现复杂功能及优化】

  • 情境 (Situation) :项目需要实现复杂功能算法和大规模功能模块,包括组织管理、人员管理、党员关系转接、待办通知、绩效考核、发展党员(25个流程)和可视化功能。
  • 任务 (Task) :负责上述复杂功能的实现,并优化其兼容性和响应式布局。
  • 行动 (Action) :通过设计和实现复杂算法,确保各模块的功能性;进行兼容性优化,使系统适配1920*1080屏幕和响应式布局。
  • 结果 (Result) :成功实现并优化了所有复杂功能,系统在不同设备和分辨率下均表现良好,提高了用户操作的流畅度和满意度。

【全面功能开发】

  • 情境 (Situation) :需要进行前后端和数据库的全面开发,确保系统各功能模块的无缝集成。
  • 任务 (Task) :开发和实现相关功能,包括前端UI、后端接口和数据库交互。
  • 行动 (Action) :采用Java、Vue2等技术,开发并调试各功能模块,与后端团队密切合作,确保接口的准确性和数据的一致性。
  • 结果 (Result) :成功完成了所有功能模块的开发和集成,系统运行稳定,性能优异,受到了客户的好评。

【微信小程序开发与知识图谱预演】

  • 情境 (Situation) :项目需要开发微信小程序,并进行知识图谱技术的预演。
  • 任务 (Task) :负责小程序框架的搭建、页面设计及开发,同时进行知识图谱的技术预演。
  • 行动 (Action) :使用WEui、JavaScript等技术,设计并开发小程序页面,进行知识图谱的技术预演和验证。
  • 结果 (Result) :成功搭建了微信小程序框架,完成了页面设计和开发工作,知识图谱技术预演顺利,通过了技术验证。

【项目经理工作辅助】

  • 情境 (Situation) :在项目中辅助项目经理,确保项目需求沟通顺畅,UI设计协调到位,交付材料齐全,前端代码质量高。
  • 任务 (Task) :辅助项目经理进行需求沟通、UI设计沟通、交付材料整理、前端代码质量管理以及部分功能设计。
  • 行动 (Action) :积极参与需求和UI设计的沟通,整理和管理项目交付材料,进行代码审查和质量管理,并参与功能设计。
  • 结果 (Result) :成功辅助项目经理完成了项目的各项工作,提高了项目的开发效率和交付质量,确保了项目的顺利进行。

其实还不够,这些项目才是求职香饽饽

你可能不具备这些项目的实战经验,很多同学写了很多年管理系统,简单增删改查项目,如果不跳出这个圈子,很难在薪资上有非常大的突破!

  • 大厂 UI 组件库(Vue3)整体设计与开发实践(monorepo 架构)

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践(从零到一的架构、规范流程)

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 前端性能、异常与行为监控

  • 3D 可视化数字孪生低代码实战 💥

    • 基于 cesium(arcGis、超图) 方案的 WebGIS 开发实践
    • 基于 openlayer、mapbox 开发
    • 基于 WebGL 3D 可视化开发实践

年包 50W+ 薪资长线规划

核心要素

  1. 全面的技术储备

    1. 框架基础

      • Vue 和 React 经验:包括 Vue3 + Typescript 和 React18(Hooks、Concurrent)
      • 掌握框架原理:React 生态库(React-Router、Redux)和 Vue 生态库原理
    2. 工程化能力

      • 构建工具:Webpack、Vite、Rspack、ESBuild、swc
      • CI/CD 自动化:自动化构建和自动化部署
    3. 基建能力

      • Node.js、命令行工具开发(Cli)
      • UI 库、图表库、工具库开发
    4. 业务领域经验

      • 管理系统和图表类应用
      • 可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  2. 项目经验

    • 参与过至少两个大型项目,并主导过一个复杂项目
    1. 管理系统:包括项目搭建、技术方案选择、技术栈构建、CI/CD 流程
    2. 其他领域项目:如可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  3. 面试表现

    1. 个人介绍

      • 准备个人介绍草稿,涵盖基本信息、技术栈和项目重难点
    2. STAR 法则

      • 问题描述:阐述遇到的问题或需求
      • 解决方案评估:方案对比与选择(如 React 状态管理:redux、mobx、jotai、recoil,Vue3 使用 Pinia)
      • 方案实施:具体的实施步骤
      • 反思与优化:项目反思及优化建议
    3. 面试准备

      • 重点复习知识点:如 v8 内存管理、Promise A+ 规范、事件循环、this、面向对象编程原型
      • 技术储备:结合项目经验展示技术在项目中的应用
  4. 学历提升

    1. 现有学历:大专
    2. 未来计划:尽快取得本科证书(不需要注明具体年限)
    3. 学历背景:民办学校
    4. 内推建议:应对学历和工作经历问题,通过内推提升机会

补足短板

  • 项目简单,管理后台一做就是大半年,天天 CRUD

    • 看开源项目(react-hook-form ts 类型、hook 处理、状态管理、架构 Provider,keyPath)
    • 找一些不错的项目练手
    • 拿好的项目,学习完放在简历里, 可视化、编辑器、云表格、低代码、SaaS 产品、数字孪生、三维可视化
    • 1.自研:15K, 2.外包:20K ,这个火坑, 灰(供需决定)
  • 技术栈掌握不深不广,只会用 Vue2 (Vue3 + Typescript),React18(React stack reconciler)

  • 架构、方案设计没碰过

    • React,create-react-app、umi,没有真正从零到一去设计初始化过一个项目
    • Vue,Vue CLI,Vite/Webpack。Vue2 CLI 创出来项目 1. webpack、2.vite
  • 没有专精的技能或业务

    • 自驱 (假定自己是 Leader),项目的赢利点、商业价值【 可视化、编辑器、白板、团队基建、AI产品
    • 与生俱来有些东西,好奇心、自驱力、清晰规划
    • 我:管理平台,HPE(官网、后台管理),云表格(维格表、飞书云表格)、云编辑器(CKEditor 老【html string】)(语雀、【石墨文档】)

妙码学院——全程陪跑、督学、内推

⚠️ 暂不支持的文档区域,【文档小组件】

  • 跨端开发 Taro(Taro 编译器 compiler、运行时 runtime)、uniapp
  • 协同编辑器(文档类、画板类)wangEditor、CKEditor
  • 团队基建工程(UI 库、图表库、Cli -> 产生产物 npm 包)
  • 3D 可视化数字孪生 bigdata
  • 低代码平台

课程体系 2.0 升级,除了基础知识夯实,融入了更多项目实战内容,包含:

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 大厂 UI 组件库(Vue3)整体设计与开发实践

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践

  • 埋点与数据监控平台实战

  • 3D 可视化数字孪生实战 💥

    • 基于 cesium 方案的 WebGIS 开发实践
    • 基于 WebGL 3D 可视化开发实践

妙码学院全网独家项目实战矩阵

所有项目实战,均完全 从零到一手写纯原创 ,项目架构与编码规范真一线大厂级。

  • 微前端在分拆原子应用场景下的落地与实践

  • 协同编辑器从零到一架构实现

  • 推动团队基建落地

    • React UI 库
    • Vue Composition API 库
    • 企业级脚手架
  • 数字孪生平台整体架构设计

  • 企业级无代码可视化平台实践(Vue3)

  • 低代码平台设计与实现

    • 编排引擎
    • 流程引擎
    • 编辑器
    • 代码执行器与 JavaScript 沙箱
  • 用户行为分析 SDK 及监控可视化整体实现

  • 可视化渲染引擎设计与实现

  • 基于 RAG / Agent 前端 AI 应用流程编排平台

不同阶段对前端人的硬性要求

以下是对您提供的内容进行权威和专业化改写的建议:

1~3年

在此阶段,重点在于评估个人的基础知识和热情。对前端基础、计算机原理、网络通信和算法等领域的要求较高。由于在此阶段难以评估业务深度,因此更多关注基础知识的掌握程度。

  • 关键在于通过学术教育或网络资源加强基础知识;
  • 在简历中以多种方式展示对前端的热情,展现个人潜力;
  • 积极探索前沿技术,关注国内外技术动态;
  • 尝试开发小型项目或参与社区开源项目;
  • 建立技术博客,以输出促进知识吸收。

3~5年

此阶段通常是向成为独立工程师发展的关键时期,避免重复使用有限的经验。

  • 关注社区中关于进阶的资料和路线,强化基础知识;

  • 深入掌握常用框架的高级用法,探索其原理;

  • 在业务开发中不仅完成功能,还需考虑项目结构设计、封装基础工具、设计和开发基础组件;

  • 思考提高团队效率的方法,例如:

    • 集成代码检验和风格统一插件(如 eslint、stylelint、prettier、spellcheck);
    • 从工程化角度提高本地开发效率,优化webpack构建,探索esbuild、vite等工具;
    • 对于多项目开发,整理差异和统一部分,建立内部脚手架以减少重复工作;
    • 尝试搭建CI/CD平台,维护公司内部的通用npm包;
    • 培养软技能,如沟通协作,协调各角色共同推进目标。

5年以上

进入此阶段,可能朝技术专家或管理方向发展。期望您能够独立负责高复杂度项目,突破关键技术难题。

  • 负责技术调研,关注行业趋势,选择最优技术方案,具备决策能力;
  • 拥有丰富的技术经验和技术储备,能够解决遇到的困难,并有自己的方法论;
  • 协助或主导业务目标制定,合理推动项目达成预期效果;
  • 是否具有团队领导经验,能够协调跨团队项目,处理团队成员情绪问题,解决技能分布不平衡等问题;
  • 打造技术氛围,促进团队共同成长。

职业规划指导

评论区选取三位同学互动,其他同学也可以联系咨询老师,文字方式提供辅导解答。

【未知组件reminder】