浅析Sentry 架构设计

2,818 阅读8分钟

简介

Sentry 是一个开源的实时错误监控的项目,支持多端的配置,包括 web 前端、服务器端、移动端及游戏端。

支持各种主流语言,例如 python、oc、java、node、javascript 等,也可以应用到各种不同的框架上面,如前端框架中的 vue 、angular 、react 等最流行的前端框架,此外还提供了 GitHub、Slack、Trello 等常见开发工具的集成。

Sentry 使用 python 的 Django 编写后端服务;8.0 版本开始使用了 React.js 构建前端 UI。

Sentry 采用的是 C/S 架构,客户端通过 SDK 的方式集成到应用程序中,并自动将错误发送到 Sentry 的

服务端。一般情况下,我们只需要在项目里安装 SDK 且进行少量配置,十分方便。

官方提供的 SaaS 服务,有 免费收费 两种模式:

  • 个人开发者(免费),支持所有语言,不支持团队协作,功能受限较多;
  • 团队/企业(收费),$26/月起,收费主要以事件数量和一些高级功能为准;

除此之外,作为开源项目,Sentry 也支持私有化部署,官方提供了相关 文档

后端架构设计

1. 概述

边代表服务之间的依赖关系

相关服务说明

  • Load balancer:负载均衡器 e.g. nginx
  • Sentry(web):后台管理平台
  • Sentry(work):内置任务队列、可以以更异步的方式处理任务。如:当一个事件出现而不是立即将其写入数据库时,它会向队列发送一个作业,以便可以立即返回请求,并且后台工作人员会实际处理保存该数据。
  • relay:消息处理与转发,详见(2)
  • snuba:是一种在 Clickhouse 之上提供丰富数据模型以及快速摄取消费者(直接从 Kafka 获取数据)和查询优化器的服务。详见(4)
  • kafka:消息队列、是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统,常用于web/nginx日志、访问日志,消息服务等等;
  • zookeeper:管理分布式系统节点,主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理;
  • clickhourse:一个开源的面向列的数据库管理系统;
  • postgres:一个免费的对象-关系数据库管理系统;
  • Redis:一个开源的跨平台的非关系型数据库;
  • Memcached:服务器系统内存;
  • Symbolicator:主要用于错误信息格式化及异常处源代码还原。

2. 消息处理-relay

Sentry 中继服务器应用程序:该模块包含run启动中继服务器的功能。它响应多个受支持的端点,向下游中继提供查询并将接收到的事件发送到上游。通过中继的事件路径如下:

上图标注:事件摄取的简化概述(忽略 snuba/后处理)

2.1 处理启用与否?

Relay 可以作为 Sentry 安装的一部分运行,例如在sentry.io的基础架构内,或作为转发代理在应用程序旁边运行。当 Relay 在启用处理的情况下运行时,此处描述的许多步骤将被跳过或以有限的形式运行:

  • 事件规范化做不同(更少)的事情。
  • 在某些模式下,项目配置根本不会从 Sentry 中获取(而是从磁盘中获取或使用默认值填写)。
  • 事件被转发到 HTTP 端点,而不是被写入 Kafka。
  • 速率限制不是使用 Redis 计算的,而是 Relay 仅尊重前面提到的端点的 429s。
  • 根本不应用过滤器。

2.2 端点内部

返回的 HTTP 响应只是对事件实际结果的最大努力猜测。4xx如果我们知道响应将失败(基于缓存的信息),我们只返回一个代码,如果我们不返回一个 200 并继续异步处理事件。这种异步处理曾经在 StoreView.

这样做的效果是服务器将比以前更快地响应,但我们可能会为最终不会被接受的事件返回 200。

通常 Relay 在比旧的更多的情况下会返回 200 StoreView

2.3 后台任务

对于返回 a 的事件,200我们会生成一个进程内后台任务,该任务完成旧任务的其余部分StoreView

此任务更新速率限制和禁用项目/键的内存状态。

2.4 结果消费者

结果是 Kafka 中的小消息,其中包含事件 ID 和有关该事件是否被拒绝的信息,如果是,为什么。

结果消费者主要负责更新 Sentry 中的(用户可见的)计数器(缓冲区/计数器和 tsdb,它们是两个独立的系统)。

2.5 摄取消费者

摄取消费者从 Kafka 读取已接受的事件,并更新一些统计信息。其中一些统计数据与计费相关。

它的主要目的是做insert_data_to_databasePython 商店里做的事情:调用preprocess_event,然后是源映射处理、本地符号化、分组、snuba 和所有其他与 Relay 无关的东西。

2.6 Relay内部组件时序图:

3 搜索引擎-snuba

是一个由两部分组成的服务,旨在将 ClickHouse 从 Sentry 中抽象出来。除了应用程序代码和 ClickHouse,我们还利用了其他一些帮助服务来完成 Sentry 的事件数据流。

3.1 数据流

3.2 数据读取

Snuba 的查询服务器由 Flask Web 服务提供支持,该服务使用 JSON 模式为 Sentry 开发人员提供丰富的查询接口。

通过提供 Snuba 客户端而不是直接使用 ClickHouse SQL,我们可以向应用程序开发人员隐藏许多底层复杂性

此外,我们现在进行集中更改,影响各种不同的查询模式。

例如,我们使用 Redis 来缓存单个查询结果,它将我们的一些更突发和频繁重复的查询合并到单个 ClickHouse 查询中,并从 ClickHouse 集群中移除不必要的负载。

3.3 数据写入

写入 Snuba 开始于读取已通过 Sentry 规范化和处理步骤的 JSON 事件的 Kafka 主题。它批量处理事件,将每个事件转换为一个元组,该元组将映射到单个 ClickHouse 行。批量插入 ClickHouse 非常关键,因为每次插入都会创建一个新的物理目录,其中每列都有一个文件,ZooKeeper 中有相应的记录。这些目录由 ClickHouse 中的后台线程合并,建议您大约每秒写入一次,这样就不会有太多写入 ZooKeeper 或磁盘上的文件需要处理。数据按时间和保留窗口划分,使我们能够轻松删除超出其原始保留窗口的任何数据。

4. 事件流&存储

如何保存事件。边表示通过系统的数据流。

4.1 客服端应用上报

使用Sentry sdk的客户端所上报数据、数据的格式如下:

{"exception":{"values":[{"stacktrace":{"frames":

[{"colno":"12","filename":"http://test.com/f.js",

"function":"?","in_app":true,"lineno":13}]},"type":

"SyntaxError","value":"Use of const in strict mode." ...

4.2 数据处理与转发

  1. 开始事件处理传入的请求。立即返回200或429。然后在内存中队列事件,并做一些基本的检查:
  1. 发起一个会话至 "ingest-events"

4.3 推入消息队列

将消息推入kafka 摄取流,同时缓存用于在事件处理阶段之间传递数据

4.4 消费消息队列

负责从Relay中消费已处理的事件。同步运行preprocess_event(不是作为 sentry任务,而是作为函数调用)

  • symbolicate_event:这个任务是为需要它的事件(例如原生事件)处理符号化(使用Symbolicator服务)。
  • process-event:在这个阶段发生的事情为 stacktrace 处理及插件预处理器(例如,对于javascript,我们试图应用源映射和翻译错误消息),
  • postprocess-event 触发警报,一个负责警报的 Celery 任务(由 Sentry 中的 Kafka 消费者从事件流中读取)
  • save-event:将前序已处理事件流进行保存至数据库(PostgreSQL\Nodestore)、snuba所消费的 kafka队列内,用于管理后台snuba 服务消费后查询分析

前端SDK原理

window.onerror 劫持

Sentry 对 window.onerror 函数进行了重写,在这里实现了错误监控的逻辑,添加了很多运行时信息帮助进行错误定位,对错误处理进行跨浏览器的兼容等等。

unhandledrejection 事件监听

在我们使用Promise的时候,如果发生错误而我们没有去catch的话,window.onerror是不能监控到这个错误的。但是这个时候,JavaScript引擎会触发unhandledrejection事件,只要我们监听这个事件,那么就能够监控到Promise产生的错误。

数据上报

Sentry 对数据上报方式做了统一,从其源码中获知优先使用 fetch、其次是 xhr 接口,更多关于接口判断可参考源码查看实现细节;

总结

首先介绍 Sentry 是什么、以及它具备可监控的覆盖面与能力,及其实现所采用的开发语言等等,它做到了帮助研发快速发现与定位且变被动为主动的一个监控系统,如此般优秀的监控工具有必要揭开其面纱探索其底层设计;此举不仅能让我们更懂它,也能深入学习其背后所蕴含的智慧,感谢阅读、希望能够帮助到你。

参考资料

[1] docs.sentry.io/platforms/j…

[2] develop.sentry.dev/architectur…

[3] getsentry.github.io/relay/relay…

[4] blog.sentry.io/2019/05/16/…

[5] docs.celeryq.dev/en/stable/

[6] zhuanlan.zhihu.com/p/62526102

[7] fe-blog.workplus.io/sentry-gett…

[8] zhuanlan.zhihu.com/p/75577689