随着现代应用程序设计的发展,系统变得越来越多样化,具有比以往更多的组件。开发人员经常被迫成为厨师,添加来自几十种不同技术的原料,并将它们混合在一起,创造出美味而令人惊叹的东西。但是有这么多不同的成分,通常很难理解各个成分之间是如何相互作用的。应用程序越多样化,一些看似无关紧要的技术组合就越有可能引起级联效应。
与我交谈过的许多人都有数百个(如果不是数千个的话)不同的库、api、组件和服务来组成他们支持的系统。在这种环境下,很难知道一件小事能累积成一件大得多的事情。看看最近的一些大型云或应用程序中断在美国,这些问题的根源通常都在一些相当小的事情上。
街战:Python 3.10 vs 3.9.7
让我给你们举一个我最近遇到的例子。我注意到,在运行相同硬件/应用程序代码的两个不同节点上,性能之间的差异非常大。应用服务器在一台服务器上的CPU运行接近100%,而另一台服务器的CPU运行在40%左右。每个都有相同的工作负载和相同的数据库,等等。结果发现,一台服务器使用的是Python 3.10.0,另一台运行的是3.9.7。这与MySQL连接器/ Python导致数据库吞吐量减少了近50%(3.10.0版本出现了倒退)。然而,在我的PostgreSQL测试和测试mysqlclient连接器。只有在运行纯python版本的MySQL连接器时才会发生这种情况。结果如下:
注意:该工作负载使用加热BP,在测试前工作负载运行超过24小时。我循环应用服务器,将其更改为python或MySQL库的版本。无论运行的长度如何,这些测试都是可重复的。所有数据都在这里的内存中。我并不是试图对特定的技术做出权威的声明,只是指出技术层的复杂性。
纯粹从用户的角度来看,这个特定的基准测试模拟了某些类型的用户。让我们看看每秒能够完成操作的用户数量。我还将添加另一个纯python MySQL驱动程序。
注意:在3.10中出现了显著的回归。在使用Python 3.10和一个纯Python驱动程序时,应用服务器比在3.9或更早版本中运行相同的测试时要忙得多。
MySQL连接器和mysqlclient之间的主要区别是mysqlclient使用的是C libmysqlclient。奇怪的是,官方的MySQL连接器说,如果可用的话,它应该在纯python和C版本之间切换,但我没有看到这种行为(所以我必须调查一下)。这导致Python 3.10.0的页面加载时间从Python 3.9.7的0.03秒增加到0.05秒。然而,我想强调的关键是,有时看起来很小或不重要的变化可能会导致性能和稳定性的巨大差异。您可以在几个月甚至几年的时间内运行良好,直到某个升级到您认为不会严重影响性能的某个升级。
通过更好的测试可以解决这个问题吗?
您可能认为这是在升级组件之前进行测试的典型,虽然这是一个要求,但它不一定能防止这种类型的问题。虽然技术组合、升级和发布通常会有一些奇怪的副作用,但它们引入的问题通常是隐藏的,直到一些外部影响出现才会显现出来。注意:这些通常发生在最糟糕的时候,比如重大的营销活动、活动等。我所看到的最常见的暴露严重bug的方式不是通过发布或测试,而是经常与工作负载的变化有关。工作负载更改可能会在最糟糕的时候隐藏或引发瓶颈。让我们来看看上面的Python版本和不同工作负载的不同连接器的组合:

在这里,报告和读/写工作负载的组合将所有应用程序节点和数据库节点推到红线。就性能而言,它们看起来非常相似,但工作负载隐藏了我提到的上述问题。一个被推到红色的系统将表现得不同于它在现实世界中的表现。如果你最终测试在你的应用服务器上升级python到3.10.0,把你的系统升级到最大,你可能会看到上面的小回归在可接受的范围内。然而,实际上,升级可以使您在转移到生产环境时看到吞吐量减少50%。
我们在乎吗?
根据应用程序的构建方式,许多人在升级后不会注意到上述性能下降。首先,大多数人甚至不会在接近100%负载的情况下运行服务器,在服务器上增加更多负载可能不会立即影响用户的性能。给用户增加0.02秒的加载时间可能是难以察觉的,除非在重载下(这会增加加载时间)。实际的影响是加快了您需要添加更多节点或更快地升级它们的实例的速度。
其次,在大多数现代云原生环境中,自动扩展应用程序节点几乎是必需的。当您需要添加更多节点和更强大的处理能力时,应用程序上的用户将会增加,因此很容易解释清楚。
假设用户不会立即注意到,系统会根据需要自动扩展(防止您知道或参与)。在这种情况下,我们是否应该关心添加更多的节点或服务器?添加节点很便宜;它不是免费的。
首先,你会有直接的成本。在上面的例子中,将应用服务器的托管成本增加一倍。那是什么?一年1万美元,10万美元,还是100万美元?那是浪费的钱。看看最近关于云计算成本不断增加的新闻就知道了:
- https://siliconangle.com/2021/11/28/cloud-computing-costs-high-can/
- https://www.datanami.com/2021/11/17/cloud-getting-expensive-thats-by-design-but-dont-blame-the-clouds/
- ,https://www.zdnet.com/article/how-to-get-cloud-storage-costs-under-control/)
其次,复杂性带来了更大的成本。可观测性是一个巨大的话题,因为我们在现代环境中所做的一切都是大规模的。您拥有的节点和服务器越多,就越有可能出现问题或某个节点行为不佳。虽然我们的目标是创建一个系统,其中所有东西都是可替换的,可以拆除和重建以克服问题,但这往往不是现实。相反,我们最终复制了糟糕的代码,潜在的瓶颈,并使单个问题成为100倍规模的问题。
我们需要关心。应用程序工作负载是一个随用户而增长、收缩和扩展的活实体。虽然现代系统需要快速扩展和缩小以满足需求,但这并不排除我们必须寻找隐藏的问题和瓶颈。了解应用程序工作负载并寻找正常模式中的偏差是非常重要的。我们需要问为什么事情会发生变化,并深入挖掘答案。仅仅因为我们可以建立自动化来缓解问题并不意味着我们应该自满和懒惰地修复和优化我们的系统。






嗨,马特,
当前版本的MySQL Connector Python(8.0.27)不支持Python 3.10(下一个版本将支持)。因此,在您的测试中,连接器没有使用C扩展,而是退回到纯Python(您可以看到它与pymysql的数字匹配)。这意味着在您的测试中,您是在比较纯Python和C,这当然没有多大意义。
这不是一个回归,因为在Python 3.10中,你没有使用C扩展。
我猜你用pip升级了Connector/Python,由于Python 3.10还不支持,所以安装了不包含任何C扩展的通用包。
你可以使用Python 3.9和3.10解释器运行以下命令,然后你会看到区别:
" import _mysql_connector "
你好Lefred !
是的,我提到它默认返回到纯python库。当3.10支持下一个版本时,我将重新讨论它。我试着坚持使用常用的方法,所以我确实使用了pip。我在这里的目标是强调一些小型开发者可能没有意识到却可能产生巨大影响的内容。在这种情况下,纯Python驱动程序和3.10确实有一些问题。希望当3.10正式支持时,一切都能正常运行。
马特
“这与MySQL连接器/Python相结合,导致数据库吞吐量减少了近50%(3.10.0版本出现了倒退)。然而,在我的PostgreSQL测试和mysqlclient连接器测试中都没有看到这种性能变化。只有在运行纯python版本的MySQL连接器时才会发生这种情况。”
在我的PostgreSQL测试中?
我猜你的意思是在我的MySQL测试中?