Wolfram云需要完美
的Wolfram云很快就会出来测试了,现在我花了很多时间让它尽可能的好(顺便说一下,它变得非常棒!)我主要专注于定义高级功能和战略。但我喜欢了解每一个层面的事情,作为一名首席执行官,一个人要对一切负责。三月初,我发现自己深入了一些我从未预料到的事情……
这是故事。作为一种严肃的生产系统,许多人将使用像经营业务这样的事情,Wolfram云应该尽可能快。我们的指标说,典型的速度很好,但主观的时候,当我用它时感到错了。有时它很快很快,但有时它似乎太慢了。
我们有优秀的软件工程师,但几个月过去了,事情似乎没有改变。与此同时,我们刚刚发布了Wolfram数据下降.所以我想,为什么我为什么不跑一些测试,也许在我们的漂亮新的Wolfram数据下降中收集数据?
关于Wolfram语言是对忙碌的人多么友好:即使你只有时间匆匆离开几行代码在美国,你可以做真正的事情。在这种情况下,我只需要运行三行代码就可以找到问题。
首先,我部署web API为一个微不足道的Wolfram语言程序到Wolfram云:
然后我调用API 50次,测量每次调用花费的时间(%这里表示之前的结果):
然后我绘制了这些调用的时间序列:
马上就有一些疯狂的事情发生了。有时每个电话的时间是220毫安大约是这样,但通常是这样900毫秒,甚至是两倍那么长。最疯狂的是时间似乎被量化了!
我做了一个直方图:
果然,左边有一些快速的叫声,然后是第二个缓慢的叫声高峰,第三个“露头”的非常缓慢的叫声。这是奇怪的!
我想知道时间是否总是这样。我建立了一个周期计划任务每隔几分钟就进行一次API调用,并将它们的时间放在Wolfram Data Drop中。我把它放了一晚上……第二天早上我回来的时候,我看到了:
甚至令人烦恼!为什么大规模的结构?例如,我可以想象,群集中的特定节点可能逐渐减慢(不是那应该),但为什么它会慢慢恢复?
我的第一个想法是,也许我看到了网络问题,因为我正在1000多英里以外的测试云服务器上调用API。所以我看了ping时间。但除了几个奇怪的峰值(嘿,这是互联网!),时代非常稳定。
服务器内部有问题
所以它一定是服务器本身的东西。在Wolfram云中有很多新技术,但大部分都是纯Wolfram语言代码,很容易测试。但是在Wolfram语言层下面还有通用的现代服务器基础设施。这在本质上是一样的Wolfram | Alpha.已成功地用于六年为数十亿的结果服务,还有什么网络Mathematica早在十年前就开始使用了。但作为一个要求更高的计算系统,Wolfram Cloud的设置略有不同。
我的第一个怀疑是,这种不同的设置可能会导致服务器层内部出现问题。最终,我希望我们将拥有完全的Wolfram语言基础设施,但目前我们使用的是一个基于Java的名为Tomcat的web服务器系统。起初,我认为可能是Java垃圾收集导致了速度变慢。分析表明,确实有一些由Tomcat触发的“停止世界”垃圾收集事件,但它们很少见,而且只花了几毫秒的时间,而不是几百毫秒。所以他们不是解释。
但到目前为止,我被迷住了解问题是什么。我在系统调试的战壕中没有这么深,很长一段时间。它感觉很像是做实验科学。与实验科学一样,简化了一个人的学习始终是重要的。因此,我通过操作“云到云”来缩小大部分网络:从同一群集中调用API。然后我剪掉了负载均衡器,将请求调度到群集中的特定节点,通过将我的请求锁定到单个节点(顺便说一下,除非他们有一个私人云).但经济放缓仍在继续。
然后我开始收集更详细的数据。我的第一步是让API返回它开始和完成执行Wolfram语言代码时的绝对时间,并将这些时间与调用API的包装器代码中的绝对时间进行比较。以下是我所看到的:
蓝线显示运行Wolfram语言代码之前的时间;金线之后。我收集这些数据的时候,整个系统的表现都很糟糕。我所看到的是在“之前”时间里有很多戏剧性的减速,而在“之后”时间里只有一些量化的减速。
再一次,这很奇怪。经济放缓似乎与“之前”或“之后”并没有特别关联。相反,它看起来更像是什么东西随机撞击系统从外面。
一个令人困惑的特性是,集群的每个节点包含(在本例中)8个核,每个核运行一个不同的实例Wolfram引擎.Wolfram Engine很好也很稳定,所以这些实例在重新启动之间都要运行数小时到数天。但我想知道,在这一过程中,是否会出现一些问题。我对API进行了测试进程id和过程时间,然后,例如,绘制了总的处理时间与组件的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时间突然从大约100毫秒跃升到500毫秒。但是,为什么简单的文件操作会对节点的所有8个核心产生这样的影响呢?
罪犯找到了
我们开始进行更多的调查,很快就发现看似“简单的文件操作”并非如此——我们很快就找到了原因。您看,也许在5年前,在开发Wolfram云的早期,我们想试验文件版本控制。为了证明这个概念,有人插入了一个简单的版本控制系统,名为RCS。
世界上仍然有许多软件系统在使用RCS,尽管它在近30年里没有进行实质性的更新,而且现在已经有了更好的方法(比如我们在笔记本上使用的无限撤销)。但不知为何,RCS“概念验证”从未在我们的Wolfram云代码库中被取代——它仍然在每个文件上运行!
RCS的一个特征是,当一个文件被修改时,即使是一位微小的位,大量数据(甚至多次文件本身的大小)结束了写入磁盘。我们肯定一般期待多少I / O活动。但很明显,RCS是不必要地更加激烈的。
I/O活动真的会挂起整个Linux内核吗?也许有某种神秘的全局锁。磁盘子系统可能会冻结,因为它没有足够快地刷新已填满的缓冲区。也许内核正忙着重新映射页面,试图使更大的内存块可用。但不管发生了什么,最明显的事情就是尝试取出RCS,看看发生了什么。
所以我们这样做了,而且Lo和Phoold,可怕的放缓立即消失了!
所以,经过一周的紧张调试,我们找到了问题的解决方案。重复我最初的实验,现在一切都运行得很干净,API时间完全由向测试集群的网络传输控制:
Wolfram语言和云
我从这一切学到了什么?首先,它加强了我的印象,即云是我在软件中全部见过的最困难的敌对开发和调试环境。但其次,它让我意识到Wolfram语言是一种改性的重要性,用于分析,可视化和组织在像云等复杂基础设施内部发生的事情。
当谈到调试时,我自己已经被宠坏了多年——因为我基本上用Wolfram语言进行所有的编程,在Wolfram语言中调试特别容易,而且很少有错误需要花费我几分钟以上才能找到。为什么在Wolfram语言中调试如此容易?我认为,最重要的是,这是因为代码往往很短和可读性。人们通常也会把它写在笔记本上,这样就可以在编写程序的过程中对程序的每一部分进行测试和记录。同样重要的是,Wolfram语言是符号的,所以人们总是可以取出程序的任何部分,它将自己运行。
在软件堆栈的较低级别的调试是一种非常不同的体验。更像医学诊断在这种情况下,人们还需要处理一个复杂的多组分系统,并试图通过一些测量或实验来弄清楚发生了什么。(我猜我们的版本问题可能是类似于DNA复制中的某些可怕缺陷。)
我在云计算中的整个冒险经历也非常强调了我们通过Wolfram云计算所增加的价值。因为Wolfram Cloud的部分内容就是将人们从云基础设施的混乱问题中隔离出来,并让他们取而代之实施和部署任何他们想要的直接在Wolfram语言。
当然,为了实现这一点,我们自己需要构建所有自动化的基础设施。现在,多亏了这个“科学调试”的小冒险,我们离完成它又近了一步。事实上,到今天为止,Wolfram云的api一直在运行,没有任何神秘的量化的减速,而且它很快就会走出测试阶段,进入全面生产阶段。