<转> 从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例

注: 转自 微信公众号“高可用架构”:从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例

导读:Python 被很多互联网系统广泛使用,但在另外一方面,它也存在一些性能问题,不过 Sentry 工程师分享的在关键模块上用另外一门语言 Rust 来代替 Python 的情况还是比较罕见,也在 Python 圈引发了热议,高可用架构小编将文章翻译转载如下。
《<转> 从20秒到0.5秒:一个使用Rust语言来优化Python性能的案例》” /></span></p>
<p>Sentry 是一个帮助在线业务进行监控及错误分析的云服务,它每月处理超过十亿次错误。我们已经能够扩展我们的大多数系统,但在过去几个月,Python 写的 source map 处理程序已经成为我们性能瓶颈所在。(译者:source map 就是将压缩或者混淆过的代码与原始代码的对应表)</p>
<p>从上周开始,基础设施团队决定调查 source map 处理程序的性能瓶颈。——我们的 Javascript 客户端已经成为我们最受欢迎的程序,其中一个原因是我们通过 source map 反混淆 JavaScript 的能力。然而,处理操作不是没有代价的。我们必须获取,解压缩,反混淆然后反向扩张,使 JavaScript 堆栈跟踪可读。</p>
<p>当我们在 4 年前编写了原始处理流水线时,source map 生态系统才刚刚开始演化。随着它成长为一个复杂而成熟的 source map 处理程序,我们花了很多时间用 Python 来处理问题。</p>
<p><strong>截至昨天,我们通过 Rust 模块替换我们老的 Python 的 souce map 处理模块,大大减少了处理时间和我们的机器上的 CPU 利用率。</strong></p>
<p>为了解释这一切,我们需要先理解 source map 和用 Python 的缺点。</p>
<h2>Python 的 Source Maps</h2>
<p>随着我们的用户的应用程序变得越来越复杂,他们的 source map 也越来越复杂。在 Python 中解析 JSON 本身是足够快的,因为它们只是字符串而已。<strong>问题在于反序列化</strong>。每个 source map token 产生一个 Python 对象,我们有一些 source map 可能有几百万个 token。</p>
<p>将 source map token 反序列化的问题使得我们为基本 Python 对象支付巨大的成本。另外,所有这些对象都参与引用计数和垃圾收集,这进一步增加了开销。<strong>处理 30MB source map 使得单个 Python 进程在内存中扩展到〜 800MB,执行数百万次内存分配,并使垃圾收集器非常忙碌</strong>(译者注:token 是短生命周期对象,有新生代就好多了,这时候就体现出我大 Java 的优势了)。</p>
<p>由于这种反序列化需要对象头和垃圾回收机制,我们能在 Python 层做改进的空间非常小。</p>
<h2>Rust 的 Source Maps</h2>
<p>在调查发现问题在于 Python 的性能缺陷后,我们决定尝试 Rust source map 解析器的性能,这是为我们的 CLI 工具编写的。在将 Rust 解析器应用于问题很大的 source map 之后,其表明单独使用该库进行解析可以将<strong>处理时间从 > 20 秒减少到 < 0.5 秒</strong>。这意味着即使忽略任何优化,只是将 Python 解析器替换为 Rust 解析器就可以缓解我们的性能瓶颈。</p>
<p>我们证明 Rust 确实更快后,就清理了一些 Sentry 内部 API,以便我们可以用新的库替换原来的实现。这个 Python 库命名为 libsourcemap,是我们自己的 Rust source map 的一个薄包装。</p>
<h2>优化结果</h2>
<p>部署该库后,专门用于 source map 处理的机器压力大大降低。</p>
<p><span><img layer-src=http://www.ruanyifeng.com/blo…

    原文作者:刘阳龙Herman
    原文地址: https://segmentfault.com/a/1190000007299177
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞