性能文章>一次 Kafka 导致的 Sentry 无法处理 MiniDump 问题分析>

一次 Kafka 导致的 Sentry 无法处理 MiniDump 问题分析原创

480715

业务反馈部署的 Sentry 系统处理 Electron 的 MiniDump 信息出现异常,界面提示。

于是做了一次分析,记录如下。

Sentry 是什么

Sentry 是一个跨平台的应用错误跟踪系统,专注于错误报告,支持 web 前后端、移动应用以及游戏,此次反馈问题的是 Windows PC 端 Electron 客户端。官网:https://sentry.io/

做过客户端的通信可能对 MiniDump 比较清楚,拿 Windows 为例,每次 Windows 操作系统意外遇到错误时(例如在“蓝屏死机”崩溃期间)都会生成一个小文件。该文件包含有关错误性质的信息,例如崩溃之前和崩溃期间的系统状态。其中包含诸如运行服务和流程之类的信息,以及每个服务所使用的资源。除了系统,应用 crash 也是可以生成 MiniDump 文件的,本例中就是一个 Electron 的客户端程序生成的 MiniDump。

初步分析

遇事不决先抓包,因为是 HTTPS 的请求包,所以这里需要特殊处理。


SSLKEYLOGFILE=/Users/arthur/keylog.txt
curl -X POST \
  'https://o0.ingest.sentry.io/api/0/minidump/?sentry_key=examplePublicKey' \
  -F upload_file_minidump=@mini.dmp

发现请求是没有什么问题的,HTTP 放回了正确的结果和对应的 EventId

出问题的同学反馈,当上传的 MiniDump 文件是小文件时,比如 300k 没有任何问题。当上传一个 1M 多的文件时,就会出现 Invalid Minidump 异常,怀疑是 sentry 后端处理文件上传的时候有一些问题。

但是这个系统完全不熟,只能硬分析,找到它对应的 Nginx 看下请求跑到了哪里。通过 nginx -T 查看当前的 Nginx 配置文件

server {
  listen 8080;

  proxy_redirect off;
  proxy_set_header Host $host;

  location /api/store/ {
    proxy_pass http://relay;
  }

  location ~ ^/api/[1-9]\d*/ {
    proxy_pass http://relay;
  }

  location / {
    proxy_pass http://sentry;
  }
}

可以看到请求去到了 relay 这个 upstream 上游服务中,这个服务是一个用 rust 写的服务,先搜索了一下处理文件上传部分的逻辑。

发现大小受限于 max_attachment_size 参数。

max_attachment_size 这个参数的默认值是 50MB

讲道理,我们没有修改默认值应该不会触发文件上传这里的校验错误,出问题的应该是在后续的逻辑里,也就是文件上传完以后,继续处理的部分发送数据到 kafka 交给后面的服务继续处理。

艰难的找到了 relay 打印的日志

可以看到 rust 打印提示发送到 kafka 的消息过大,对应的代码如下。

在 relay 服务 tcpdump 抓包同步确认,因为不止我一个人在使用,但是如何找到对应的包呢?

这里有一个小技巧,wireshark 里可以过滤包体里的内容,因为我发现 Minidump 文件的文件头有一个魔数 "MDMP"

于是就可以过滤了,在 wireshark 中输入 frame contains "MDMP",就可以找到对应的kafka 发送那一条的记录。

然后使用 follow tcp stream 就可以看到这个包发送的全过程。

这里有非常多的包,如何快速定位到 kafka 可能发生错误的包呢,wireshark 足够智能可以分析 Kakfa 的包,这里有一个骚操作,kafka 的头部里都有两字节表示的 error 字段,如果无异常,这个值就等于 0

这里我们想看非 0 的,就可以这样来过滤了。

tcp.stream eq 2 and kafka.error != 0

这下就可以真的确认,我们的那个 MiniDump 的包,确实在发送到 kafka 的时候发生了错误。

后面的 MiniDump 解析的服务(一个 python 的服务)解析文件发现文件不完整,就解析失败了。

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/sentry/tasks/store.py"
  line 255in _do_symbolicate_event
    symbolicated_data = symbolication_function(data)
  File "/usr/local/lib/python3.6/site-packages/sentry/lang/native/processing.py"
  line 259in process_minidump
    response = symbolicator.process_minidump(minidump.data)
  File "/usr/local/lib/python3.6/site-packages/sentry/attachments/base.py"
  line 61in data
    self._data = self._cache.get_data(self)
  File "/usr/local/lib/python3.6/site-packages/sentry/attachments/base.py"
  line 160in get_data
    raise MissingAttachmentChunks()
sentry.attachments.base.MissingAttachmentChunks

通过跟运维的同学确认,kafka 集群是自己新建的,消息体的大小使用的是 kakfa 的默认值 1M(message.max.bytes),于是动态调整这个值到 50M,然后再次测试,已经成功。

至此问题解决。

后记

这个项目啥语言都有,rust、python 等等,开源大杂烩。好了我滚回去学 rust 了。

 

请先登录,再评论

看的通畅!👍

11周前

为你推荐

大数据中台之Kafka,到底好在哪里?
Hello,大家好,今天给大家分享一个大数据里面很火的技术——Kafka,Kafka 是一个分布式的消息系统,其高性能在圈内很出名。本人阅读过多个大数据生态的开源技术的源码,个人感觉 Kafka 的源
跟Kafka学技术系列之时间轮
kafka的延迟队列使用时间轮实现,能够支持大量任务的高效触发,但是在kafka延迟队列实现方案里还是看到了delayQueue的影子,使用delayQueue是对时间轮里面的bucket放入延迟队列,以此来推动时间轮滚动,但是基于将插入和删除操作则放入时间轮中,将这些操作的时间复杂度都降为O(1)
什么?搞不定Kafka重复消费?
今天我们聊一个话题,如何保证 Kafka 消息不重复消费?在使用 Kafka 的时候一般都会设置重试的次数,但是因为网络的一些原因,设置了重试就有可能导致有些消息重复发送了(当然导致消息重复也有可能是其他原因),那么怎么解决消息重复这个问题呢?
Kafka的生产者优秀架构设计
前言 Kafka 是一个高吞吐量的分布式的发布订阅消息系统,在全世界都很流行,在大数据项目里面使用尤其频繁。笔者看过多个大数据开源产品的源码,感觉 Kafka 的源码是其中质量比较上乘的一个,这得益于
Kafka 顺序消费线程模型的实践与优化
各类消息中间件对顺序消息实现的做法是将具有顺序性的一类消息发往相同的主题分区中,只需要将这类消息设置相同的 Key 即可,而 Kafka 会在任意时刻保证一个消费组同时只能有一个消费者监听消费,因此可
kill -9 导致 Kakfa 重启失败的惨痛经历!
背景在 2 月10 号下午大概 1 点半左右,收到用户方反馈,发现日志 kafka 集群 A 主题 的 34 分区选举不了 leader,导致某些消息发送到该分区时,会报如下 no leader 的错
《吃透 MQ 系列》之 Kafka 存储选型的奥秘
谈到 Kafka 的存储设计,了解不多的同学,可能会有这样的疑惑:为什么 Kafka 会采用 Logging(日志文件)这种很原始的方式来存储消息,而没考虑用数据库或者 KV 来做存储?
《吃透 MQ 系列》之核心基础篇
上一篇文章谈到了《吃透系列》的讲解思路:先找到每个技术栈最本质的东西,然后以此为出发点,逐渐延伸出其他核心知识。所以,整个系列侧重于思考力的训练,不仅仅是讲清楚 What,而是更关注 Why 和 How,以帮助大家构建出牢固的知识体系。回到正文,这是技术系列《吃透 MQ》的开篇。