likes
comments
collection
share

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

作者站长头像
站长
· 阅读数 10

最新活动

◇ 杭州 AI 峰会:AI 最后一公里,变现探索 🔗 Link

AI 浪潮,一起搞钱!早鸟有限,详情链接:xhkzr.xet.tech/s/2LquL0

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务


正文如下

各位小伙伴大家好,本次我要和大家分享的内容是《基于 Node.js 的前端监控系统日志处理实践》。首先给大家做一个自我介绍,我叫刘刚,来自兴盛优选。有 8 年的 Node.js 开发经验,于 2020 年加入兴盛优选,我一直在公司的体验技术部 - 前端架构部工作,并负责自研的前端监控系统 - 棱镜平台。作为该产品的开发负责人,我在过去三年中负责了平台的功能设计和技术方案的制定,积累了一些前端监控系统的经验。希望本次与大家聊一下这个话题,相互交流进步。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

本次我的分享分共有 4 个部分,首先我将对前端监控系统做一个简单的介绍,包括业务背景、产品功能,其实就是介绍前端监控系统的日志处理的流程,了解日志在监控系统中的整个的处理流程之后,我将从代码出发给大家详细讲一下日志的处理,以及最后将向大家介绍一下我们之后的一个对于这个棱镜产品的一些展望。

  • 前端监控系统简介
    • 业务背景
    • 产品功能
  • 日志处理的工作流
  • 日志处理实践
    • 代码出发详细讲解日志处理
  • 未来展望
    • 对棱镜产品的展望和发展方向

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

前端监控系统简介

背景

先给大家介绍第一部分,前端监控系统的简介,特别是我们棱镜平台的监控系统。在谈论前端监控之前,我们首先了解一下前端监控的背景。作为与用户最接近的一环,我们的开发人员在接入前端监控系统之前,对线上性能和异常数据毫无感知。任何性能问题或异常都依赖于用户的反馈,需要手动统计数据,然后尝试修复问题。

也经常会遇到业务的吐槽,比如页面渲染慢等等。然而,在没有监控系统之前,我们无法提供明确的解释,因为可能是用户的网络问题,或其他各种原因,而不一定是我们的系统性能问题。但由于缺乏证据,我们无法反驳这些投诉,只能接受。

因此,基于这些问题,我们决定接入一个监控系统,以及时识别系统性能问题所在,进行全面的前端性能分析。在接入前端监控系统之前,我们进行了市场调研,研究了各种开源和付费的前端监控系统。最终,出于数据安全性、成本和与我们业务的贴合性等因素考虑,我们决定自行开发一款监控系统。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

产品功能

下图是棱镜平台目前提供的工具界面。我们的平台提供了一个全面的应用数据仪表板,包括错误分析、性能分析、埋点分析、增长分析、以及智能预警等功能。通过这个数据仪表板,我们能够有效地查看应用在客户手机上的各个版本的分布情况。特别是,由于我们主要业务是小程序,我们能够获取用户手机上的小程序版本和基础库信息。这些信息有助于我们更好地制定产品决策,减少因系统问题或版本问题而导致的用户体验问题。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

产品架构

然后简要介绍一下我们棱镜产品的整体架构图,从下往上依次为:

  1. 采集端:我们在客户端采集各种数据,包括性能数据、错误数据、用户行为等等。
  2. 日志服务:采集的数据最终上报到我们的日志服务,在这里进行根据 Node.js 处理。
  3. 数据清洗:经过处理后的数据会经过数据清洗,然后存储到数据库中。
  4. 异常监控:我们还会消费 Kafka 数据,实时监控错误和异常情况,以实现实时错误告警。
  5. 客户端:客户端利用 Node.js 查询数据库,并进行前端可视化展示。例如,我们之前看到的页面上的数据都是通过 Node.js 后端进行数据的查询。

这个架构帮助我们采集、处理、存储和展示各种数据,以便有效地监控前端性能和错误情况。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

产品成果

接下来讲一下目前整个产品的成果,就接入方面而言,我们已经成功覆盖了公司的所有产品线,而且实现了零成本的接入。就日志量而言,我们目前平均每天处理超过 30 亿条日志数据。在监控方面,我们已经实现了分钟级的告警,能够及时准确地通知相关负责人。此外,我们的数据是实时分发的,没有任何延迟。这意味着,一旦发生问题,我们会立刻触发告警,通知相关的业务、开发人员、产品团队等,以便迅速做出决策,减少因故障而导致的生产损失。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

日志处理的工作流

日志工作流

第二部分给大家介绍一下我们监控系统中收集和处理日志数据的工作流程。数据采集过程大致如下图所示:

  1. 不同业务的应用首先接入采集的 SDK。SDK 负责采集各种数据,并将其上报到统一的日志服务,其中日志服务由 Node.js 支撑。
  1. 在日志服务内,数据经过验证、过滤等一系列处理后,最终被写入 Kafka。这一步后,产生两个主要链路。
    • 数据存储链路:数据被清洗并写入数据库。最初,我们使用 MySQL 来存储数据,但随着业务增长,数据量大幅增加,因此我们经过调研,最终选择了 ClickHouse 作为我们的数据存储解决方案。
    • 监控链路:在日志服务中,我们消费上报的日志数据和错误日志数据,然后根据规则进行筛选、过滤等一系列处理,及时触发告警。

这个流程简要地描述了我们的日志数据上报和处理过程。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

日志服务功能

接下来,我向大家介绍我们的整个日志服务所提供的一些功能。例如,我们使用了 Node.js 加载的服务日志,为数据提供验证。具体来说,我们要求数据必须经过验证,确保它是由我们的平台注册的用户应用程序所生成的。我们之前曾遭受过一些攻击者,其中一些攻击上报了并非由我们的系统应用程序生成的数据。这些非法数据实际上可能导致程序出现异常。因此,我们进行了数据验证,然后进行一些数据预处理。

举个例子,当我们收集到客户端的地理位置信息后,我们在 Node.js 的日志服务中进行数据预处理。我们将地理位置数据进行解析,然后将解析后的信息与元数据一起存储到 Kafka 中。此外,我们还会进行配置的下发。因为我们的 SDK 支持动态埋点,当应用程序启用了动态埋点后,SDK 会主动请求我们的日志服务,以获取动态埋点的配置信息。

另外,像之前介绍过的监控和告警模块。除此之外,我们还提供一些其他较小的功能,例如 open API。这些 API面向第三方公司的内部系统,因为我们的数据都可以在我们的系统中找到,我们可以将数据提供给第三方,以供其进行所需的分析。虽然我们的平台本身也提供了一些分析功能,但可能无法完全满足第三方的需求,因此我们提供API 给第三方,让他们自行实现并调用我们的接口。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

日志服务架构

最后介绍一下 Node.js 日志服务的架构。我们的日志服务是一个集群,部署在腾讯云,暂时尚未考虑跨云状态。我们利用了腾讯云的 CLB 来均衡负载。当我们的用户客户端发起 SDK 请求以上传数据时,CLB 会将 HTTP 请求均匀地转发到我们的 Node.js 服务集群。Node.js 服务在经过数据验证、过滤等处理后,将处理过的请求返回给客户端。标志着整个数据上报过程的结束,接下来是对数据的后续处理。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

日志处理实践

数据规范

第三部分我将基于实际代码,向大家介绍我们的日志处理过程。首先,在进行日志处理之前,我们必须定义数据规范,因为后续的所有处理都要根据这个规范来进行。我们需要定义数据模型,以便在后续的处理中使用。因此,数据规范的定义非常重要,如果定义得不好,将导致在 Node.js 端和数据清洗等后续流程中需要执行许多额外的操作。因此,数据规范的定义必须特别仔细,同时考虑到可扩展性等因素。

在设计字段时,我们还要避免字段的歧义性。字段的命名应该清晰,不应该造成混淆,一个字段不应该有多种不同的含义。否则,在开发过程中就会出现困惑,需要进行额外的数据开发。此外,在设计数据规范时,还需要考虑到数据上报的网络成本。如果数据量过大或验证等因素导致页面卡顿,会影响用户体验。

因此,在设计数据规范时,我们需要充分考虑这些因素。如下图所示,这是我们当前平台上错误上报规范的一个示例,我们平衡了数据传输成本和存储成本。在 SDK 端,我们进行了数据的批量聚合处理,而不是每次采集数据就立即上报。这减少了客户端上报请求的次数,并减轻了服务端接收数据请求的压力。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

上报

接下来,为大家介绍我们的数据上报接口。实际上,我们的数据上报接口非常简单,我们使用了一个 KOA JS 实现了一个 HTTP 接口。但是,我们没有采用在左图中显示的 KOA 剥离的中间件,因为我们发现,使用 KOA 中间件会导致性能吞吐量很低,延迟特别长,从而导致整个接口的响应速度超过了 200 毫秒。一旦发现了这个问题,我们进行了排查,并查看了 KOA 剥离源码,发现其中实际上包含了许多不适用于我们场景的额外处理。因为我们的场景只需要接收数据并提取数据,所以我们自己查阅了文档,然后在 Node.js 中直接实现了原生的 HTTP 请求体接收方式,用于接收来自用户端的请求数据。接收数据后,我们将其分层处理,JSON 化,然后将其写入 Kafka。

目前,我们整个数据上报接口的 P99 响应时长基本都在 100 毫秒以内。对于我们的小程序用户来说,这已经相当快了,因为我们的数据是批量上报的,数据量较大,相当于在客户端进行了数据聚合,每次上报都包含 20 条数据,而且请求体的长度也很大。因此,我们的服务支持了我们整个业务平台产品的数据上报。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

监控

下面给大家介绍一下我们如何处理监控数据。在我们的 Node.js 中,我们使用 Kafka.js 库来消费数据。当我们建立连接时,我们会使用自定义的消费者来订阅错误的主题。一旦我们消费到数据,我们首先对其进行JSON解析,然后将其进入一个队列进行处理。因为我们的数据是批量实时消费的,所以当消费到数据后,我们进行排队处理,执行各种操作,如过滤和统计。我们需要对错误出现的次数进行统计,只有当满足了用户自定义的条件,例如高发次数和告警时长等条件,才会触发告警。

目前,我们的告警是通过企业微信的 Webhook 实现的,但同时我们也在进行短信、电话等其他方式的告警功能的实现。下面左图展示了我们的消费代码,我在这里只简单粘贴了一部分,实际上还有许多业务逻辑需要根据不同的业务进行实时调整。右图显示了我们将 Node.js 日志服务下的告警规则处理后发送的告警信息,其中包括错误的页面、错误的接口、错误的响应以及在某个时间段内受到影响的用户数量等信息。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

未来展望

最后,分享一下我们棱镜系统未来的展望。我们希望将 Node.js 与 Rust 相结合,因为我一直在学习 Rust,也尝试编写了一些 demo,发现 Rust 在性能方面非常强大。众所周知,Node.js 在处理 I/O 方面具有优势,但在 CPU 性能上并不出色。然而,在日志处理中,我们需要进行许多需要 CPU 处理的操作,例如在数据计算中,比如在错误告警中,我们需要进行统计和计算,需要进行大量的 CPU 计算。但目前,Node.js 在这方面并不太适合,而 Rust 在性能方面表现卓越。

早些时候,在 Rust 出现之前,我们也经常在 Node.js 中使用一些与 C++ 结合的包。例如,我们之前在前端中使用的 SaaS 库实际上使用了一些 C++ 的原生模块。但是实际上,在使用 C++ 原生模块时,体验非常差,因为它需要依赖 Python 和 GPT 来进行编译,这会导致许多编译问题。我们曾在早期的操作系统版本中遇到编译错误,导致安装失败等问题。要解决这些问题,需要花费大量时间。但现在有了 Rust,整个模块不需要再进行编译,因为 Rust 会直接将这些模块打包分发给不同的平台,无需在客户端执行额外的编译,从而节省了大量排错、安装和编译等问题。

此外,Rust 在语言方面具有许多优势,如卓越的性能、内存安全性等。在生态系统方面,Rust 的生态系统也变得非常丰富,因为现在许多包都以 Rust 编写。而我们的 Node.js 也拥有丰富的生态系统,许多模块可以通过 Rust 来实现。例如,如果我们使用 Rust 编写一个原生模块,然后在 Node.js 中调用,相比于直接使用 JS 版本,性能会大大提高,产生质的变化。

因此,基于这些因素,将 Node.js 与 Rust 相结合,将有助于提高我们前端监控系统的性能和安全性。目前,我们的产品在一些方面还存在不足之处。通过 Node.js 与 Rust 的结合,我们可以期待在性能优化和安全性方面取得巨大的进步。未来,我们将继续探索 Node.js 与 Rust 的结合,如果有机会的话,我还可以分享一些有关棱镜产品在Node.js 与 Rust 结合方面的经验和成果。

【玩转 Node 连载 4/6】如何使用 Node.js 搭建高性能测试服务

以上就是我所有的分享,谢谢大家。