为什么这条异常没有上报? HTTP 429
这是一个在优化前端异常上报时出现的问题
❝山月人肉盯着异常报了半个小时,但是在 Sentry 中仍然没有收到一条报错,郁闷不已,反复踌躇徘徊。喝一杯水后顿悟,然后发现了那条 http 状态码为 429 的异常上报请求。❞
捉虫
刚开始碰到 Sentry 中未收到报错 (Event) 时,一直在尝试去找 Sentry 服务器端的 Inbound Filter
设置以及 Sentry 客户端的 beforeSend
设置,这两个均与 Event
的过滤有关。以致于耽搁了半个小时。
「日志是排查问题时最重要的线索!!!」
后来回过神来,在控制台网络中找到了 http 429 的这条请求,而 429 的描述语为 Too Many Requests
。出现了 429,往往代表着 API 被限流了。
原因
在 Sentry 上对于异常上报设置了 Rate Limit
,每小时最多只能上报 1000 个 Event,导致许多异常被丢弃。
Rate Limit By Org
Rate Limit By Project
「图中红色的部分是丢弃的 Event,可以看出丢弃的比捕捉到的更要多!」
解决
基于以往上报及丢弃的 Event 数量,往大调整 Rate Limit
Rate Limit By Org
总结
- 还好这次问题暴露在前端的 Sentry 上报,可以很方便地通过
devtools -> network
来查询日志,如果本次是后端上报异常的话,就会较难调试,可能得用上一天时间 - 「对 Sentry 此类异常上报系统,作为业务层重要的基础设施,还是要多一分熟悉,平时才能更好地定位 Bug」
反思
关于异常监控系统,很多开发同学往往只注重如何去上报,但这远远不够!因为只注重如何去上报只是异常上报链路中的一个生产侧,不谋全局者不足谋一域。此时开发更应该在更高的角度去思考:
- 每个异常有没有都上报上去,会不会被限流或其他原因(如磁盘满了)被丢弃掉
- 每个异常上报上去后,如何去设计 Alert 规则:邮箱还是钉钉?警告要触发吗?
拓展
这里拓展一些关于异常上报的注意点,关于 Sentry 异常上报信息有三大关键字段及两大核心概念
三大关键字段指:
-
Tags
,也可以认为是Index
,作为索引,方便查询。如 userId,errorCode 前端还会涉及到浏览器及一些业务相关要素。 -
Stack
,异常堆栈,方便在异常系统直接定位代码 -
Context
,相关上下文信息,如发请求的url
及body
,执行数据库查询的sql
等
两大核心概念:
-
Event
,报一次错就是一个Event
-
Issue
,如一个 Bug 导致了 N 次 Event,则会聚合为一个Issue
,关于聚合算法,会根据fingerprint
来辨别
如果以上这些做好了,无论采用 ElaticSearch
还是 Sentry
做异常上报都是无关紧要的。
❝好吧,其实还是有很大不一样的,比如 Sentry 作为专一的异常上报系统,则会有更好的 Alert,而 ES 做 Alert 就很难了。且 Sentry 对 User Feedback,Event Group,Bug workflow 及与 jira,gitlab 的集成更好。 ❞
关于 Node
服务端的异常上报可以参考我以前的文章:
- Node 异常结构化与上报[1]
Reference
[1]Node 异常结构化与上报: https://shanyue.tech/node/error.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- C++类型转换几种情况
- 疯子的算法总结(九) 图论中的矩阵应用 Part 1 POJ3613 Cow Relays
- 『数据库』你这些知识点都不会,你学个锤子SQL数据库!
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 XKC's basketball team
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 D Carneginon
- 地表最强的MySQL安装一键式安装,信不信你下完我就给你装好!附各种Mysql安装失败的解决办法(什么你安装失败了?快来看这个)
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 C Buy Watermelon
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 B so easy
- 萌新不看会后悔的C++基本类型总结(二)
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 A Who is better?
- 树的重心
- PostgreSQL 13:索引并行vacuum
- 『数据库』震惊,某博主为吸引眼球拿出压箱底SQL总结,如果你没看那就吃亏了!(超级详细的SQL基础,你还不会的话就别学数据库了)
- 萌新不看会后悔的C++基本类型总结(一)
- 2019 ICPC 银川网络赛 D. Take Your Seat (疯子坐飞机问题)