云中的科学漏洞:意外的首席执行官冒险

Wolfram云需要完美

Wolfram云很快就会出来测试了,现在我花了很多时间让它尽可能的好(顺便说一下,它变得非常棒!)我主要专注于定义高级功能和战略。但我喜欢了解每一个层面的事情,作为一名首席执行官,一个人要对一切负责。三月初,我发现自己深入了一些我从未预料到的事情……

这是故事。作为一种严肃的生产系统,许多人将使用像经营业务这样的事情,Wolfram云应该尽可能快。我们的指标说,典型的速度很好,但主观的时候,当我用它时感到错了。有时它很快很快,但有时它似乎太慢了。

我们有优秀的软件工程师,但几个月过去了,事情似乎没有改变。与此同时,我们刚刚发布了Wolfram数据下降.所以我想,为什么我为什么不跑一些测试,也许在我们的漂亮新的Wolfram数据下降中收集数据?

关于Wolfram语言是对忙碌的人多么友好:即使你只有时间匆匆离开几行代码在美国,你可以做真正的事情。在这种情况下,我只需要运行三行代码就可以找到问题。

首先,我部署web API为一个微不足道的Wolfram语言程序到Wolfram云:

在[1]:= CloudDeploy[apiffunction [{}, 1 &]]

然后我调用API 50次,测量每次调用花费的时间(这里表示之前的结果):

在[2]:=表[第一[AbsoluteTiming [URLExecute [%]]], {50}]

然后我绘制了这些调用的时间序列:

在[3]:= ListLinePlot (%)

马上就有一些疯狂的事情发生了。有时每个电话的时间是220毫安大约是这样,但通常是这样900毫秒,甚至是两倍那么长。最疯狂的是时间似乎被量化了!

我做了一个直方图:

在[4]:=直方图(% % 40)

果然,左边有一些快速的叫声,然后是第二个缓慢的叫声高峰,第三个“露头”的非常缓慢的叫声。这是奇怪的!

我想知道时间是否总是这样。我建立了一个周期计划任务每隔几分钟就进行一次API调用,并将它们的时间放在Wolfram Data Drop中。我把它放了一晚上……第二天早上我回来的时候,我看到了:

API调用图,显示奇怪的大规模结构

甚至令人烦恼!为什么大规模的结构?例如,我可以想象,群集中的特定节点可能逐渐减慢(不是那应该),但为什么它会慢慢恢复?

我的第一个想法是,也许我看到了网络问题,因为我正在1000多英里以外的测试云服务器上调用API。所以我看了ping时间。但除了几个奇怪的峰值(嘿,这是互联网!),时代非常稳定。

平次

服务器内部有问题

所以它一定是服务器本身的东西。在Wolfram云中有很多新技术,但大部分都是纯Wolfram语言代码,很容易测试。但是在Wolfram语言层下面还有通用的现代服务器基础设施。这在本质上是一样的Wolfram | Alpha.已成功地用于六年为数十亿的结果服务,还有什么网络Mathematica早在十年前就开始使用了。但作为一个要求更高的计算系统,Wolfram Cloud的设置略有不同。

我的第一个怀疑是,这种不同的设置可能会导致服务器层内部出现问题。最终,我希望我们将拥有完全的Wolfram语言基础设施,但目前我们使用的是一个基于Java的名为Tomcat的web服务器系统。起初,我认为可能是Java垃圾收集导致了速度变慢。分析表明,确实有一些由Tomcat触发的“停止世界”垃圾收集事件,但它们很少见,而且只花了几毫秒的时间,而不是几百毫秒。所以他们不是解释。

但到目前为止,我被迷住了解问题是什么。我在系统调试的战壕中没有这么深,很长一段时间。它感觉很像是做实验科学。与实验科学一样,简化了一个人的学习始终是重要的。因此,我通过操作“云到云”来缩小大部分网络:从同一群集中调用API。然后我剪掉了负载均衡器,将请求调度到群集中的特定节点,通过将我的请求锁定到单个节点(顺便说一下,除非他们有一个私人云).但经济放缓仍在继续。

然后我开始收集更详细的数据。我的第一步是让API返回它开始和完成执行Wolfram语言代码时的绝对时间,并将这些时间与调用API的包装器代码中的绝对时间进行比较。以下是我所看到的:

蓝线显示Wolfram语言代码运行之前的API呼叫时间;金线,之后。

蓝线显示运行Wolfram语言代码之前的时间;金线之后。我收集这些数据的时候,整个系统的表现都很糟糕。我所看到的是在“之前”时间里有很多戏剧性的减速,而在“之后”时间里只有一些量化的减速。

再一次,这很奇怪。经济放缓似乎与“之前”或“之后”并没有特别关联。相反,它看起来更像是什么东西随机撞击系统从外面。

一个令人困惑的特性是,集群的每个节点包含(在本例中)8个核,每个核运行一个不同的实例Wolfram引擎.Wolfram Engine很好也很稳定,所以这些实例在重新启动之间都要运行数小时到数天。但我想知道,在这一过程中,是否会出现一些问题。我对API进行了测试进程id过程时间,然后,例如,绘制了总的处理时间与组件的API调用时间:

总体处理时间与组件的API调用时间绘制

确实,“年轻”的进程运行API调用速度更快,但是(特别注意在x效果并不显著。

是什么在吞噬CPU?

我开始怀疑在同一台机器上运行的其他Wolfram云服务。这些会导致我们所看到的那种量子化的减速似乎没有意义,但为了简化系统,我想去掉它们。首先,我们隔离了生产集群上的一个节点。然后我就有了自己的Wolfram私有云设置。经济放缓依然存在。然而,令人困惑的是,在不同的时间和不同的机器上,它们的特征似乎有些不同。

在私有云上,我可以登录原始的Linux系统并开始查看。我做的第一件事就是读取结果从“top”和“ps axl”Unix实用程序到Wolfram语言,以便我可以分析它们。有一件事是显而易见的,那就是大量的“系统”时间被占用了:Linux内核一直忙于某些事情。事实上,这种减速似乎根本不是来自用户代码;它们可能来自于操作系统的内核。

这让我想追踪系统调用。我已经有将近25年没有做过类似的事情了,我过去的经验是,一个人可以得到很多数据,但却很难解释。现在,我有了Wolfram语言。

运行Linux“strace”实用程序,同时执行几秒钟的API调用,给出了28,221,878行的输出。但是,只有几行Wolfram语言代码来编织在一起的特定系统调用的开始和结束时间,并开始生成系统调用持续时间的直方图。只为几个系统调用这样做给了我这个:

系统调用持续时间 - 注意群集......

有趣的是,这表明了离散峰的证据。当我观察这些峰值中的系统调用时,它们似乎都是“futex”调用——Linux线程同步系统的一部分。然后我只挑出了futex的电话,果然,看到了尖锐的时间峰值——在250毫秒、500毫秒和1秒:

系统调用的持续时间只是浮选呼叫 - 显示剧烈的时序峰值

但这真的是个问题吗?Futex的呼叫本质上只是“休眠”;它们不会消耗处理器时间。实际上,看到这样的调用是很正常的,它们在等待I/O完成等等。对我来说,最有趣的观察是没有其他的系统调用花费了几百毫秒。

操作系统冻结了!

那么,到底发生了什么?我开始查看每个节点的不同核心上发生了什么。现在,Tomcat和我们基础设施堆栈的其他部分都是很好的多线程的。然而,无论什么原因导致了速度放缓,似乎都在冻结所有的内核,即使它们运行的是不同的线程。而唯一能做到这一点的就是操作系统内核。

但是什么会让Linux内核冻结成那样呢?我想知道日程安排的事。我真不明白为什么我们的情况会让调度员发疯。但我们还是看了调度器,试着改变一些设置。没有效果。

然后我有一个更奇怪的想法。我正在使用的Wolfram Cloud的实例在虚拟机中运行。如果放缓来自“矩阵之外”是什么?我要求在裸机上运行的Wolfram云版本,没有VM。但在配置之前,我发现了一种效用,以测量VM本身拍摄的“窃取时间” - 它可以忽略不计。

到目前为止,我已经连续几天每天花一两个小时在这上面了。是时候离开去一个紧张的旅行了SXSW..尽管如此,我们云软件工程团队的人还是被调动起来了,我把问题交给了他们能干的人处理。

当我的航班到达时,已经有另一个有趣的数据。我们将每个API呼叫分为15个子步骤。然后,我们的一个物理博士工程师将特定子步(左侧)放缓的概率与在该子步骤中所花费的中位数(右侧)进行了比较:

左边的条形图显示了特定子步骤出现减速的概率;右边的条形图显示了每个子步骤花费的时间中值

除了一个例外(有一个已知的原因),它们之间有很好的相关性。看起来好像Linux内核(以及在内核下运行的所有东西)在完全随机的时间里被某个东西击中,如果它碰巧与某个API调用的某些部分同时运行,就会导致“减速事件”。

所以我们开始寻找可能的原因。注意到的下一个可疑的事情是大量的I/O活动。在我们测试的配置中,Wolfram Cloud使用NFS网络文件系统来访问文件。我们尝试调优NFS、更改参数、切换到异步模式、使用UDP而不是TCP、更改NFS服务器I/O调度器等。没有什么不同。我们尝试使用一个完全不同的分布式文件系统Ceph。同样的问题。然后我们尝试使用本地磁盘存储。最后,这似乎产生了效果——消除了大部分(但不是全部)放缓。

我们将此作为一个线索,并开始调查更多关于I / O.一个实验涉及在节点上编辑一个巨大的笔记本,同时运行大量API调用到同一节点:

花费在编辑一个大型笔记本上的系统时间、用户时间和API时间的图表——当笔记本被编辑并持续保存时,它的速度有了很大的提升
结果很有趣。在笔记本被编辑(并持续保存)期间,API时间突然从大约100毫秒跃升到500毫秒。但是,为什么简单的文件操作会对节点的所有8个核心产生这样的影响呢?

罪犯找到了

我们开始进行更多的调查,很快就发现看似“简单的文件操作”并非如此——我们很快就找到了原因。您看,也许在5年前,在开发Wolfram云的早期,我们想试验文件版本控制。为了证明这个概念,有人插入了一个简单的版本控制系统,名为RCS。

世界上仍然有许多软件系统在使用RCS,尽管它在近30年里没有进行实质性的更新,而且现在已经有了更好的方法(比如我们在笔记本上使用的无限撤销)。但不知为何,RCS“概念验证”从未在我们的Wolfram云代码库中被取代——它仍然在每个文件上运行!

RCS的一个特征是,当一个文件被修改时,即使是一位微小的位,大量数据(甚至多次文件本身的大小)结束了写入磁盘。我们肯定一般期待多少I / O活动。但很明显,RCS是不必要地更加激烈的。

I/O活动真的会挂起整个Linux内核吗?也许有某种神秘的全局锁。磁盘子系统可能会冻结,因为它没有足够快地刷新已填满的缓冲区。也许内核正忙着重新映射页面,试图使更大的内存块可用。但不管发生了什么,最明显的事情就是尝试取出RCS,看看发生了什么。

所以我们这样做了,而且Lo和Phoold,可怕的放缓立即消失了!

所以,经过一周的紧张调试,我们找到了问题的解决方案。重复我最初的实验,现在一切都运行得很干净,API时间完全由向测试集群的网络传输控制:

清洁运行时间!将其与上面的In[3]图像进行比较。

Wolfram语言和云

我从这一切学到了什么?首先,它加强了我的印象,即云是我在软件中全部见过的最困难的敌对开发和调试环境。但其次,它让我意识到Wolfram语言是一种改性的重要性,用于分析,可视化和组织在像云等复杂基础设施内部发生的事情。

当谈到调试时,我自己已经被宠坏了多年——因为我基本上用Wolfram语言进行所有的编程,在Wolfram语言中调试特别容易,而且很少有错误需要花费我几分钟以上才能找到。为什么在Wolfram语言中调试如此容易?我认为,最重要的是,这是因为代码往往很短和可读性。人们通常也会把它写在笔记本上,这样就可以在编写程序的过程中对程序的每一部分进行测试和记录。同样重要的是,Wolfram语言是符号的,所以人们总是可以取出程序的任何部分,它将自己运行。

在软件堆栈的较低级别的调试是一种非常不同的体验。更像医学诊断在这种情况下,人们还需要处理一个复杂的多组分系统,并试图通过一些测量或实验来弄清楚发生了什么。(我猜我们的版本问题可能是类似于DNA复制中的某些可怕缺陷。)

我在云计算中的整个冒险经历也非常强调了我们通过Wolfram云计算所增加的价值。因为Wolfram Cloud的部分内容就是将人们从云基础设施的混乱问题中隔离出来,并让他们取而代之实施和部署任何他们想要的直接在Wolfram语言。

当然,为了实现这一点,我们自己需要构建所有自动化的基础设施。现在,多亏了这个“科学调试”的小冒险,我们离完成它又近了一步。事实上,到今天为止,Wolfram云的api一直在运行,没有任何神秘的量化的减速,而且它很快就会走出测试阶段,进入全面生产阶段。

4评论

  1. 很棒的工作!就在几天前,我正在使用Wolfram Cloud,我惊喜地发现它的运行速度似乎快了很多。

    Daniel Bigham.
  2. 简短的答案是在开发期间安装的RCS正在拧紧所有内容!这是有趣和经典的。

  3. 这是一个明确的迹象表明,Von Neumann架构如何以及Linux单片内核如何拧紧我们所有人。首先,文件版本控制应该是OS的内置功能。其次,正如TED NELSON所说,我们必须摆脱文件系统暴政。据说,Wolfram应该优先开发在裸机上运行的版本。此时,他们可以考虑完全开发MatheMatica合适的硬件架构。最后但并非最不重要的 - 整个多线程方案很糟糕。去功能编程,人!这是计算机上的数学,所以去吧。这更难,但这件事主要是聪明人。我们可以在稍后使用Mathematica的图像处理能力计算那些想要计算苹果派音量的人......

  4. 干得好,史蒂芬,继续,如果你需要梦想家,找我

Baidu