大型网站重构指南 第1.2部分:Nodejs 系统可观测性 OpenTelemetry+SigNoz

简介: 大型网站重构指南 第1.2部分:Nodejs 系统可观测性 OpenTelemetry+SigNoz

在上一篇文章中我们介绍了 SonarQube,它是一种代码静态质量检查的工具。

但有时候一些问题在静态检查期间并不能完全暴露出来,这些问题会带到线上,在用户使用软件的时候,出现问题。

这时候就需要针对程序的运行时进行检测,这项能力也就是可观测行。也就是本篇文章要做的事。


OpenTelemetry 介绍


OpenTelemetry 是系统可观测行框架这个领域的佼佼者。

它是一个完全开源的库,它提供了一组 API/SDK 来帮助我们对程序进行监控、日志和追踪。而这三者就是目前可观测性的三大核心。

在可观测性这个领域,它几乎是唯一的事实标准。

OpenTelemetry 最初只是针对复杂的后端应用进行设计的,但现在同时也支持前端。不过 OpenTelemetry 在前端方面并不是最优的选择。

所以 ichati.cn 只在后端使用了 OpenTelemetry。前端可以选择一些更合适的工具,比如 Sentry。

OpenTelemetry 支持 C++、Java、JS、Go、Python、Rust 等 11 种主流语言。同时还可以轻松地和很多主流框架进行集成。比如 Java 的 Spring、Nodejs 的 Express、Nestjs、ASP.NET Core 等。

它的原理我就不讲了,稍微会复杂一些,通过进程间通信和上下文传播来完成的。我们主要关注如何利用 OpenTelemetry 来达到观测 ichati.cn 的目的。


OpenTelemetry 与 Nestjs 集成


ichati.cn 的后端使用 Nestjs 开发的,所以我们先将 OpenTelemetry 和项目进行集成。

这里你必须有一个 Nodejs 的项目,可以不是 Nestjs 框架的项目,比如 Express 也可以。

然后安装 OpenTelemetry 的依赖。


npm install @opentelemetry/sdk-node \
  @opentelemetry/api \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/sdk-metrics
接下来创建一个 instrumentation.ts 文件。
TypeScript
复制代码
import { NodeSDK } from '@opentelemetry/sdk-node';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { PeriodicExportingMetricReader, ConsoleMetricExporter } from '@opentelemetry/sdk-metrics';
const sdk = new NodeSDK({
  traceExporter: new ConsoleSpanExporter(),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new ConsoleMetricExporter()
  }),
  instrumentations: [getNodeAutoInstrumentations()]
});
sdk
  .start()

然后在项目的 HTTP 服务启动之前导入这个文件。通常会是 main.ts。

重新启动项目。随着你的接口被调用,你会发现控制台会有很多类似的输出:


{
  traceId: 'd4b107c7971580478eef859a2fd979aa',
  parentId: undefined,
  traceState: undefined,
  name: 'GET /user',
  id: '573d0fb86048fc11',
  kind: 1,
  timestamp: 1685629667330000,
  duration: 345450,
  attributes: {
    'http.url': 'http://127.0.0.1:4401/user',
    'http.host': '127.0.0.1:4401',
    'net.host.name': '127.0.0.1',
    'http.method': 'GET',
    'http.scheme': 'http',
    'http.target': '/user',
    'http.user_agent': 'insomnia/2023.1.0',
    'http.request_content_length_uncompressed': 0,
    'http.flavor': '1.1',
    'net.transport': 'ip_tcp',
    'net.host.ip': '::ffff:127.0.0.1',
    'net.host.port': 4401,
    'net.peer.ip': '::ffff:127.0.0.1',
    'net.peer.port': 53063,
    'http.status_code': 200,
    'http.status_text': 'OK',
    'http.route': '/user'
  },
  status: { code: 0 },
  events: [],
  links: []
}

不仅仅是 HTTP 的入站/出站会被检测,几乎其他所有的行为都会被检测,包括TLS 的连接/断开、文件系统的调用、中间件的调用、定时任务等等。

我们仅仅是把这些数据输出到控制台中显然是不够的,因为纯文本的内容不利于数据的分析和可视化。

我们还需要有一个平台来存储、查询、分析这些日志。


SigNoz 介绍


OpenTelemetry 中有一个 Exporters 的概念,其实就是一个提供存储日志数据和搜索的系统。

这类系统的开源项目有很多,比如 Jaeger、SkyWalking、Zipkin、Haystack、SigNoz 和 Grafana 等。

它们中的大多数最初都支持系统检测功能,但是后面都演变变成了纯粹的存储和可视化系统。把检测功能让给了 OpenTelemetry,让专业的人做专业事。

这里 ichati.cn 选择了 SigNoz。

SigNoz 不是里面最好的,也不是最成熟的。选择它的理由是,它可视化功能非常强大。我认为这类系统最重要的功能就是数据可视化和查询。


安装并启动 SigNoz


安装 SigNoz 很简单,但是过程可能比较慢。

第一步,首先电脑上安装 Docker。SigNoz 只支持 Docker 一种方式部署。

第二步,运行以下三行命令。


git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy/
./install.sh

不出意外的话,就可以看到启动成功。


++++++++++++++++++ SUCCESS ++++++++++++++++++++++
🟢 Your installation is complete!
🟢 Your frontend is running on http://localhost:3301

然后浏览器访问 http://localhost:3301 就可以看到 Dashboard 了。

现在的几个项目都是 SigNoz 默认的演示项目。

image.png


将 OpenTelemetry 的数据发送到 SigNoz


我们之前的代码实现是将 OpenTelemetry 的数据输出到控制台,现在我们要输出到 SigNoz。

要把 OpenTelemetry 的检测数据发送到 SigNoz,还需要安装三个包。


npm install @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions

然后修改代码。


import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'ichati-backend',
  }),
});
process.on('SIGTERM', () => {
  sdk
  .shutdown()
  .then(() => console.log('Tracing terminated'))
  .catch((error) => console.log('Error terminating tracing', error))
  .finally(() => process.exit(0));
});
export default sdk;

注意代码中的 4318 端口是 SigNoz 默认的端口。

最后在 main.ts 中导入 sdk 运行。


import instrumentation from './instrumentation';
instrumentation.start();

现在我们发送一些请求,就可以在 SigNoz 中查看到项目了。

image.png


SigNoz 云托管


实际上,像 ichati.cn 这类中小型团队,不想花太多时间在基础设施上面,所以运行了一段时间的 SigNoz 后,觉得管理服务器比较麻烦。

后面切换到了云服务商 elest 上面: elest.io

在 elest 上面,SigNoz 最便宜的套餐是每月 36 美元,2C、8G、80G 存储。我认为还算划算。虽然比自己买裸机要贵一点,但绝对比单独招个人来做运维划算得多。


数据的用途


以上步骤都只是一些繁琐无聊的项目搭建和配置,现在我们才正式进入主题。

我们应该关心应用的哪些数据呢?

第一是接口的延迟。

SigNoz 将接口延迟分为了三类:

  • P50,也就是中位数
  • P95,前 95% 的情况
  • p99,也就是前 99% 的情况。

这个数据指标可以反应系统的性能和稳定性。

第二是 Rate。单位是 ops/s,也就是系统每秒处理的请求数。

这个指标主要反应系统的性能。

image.png

第三是操作的错误率。

这个指标主要反映系统的稳定性。

image.png

我们还可以通过条件筛选来查看更详细的内容,SigNoz 支持的筛选项非常多,包括时段、操作名、HTTP 请求方法、请求 URL、请求来源、Trace ID 等。

image.png

如果你想查看某些特殊的接口,我们还可以查看它的火焰图和调用堆栈,比较有利于排查问题。

image.png

以上就是常见的数据功能。

SigNoz 的强大还不止于此,它还有一些其他功能,比如自定义 Dashboard、定义 Alert、服务地图等等。

这样当系统出现故障时可以方便的通过某行方式通知到对应的人。比如邮箱、飞书、微信等等。

但目前 ichati.cn 还用不到这么多功能。所以就不对这些功能做更深入地介绍了。

篇幅所限,本文暂时结束。

后面会持续更新,让我们一起期待《大型网站重构指南》的下一篇。

如果你对最新的技术感兴趣,特别是对 Web3、AI 相关的内容感兴趣,可以添加我的微信 LZQ20130415,拉你进群交流。



相关文章
|
2月前
|
小程序 测试技术
基于微信小程序+SSM+Vue+Node实现智慧旅游商城系统(三)
基于微信小程序+SSM+Vue+Node实现智慧旅游商城系统
|
1月前
|
缓存 JSON JavaScript
Node.js模块系统
Node.js模块系统
16 1
|
2月前
|
监控 JavaScript API
局域网监控软件的实时通知系统:利用Node.js和WebSocket实现即时消息推送
本文介绍了如何使用Node.js和WebSocket构建局域网监控软件的实时通知系统。实时通知对于网络安全和家庭监控至关重要,能即时发送监控数据变化的通知,提高响应速度。通过Node.js创建WebSocket服务器,当数据变化时,监控软件发送消息至服务器,服务器随即推送给客户端。此外,还展示了如何利用Node.js编写API,自动将监控数据提交到网站,便于用户查看历史记录,从而提升监控体验。
122 3
|
2月前
|
消息中间件 存储 JavaScript
构建一个基于Node.js的实时数据流处理系统
【5月更文挑战第30天】使用Node.js构建实时数据流处理系统,结合WebSocket实现双向通信,Kafka作为消息队列,Redis做数据存储和缓存,D3.js用于数据可视化。系统包括数据源、传输、处理、存储和可视化五个关键部分,适合高并发、低延迟的实时监控与分析需求。
|
2月前
|
存储 Web App开发 JavaScript
构建基于Node.js的实时通信系统:技术详解
【5月更文挑战第22天】构建基于Node.js的实时通信系统,利用WebSocket协议和Socket.IO库实现全双工通信。系统采用Node.js作为服务器环境,处理高并发,结合WebSocket进行高效数据交换。Socket.IO提供WebSocket封装,保证兼容性。系统架构包括客户端(使用WebSocket连接服务器)、Node.js服务器(处理连接、消息、认证和数据存储)和数据库。开发流程包括环境搭建、服务器和客户端开发,最后部署测试。该系统可为在线聊天、视频会议等场景提供流畅交互体验,未来可优化性能和扩展性。
|
2月前
|
缓存 并行计算 JavaScript
【Node系列】模块系统
Node.js 的模块系统是其核心特性之一,允许开发者编写可复用的代码,并通过简单的导入和导出机制来共享和使用这些模块。
26 3
|
2月前
|
缓存 JavaScript 前端开发
Node.js的模块系统:CommonJS模块系统的使用
【4月更文挑战第29天】Node.js采用CommonJS作为模块系统,每个文件视为独立模块,通过`module.exports`导出和`require`引入实现依赖。模块有独立作用域,保证封装性,防止命名冲突。引入的模块会被缓存,提高加载效率并确保一致性。利用CommonJS,开发者能编写更模块化、可维护的代码。
|
2月前
|
JavaScript API
node.js之模块系统
node.js之模块系统
|
2月前
|
JavaScript 前端开发 关系型数据库
分享66个NodeJs系统源码总有一个是你想要的
分享66个NodeJs系统源码总有一个是你想要的
73 1
|
2月前
|
Web App开发 JavaScript 前端开发
了解 Node.js 的运行机制:从事件循环到模块系统(下)
了解 Node.js 的运行机制:从事件循环到模块系统(下)
了解 Node.js 的运行机制:从事件循环到模块系统(下)