当前位置

sohulinux

ZZ: Bleeding Edge版V8引擎的内存使用评测

老韩说:未经许可,严禁转载... 哈哈,所以我只转载一个链接: 秀码趣:Bleeding Edge版V8引擎的内存使用评测

这篇文章背后是我们暑期实习生训练营的成果,非常高兴看到他们的成长!

以后俺们如果开始发布 sohu developer blog 的话,除了 linux@SOHU 之外,看来可以增加一个 NodeJS 的专栏.. :)

确保数据存入磁盘

翻译:靳彬
原文:Ensuring data reaches disk
September 7, 2011
This article was contributed by Jeff Moyer

在理想的情况下,系统崩溃、断电、磁盘访问失败这些情况是不会出现的,开发者编写程序时也不用为这些情况担忧。不幸的是,这些情况比我们想像的还经常出现。本文描述了数据是怎样一步步被写入磁盘上的,尤其是其中被缓冲的几个步骤。本文也提供了数据被正确写盘的最佳实践,以确保意外发生的时候,数据不会丢失。主要是面向 C 语言的,其中的系统调用也有其它语言的实现。

I/O缓存
考虑到开发系统时数据的完整性,有必要理解系统的整体架构。在数据最终存入稳定存储器前,可能会经过多个层,如下图所示:

处于顶层的是需要将数据写入永久存储的应用程序。数据最初存在于应用程序的内存或缓存中的一个或多个块中。这些缓存中的数据可能被提交给一个具有自己缓存的库。抛开应用程序缓存与库缓存,这些数据都存在于应用程序地址空间中。数据经过的下一层是内核,内核有一个叫做页缓存的回写缓存。脏页会存放在页缓存中一段时间,这段时间的长短取决于系统的负载与I/O模式。最后,当脏数据离开内核的页缓存时,会被写入存储设备(如磁盘)。存储设备可能会进一步将数据缓存在临时的回写缓存中。如果这时发生了断电的情况,数据可能会丢失。最后一层是稳定存储。当数据到达这层时,就可以认为数据安全存入稳定存储器了。

为进一步说明分层的缓存,来看一个在 socket 上监听连接的程序,它把从各个客户机收到的数据写入一个文件的应用程序。在关闭连接前,服务器要确保数据写入稳定存储设备中,并向客户机发送确认信息。

  1.  0 int
  2.  1 sock_read(int sockfd, FILE *outfp, size_t nrbytes)
  3.  2 {
  4.  3      int ret;
  5.  4      size_t written = 0;
  6.  5      char *buf = malloc(MY_BUF_SIZE);
  7.  6
  8.  7      if (!buf)
  9.  8              return -1;
  10.  9
  11. 10      while (written < nrbytes) {
  12. 11              ret = read(sockfd, buf, MY_BUF_SIZE);
  13. 12              if (ret =< 0) {
  14. 13                      if (errno == EINTR)
  15. 14                              continue;
  16. 15                      return ret;
  17. 16              }
  18. 17              written += ret;
  19. 18              ret = fwrite((void *)buf, ret, 1, outfp);
  20. 19              if (ret != 1)
  21. 20                      return ferror(outfp);
  22. 21      }
  23. 22
  24. 23      ret = fflush(outfp);
  25. 24      if (ret != 0)
  26. 25              return -1;
  27. 26
  28. 27      ret = fsync(fileno(outfp));
  29. 28      if (ret < 0)
  30. 29              return -1;
  31. 30      return 0;
  32. 31 }

第5行是一个应用程序缓存的例子;从socket中读取的数据被存入这个缓存中。现在,要传输的数据量已经知道,由于网络传输的特性(可能会是突发的或缓慢的),我们决定使用libc的流函数(fwrite() and fflush(),由上图中的"Library Buffers"表示)进一步缓存数据。10到21行负责从socket中读取数据,并写入文件流。在22行时,所有的数据都已经被写入文件流了。在23行,文件流进行刷新,并把数据送入内核缓存。然后,在27行,数据被存入稳定存储设备。

I/O APIs

既然我们已经深入了解了API与层次模型的关系,现在让我们更详细的探寻接口的复杂性。对于本次讨论,我们将I/O分为3个部分:系统I/O,流I/O,内存映射I/O。

系统I/O可以被定义为任何通过内核系统调用将数据定入内核地址空间中的存储层的操作。下面的程序(不全面的,重点在写操作)是系统调用的一部分:

Operation Function(s)
Open open(), creat()
Write write(), aio_write(),
pwrite(), pwritev()
Sync fsync(), sync()
Close close()

流I/O是用C语言库的流接口进行初始化的I/O。使用这些函数进行写的操作并不一定产生系统调用,即在一次这样的函数调用后,数据仍然存在于应用程序地址空间中的缓存中。下面的库程序(不全面)是流接口的一部分:

Operation Function(s)
Open fopen(), fdopen(),
freopen()
Write fwrite(), fputc(),
fputs(), putc(), putchar(),
puts()
Sync fflush(), followed by
fsync() or sync()
Close fclose()

内存映射文件与系统I/O类似。文件仍然使用相同的接口打开与关闭,但对文件数据的访问,是通过将数据映射入进程的地址空间进行的,然后像读写其它应用程序缓存一样进行读写操作:

Operation Function(s)
Open open(), creat()
Map mmap()
Write memcpy(), memmove(),
read(), or any other routine that
writes to application memory
Sync msync()
Unmap munmap()
Close close()

打开一个文件时,有两个标志可以指定,用以改变缓存行为:O_SYNC( 或相关的O_DSYNC)与O_DIRECT。对以O_DIRECT方式打开的文件的I/O操作,会绕开内核的页缓存,直接写入存储器。回想下,存储系统仍然可能将数据存入一个写回缓存中,因此,对于以O_DIRECT打开的文件,需要调用fsync()确保将数据存入稳定存储器中。O_DIRECT标志仅与系统I/O API相关。

原始设备(/dev/raw/rawN)是O_DIRECT I/O的一种特殊情况。这些设备在打开时不需要显式指定O_DIRECT标志,但仍然提供直接I/O语义。因此,适用于原始设备的规则,同样也适用于以O_DIRECT方式打开的文件(或设备)。

同步I/O(O_DIRECT或非O_DIRECT方式的系统I/O,或流I/O)是任何对以O_SYNC 或O_DSYNC方式打开的文件描述符的I/O.以下是POSIX定义的同步模式:

  • O_SYNC: 文件数据与所有元数据同步写入磁盘。
  • O_DSYNC: 仅需要访问文件数据的文件数据与元数据同步写入磁盘。
  • O_RSYNC: 未实现。

用以对文件描述符进行写调用的数据与相关的元数据,在数据进入稳定存储时,生命周期结束。注意,那些不是用于检索文件数据的元数据,可能不会被立即写入。这些元数据包括文件的访问时间,创建时间,和修改时间。

值得指出的是,以O_SYNC 或 O_DSYNC方式打开文件描述符,并将其与一个libc文件流联系在一起的微妙之处。记住,对文件指针的fwrite()操作会被C语言库缓存。直到fflush()被调用,系统才会知道数据要写入磁盘。本质上来说,将文件流与一个同步的文件描述符关联在一起,意味着在fflush()操作后,不需要对文件描述符调用fsync()。

什么时候执行fsync操作?

可以根据一些简单的规则,决定是否调用fsync()。首先,也是最重要的,你必须明白:有没有必要将数据立即存入稳定存储中?如果是不重要的数据,那么不必立即调用fsync(). 如果是可再生的数据,也没有太大的必要立即调用fsync()。另一方面,如果你要存储一个事务的结果,或更新用户的配置文件,你很希望得到正确的结果。在这些情况下,应该立即调用fsync()。

更微妙之处在于新创建的文件,或重写已经存在的文件。新创建的文件不仅仅需要fsync(),其父目录也需要fsync()(因为这是文件系统定位你的文件之处)。这类同步行为依赖于文件系统(和挂载选项)的实现。你可以对专门为每一个文件系统与挂载选项进行特殊编码,或者显示调用fsync(),以确保代码的可移植性。

类似的,当你覆盖一个文件时,如果遭遇系统失败(例如断电,ENOSPC或I/O错误),很可能会造成已有数据的丢失。为避免这种情况,通常的做法(也是建议的做法)是将要更新的数据写入一个临时文件,确保它在稳定存储上的安全,然后将临时文件重命名为原始的文件名(以代替原始的内容)。这确保了对文件更新操作的原子性,以使其它读取用户得到数据一个副本。以下是这种更新类型的操作步骤:

  1. create a new temp file (on the same file system!)
  2. write data to the temp file
  3. fsync() the temp file
  4. rename the temp file to the appropriate name
  5. fsync() the containing directory

错误检查

进行由库或内核缓存的写I/O时,由于数据可能仅仅被写入页缓存,例如在执行write()或fflush()时,可能会产生不被报告的错误。相反,在调用fsync(),msync()或close()时,由写操作产生的错误会被报告。因此,检查这些调用的返回值是很重要的。

写回缓存

这部分介绍了一些关于磁盘缓存的一般知识,与操作系统对这些缓存进行控制的知识。这部分的讨论不影响程序是如何构建的,因此,这部分的讨论是以提供信息为目的的

存储设备上的写回缓存有多种形式。有我们在这篇文章中假设的临时写回缓存。这种缓存会由于断电而丢失数据。大多数存储设备可以通过配置,使其运行在 cache-less 模式,或 write-through 模式。对于写操作的请求,每一种模式,只有当数据写入稳定存储时,才会成功返回。外部存储阵列通常具有非临时的,或具有后备电源的写缓存。这种配置,即使发生了断电的情况,数据也不会丢失。程序开发者可能不会考虑到这些。最好能够考虑到临时缓存与程序防护。在数据被成功保存的前提下,操作系统会尽可能的进行优化,以获得最高性能。

一些文件系统提供挂载选项,以控制缓存刷新行为。从2.6.35的内核版本起,ext3,ext4,xfs和btrfs的挂载命令是"-o barrier",以打开写回缓存的刷新(这也是系统缺省的),"-o nobarrier"用以关闭写回缓存的刷新。之前的内核版本可能需要不同的命令("-o barrier=0,1"),这依赖于不同的文件系统。程序开发者不必考虑这些。当文件系统的刷新被禁用时,意味着fsync调用不会导致磁盘缓存的刷新。

Topic: 

GAE调价对Web架构的将来揭示了什么?

原文:What Google App Engine Price Changes Say About the Future of Web Architecture
翻译:安冲、许力波、林业、曾怀东、朱翊然、马少兵、李凯、王鑫、靳彬

当我还是一个孩子的时候,我像孩子一样说话,像孩子一样理解,像孩子一样思考:但是当我成为一个成年人的时候,我收起了那些幼稚的东西。--Corinthians

随着GAE新的定价模式调整,开发将会由成本驱动。为了使我的应用更好更快,我喜欢去优化它们,但是仅仅为了成本的便宜而去优化无疑是一种时间的浪费。-- Sylvain on Google Groups

当 GAE 摆脱幼稚,成长为一个真正的产品的时候,"pay for what you use"的美梦破了。价格改变,体系随之改变,用户随之改变,理想随之改变,但 GAE 将继续存活。

Google正在关闭很多它的项目。GAE没有被关闭。我们应该感谢由于它定价的调整而让它在更残酷环境下依然可以存活吗?如果没有迅速地向盈利转向,GAE毫无疑问仅仅将会成为诸多想法长卷中一个历史性的脚注。其涉及的迫切性由GAE提供定价百分之五十的优惠以及在多线程版本的Python铺开之前转向新的定价模式所清晰的反映出来。

梦想是美丽的:为你所使用的服务进行支付并且使得它绝对地容易使用。现在这一点很容易理解。这是公平且令人信服的。GAE曾经用了三年时间进行试运行来让梦想实现,结果是这显然是个噩梦。这是它的耻辱。Google是大胆的,他们创造新的事物。他们工作努力。GAE革新了可伸缩的应用程序的发展以及以原始和有趣的方式扩展了PaaS。他们做了惊人的工作。并且结果是被很多人喜欢甚至是热爱的。但是经济原因使他们失败了,他们不得不进行转折。这是困难的。转变的结果会是什么呢?

Pay for what you use has changed。GAE从一种将定价绑定在实际CPU使用上的抽象资源驱动模型转向为Amazon模式的将定价绑定在实际物理资产全部花费上的事例驱动模型(请参考 FAQ )。估计GAE新的定价模式将使对其使用的成本增加到2倍到10多倍。
Dead easy has changed。定价只是故事的一部分。GAE仍然承诺它的整体平台零成本维护的保障,但是更多的压力施加给了程序员来浏览新的定价模式并且重新进行复杂的编码来减少成本。GAE已经不再容易使用了,工作重心已经转移到更良好的编程上。


为什么改变?要走向商业化

Wesley Chun,来自于Google's developer relations。做了一个试图解释变化背后原因的具体工作(摘要):

  • GAE是一个优质的服务,不用花费太大力气,你的项目就具备巨大的可扩展性。
  • 在市场上很难找到其他类似的服务。GAE为所有应用程序提供每天超过1.5亿页面访问量。
    1. 使用GAE你只需要担心你的应用程序。而在EC2上,举个例子,你不得不担心所有的东西:弹性/规模,操作系统,数据库,web服务,负载均衡,许可,补丁,升级等等。
    2. 对于用户自己来说可扩展性是最难以及最昂贵实现的。使用GAE你的应用能够扩展至令人兴奋的数字,查看:Demi Moorethe Royal Wedding 的案例
  • GAE作为一个分布式应用平台是高消费服务。Google已经花费了大量的时间和金钱来进行Google规模的基础设施建设。Google通过GAE让你可以利用所有的研究和精力。
  • SLA和支付支持正在增加。
  • GAE不能继续以亏损状态进行操作。服务消耗过多的硬件以及网络带宽资源。
  • GAE不是被取消而是被发布成一个官方正式产品。
  • 是该交钱的时候了。
  • 令人兴奋的可伸缩性以及易用性是使用GAE的原因。GAE不是一个廉价的托管服务。去别的地方寻找那种廉价的托管服务吧。

一切都非常合理。作为优质的企业级产品,定价不必遵循成本,价格可以上升,以应付竞争,甚至更高,如果你认为你的产品具有特殊的价值。

诚然GAE开始不是这样子的。GAE开始采用一个低廉的价格,易于每个程序员使用的基于CPU使用率计费的平台。现在一切都不是这样了。以前的方法行不通,也许是因为太早了,so it's hard to shake that there's a bait-and-switch feel to this

转向 premium branding 尤其令人惊讶,因为它从来没有被 Google 定义为一个 premium service。从商业角度来看是有道理的,但这是为什么对所有的一切有这样轰动的部分原因

GAE现在要做的是一个企业级的服务。其他产品上赚到的钱将支付给它。它不再定位给那些希望托管于较低成本的GAE架构的开发者,而是定位在开发应用程序来赚钱的开发者。现存应用程序的大小,类型和业务模型,将不适合GAE了。

这是一个非常尖锐的转变。但是,让你做些什么才能生存。必须作出选择真的很难。当我们经历了所有悲痛的阶段,我们必须克服它,重新评估,并继续前进。

mdasen 很好的描述了这些早期日子里令人陶醉的感觉:

Hey hackers! 你必须在我们Google的系统上完全重写你的应用程序,因为我们的系统要比其他系统高效很多。有一些烦人的限制你必须去习惯,对一些事情也非常头疼。尽管如此,我们的服务在负载的使用上很便宜,甚至之后你只要对no-hassle-scaling上花费少量的编程时间,比你用过任何的托管都少!

With equal poignancy Stephen, in this Google Groups thread, captures the feeling of today:

现在的状况是"App Engine"成为了"App Engine for Business",以前那个"App Engine"不复存在了。Google 已经明确了这一点。App Engine现在是一个企业级产品,价格与成本并没有关系。

梦的延续

现在我们可以回顾一下,这只不过是一个实验期…一个实验因为一个关键的方面而失败:基于付费模型的资源似乎不起作用了。

我们震惊的一部分是价格全面上涨。我们通常认为的计算资源随着时间的推移变得便宜。摩尔定律和规模经济相结合一直是我们的好朋友。可伸缩性是朝着相反的方向流动,Google要求用户预算可伸缩性,而开发者则不必。

但是,这个问题不只是盈利和亏损,本实验的结果对于未来应用体系结构有一些有趣的影响。现在,我们要讨论这个话题

我过去完全想错了,我曾以为 GAE 将发展成为一个任务队列

说一下我这个错误的预测吧,GAE 的发展和我猜测的方向截然相反:我以为 GAE 会完全抛弃 instance image 概念,转向在一个巨大的任务队列容器上编写应用程序。

这个猜想/远景的基础是一个GAE最具创新性和深远的特点的发展和演变:任务队列。它的一个大的特征是允许将应用程序分解成异步流。任务进行排队,并在一段时间后执行。取代最初用于GAE上的 monolithic 和同步模型,应用程序可以完全异步,并且可以在任何机器上运行。现在我们清楚 monolithic 的前端实例已经成为任务队列结果的冗余。

问题是任务队列仍然基于镜像。URL可指定一个操作,来终止任务队列里的一个运行时实例,其代码模板是从镜像中读取。一个镜像包含了一个可执行的应用程序的所有代码。这就是 monolithic。

但当客户端调用 URL 的时候,就开始执行一个 monolithic 镜像内的代码。正是因为这些大的镜像必须通过GAE来管理,所以Google需要向你收取更多费用。他们管理需要资源,耗费初始化时间和运行时内存,尽管你的应用没有做任何其他事情。

一个不同的想法就是为什么我们不是简单的请求中止任务队列中?不再使用 monolithic 镜像,而是异步模型。是的,GAE将不得不继续以某种特殊的方式管理并发布这些代码库,任务并不简单。但是这将解决资源粒度如何被更好的分配和衡量的问题,而不是像现在这样把 image 作为代码分发的单元,把实例作为执行的单元。下面我们将会更多的讨论粒度问题。

所以,伴随着这个非常酷的任务队列框架和编程模型的发布,我感觉他们肯定已经做好了准备,宣布 monolithic image 将要消失,实例将要消失,将有更精细的支付以替代您所使用的计费模式。我又一次错了。

这是一个量子力学问题

驱动这个剧变的是,程序运行在一个与资源量化方法与物理机完全不同的抽象机上。一个服务器只有这么多的内存和CPU。即使程序是空转的,运行它也是要使用内存的。Google必须为实例所使用的资源付费,只承担程序运行所使用的资源的费用,而不是承载一个程序所使用的所有的资源,这就在两个模型之间造成了一个不可持续且无利可图的定价摩擦。

另一种说法,程序部署的量很大,但是运行的量却很小。一个较小的工作粒度将允许作业被安排在空闲的时间,这就是为什么我觉得任务队列模型很优秀。

在实践中我们看到了这个效果。一个使用.02cpu时间的应用程序现在或许会用掉2.8实例时间。过去,如果你正确的编码你的应用程序,GAE看起来就像一个巨大的CPU,尽可能少的CPU资源被使用到了。现在,GAE已经激增为一个组件集(前端,后端,调度器等)

现在,最小化 CPU 的运行时间已经没啥意义了。如果应用程序因为 IO 被阻塞(编译者注:被OS挂起因此也没有CPU时间的消耗)仍然会被要求付费。一个实例执行多长时间,你就得花多少钱。实例消耗时间去启动,所以不管这个启动时间对你是否有意义,你都要支付15分钟的花费。而且如果一个请求在调度器看来将会消耗很长的时间,更多的实例将会被spun up。我觉得这一点你真的不能争执。关键是改变了资源是如何共享的。转变到实例模型是某种意义上的放弃。

如果 Google 认为内存是一种稀缺资源的话,很多人都要求把 CPU 计费和内存计费分离。这会要求应用更有效率的使用内存。(编译者注:这句话的意思是,很多人认为 GAE 的调价的成本压力是来自内存)问题是,对于一个实例,内存和CPU并不是可独立的。这也是为什么Google不能制做一个完美的高效的调度程序,作业单位并不匹配计算资源的单位。

成本上升

  • Raymond C: 月花费: $900 -> $2850 (310%)
  • Daniel: 有300%的增长。
  • joakime: 在新定价模式下我们的花费增大到了原来的2800%。

因为在新的计费模式下,实例时间增加了,所以花费增加了。Python多线程编程能帮助解决这个问题,但是在数据存储行为上的开销也在增加。


The Amazing Story Of AppEngine And The Two Orders Of Magnitude

Emlyn O'Regan写了一篇非常棒的文章详细解释了他在新的定价模式中调整自己应用的经验。他后来接着发表了 AppEngine Tuning #1

最开始,像大多数人一样,他忽略了原来的公告,他认为变化不大,但实际刚好相反。他的账单从$0.51/day 上涨到了$49.92/day。原来一年$200 的花费变成了一年$20K。这是一个巨大的上涨。

Emlyn随后做的事情很cool,他带着我们浏览了一遍他的app,找出钱花在哪里,以及他对自己的app做了怎样的改变来减少使用Google工具和文档的花费。在新的模式下我们找到了以前不是问题但是现在是的一些行为。

这些行为包括:

  1. 前端实例时间。他的app每天使用11.39cpu hours,231.13 Instance hours.造成这一问题的原因是创建了很多并行的工作。这导致了 scheduler创建更多的实例来处理工作。与工作实际需要相比,实例的增加导致了很多额外的instance hours 的使用。目前还没有解决这个问题的办法,但是我们已经知道了这个问题的原因。诸如对时延要求不高一类的后台任务,scheduler 的方式应当温和一些。
  2. 存储数据读取。这是很大的成本。他的app每天会在数据库做60,000,000次操作。首先,他需要维护旧数据,对数据表进行扫描需要一直进行读取操作。It turns out by using the fetch call and paging through records using limit and offset, you can really crank up the number of datastore reads. 事实上通过使用fetch call和paging能够减少对数据库的读取操作。设计时需要考虑如何最小化读取的次数。代码上的修改能够减少数据读取的需求或者可以把这些操作转为后端操作,每天执行一次后端操作而不是没两分钟执行一次。
  3. 优化调度器很有效果。把最大空闲实例设为1,最小等待时延设为15,平均实例数设为4到5而不是10到15,这样并不会带来可感知的性能下降。

一些问题是由于"just make it work"这样的设计模式而导致的. 这在项目中很典型。GAE的新定价机制使这种不严格的代码变得花费巨大,所以需要对它们进行修改。好事情是,架构不得不从现在开始考虑这些问题。最小化实例数以及最小化数据库操作。一定要检查这些。

对于GAE来说,这会减少整体资源的使用,这也是他们所期望的。发出合适的定价信号是实现这一结果的最有效的方法。

其他问题还包括由于无意的GAE API调用造成的意外结果。在API中的后果应该更明显。由于它非常微妙而且具体app有着区别,我们需要时间来解决这些问题。


Scheduler 有利益冲突问题

scheduler 的工作是在计算机集群中安排工作。在这种情况下,工作的形式包括web请求, cron jobs以及任务。所以引入了工作队列。这项工作需要以合理的方式分配资源。那么什么在处理工作呢?是实例。实例的运行占用内存,CPU,硬盘以及带宽,这意味着运行实例需要付费。切换(spin up)实例需要固定的时间,不管工作的性能如何 切换实例也需要付费。并且由于它们花费固定的代价运行,让它们在有较多负载的情况下运行更为合理。GAE并不知道你将会造成怎样的负载。GAE的负载是由一个随机过程造成的。

想彻底解决这个问题非常困难。在实时调度中,不可能确定的安排一个变化的工作负载。即便通过系统运行同样的工作负载,在不同时刻也有不同的结果。这是由cpu定价转变为实例定价造成的奇怪后果。

很多人抱怨GAE scheduler是一个内在利益冲突的矛盾体。 scheduler决定了实例运行的数量,实例运行数量反过来决定了盈利。这是一个好主意么?这种激励方式是错误的。如果开发者和GAE都有类似的激励机制会比较好,现在他们本质上是相反的。

并且,注意到google在广告方面有相同的 edge。google建立这些数据的索引,创造市场,取走广告,设定价格,并且决定广告在何时显示。这所有的一切像GAE scheduler一样对公众是不透明的。我回忆起弗洛伦萨的美第奇家族,他们通过简单的控制那些可以参与选举的人来控制公众选举的结果。

一个存在潜在冲突的令人关注的地方是认购超额。如果你分给每个应用许多RAM而google不能在同台机器上运行太多的实例,因此RAM在前端被限制在了128M以内,在后端限制在了1G以内。像其他的托管服务一样,超额订购这些资源可以使单台机器挣得更多的钱。那样可能导致交换、系统颠簸等问题,这些问题可能导致更高的延时从而需要申请更多的实例。两个方面都需要钱。而且低内存的限制使得更难去写更大的多线程应用程序,这些程序是降低延迟以及减少实例数量的策略之一。

为了解决所有的问题,许多的压力正在放到scheduler上。我们会使调度变得更好,这里面包含了你的费用。就个人而言,由于我们之前讨论的粒度错配问题,我不太清楚那样会真正的起作用。

问题在于程序员要负责平衡所有的这些目标。Gubbi表达了这种进退两难的感觉:

我抱怨的是,新价格让延迟成为了关注的焦点,然而开发者只能在应用程序代码的层面去优化它。应用程序和基础设施都应该为延迟负责。

以前是基于如何实现业务目标的策略驱动的架构,而如今程序员将在他们的程序中硬编码一个设计模型。当所有的假设发生变化时,代码会很难改动。这所有的需求将提升到抽象的水平上。例如,当一个任务是低优先级的,scheduler会说我们不需要为它而加速实例,让我们利用空闲时间再去调度它吧。

Steve已经在scheduler配置文件和请求设置文件中做了一系列的好的scheduler变化的建议,主要的思想是基于请求头和其他我们能够在那个级别上获得的信息的基础上在预定义的调度配置文件中过滤请求的能力。


The Architecture Shift

From Barry Hunter

“旧”的方式,非常提倡低cpu的使用,即使那样可能带来高延迟的代价。缓慢请求时,将会花费大量的实例 - google的成本。

“新”的方法推崇降低你的延迟。快速的请求带来每秒钟(每个实例)更多的查询。这意味着更少的实例。

通过收取实际使用实例的费用,他们能够有助于压低实例的数量。

因此开发人员应该以压低实例的数量为目标--为了省钱。

那些需要,想要,(或者懒得去优化),慢的请求将要支付 - 接近于google实际的开销的钱。

Google不希望你spinning up 实例并且很快的把他们撤下来。Its that spinning up, that 'costs'.


故障排除指南

johnP 觉得编写一个 trouble shooting guide 来应付价格变化是一个好主意。他的第一个草案是:

  • 过高的实例成本?
    1. 突发的并行
    2. 闲置的实例设置
    3. 减少响应时间
    4. 其它?
  • 过多的写:
    1. 减少不必要的索引
  • 过多的读:
    1. 确保你的fetch()操作而不是通过结果循环
    2. 检查抵消查询
    3. 其它?

检查google的文档
google有一些值得看的好文档:

Optimize for One Instance
Joshua Smith:

我正在优化单一实例的情况,其实我只是实现了一个简单的缓存。第一次命中kiosk时生成页面并且返回它,而且在内存中保存该页面。第二次命中时从内存中获得缓存的页面。这要比我原来的方案好很多,因为在kiosk进行页面重载时我保护了任何异常发生的情况。

Task Scheduler Bunching
Joshua Smith:

尽管大家着眼于任务队列与调度器交互这种方式,但是出现了另外一种情况,任务队列趋向于聚集任务,将任务并行地导入到调度器去加速产生一个新的实例。我觉的,必须首先考虑等待任务的数量,然后考虑加速实例的产生来处理队列。如果仅仅有两个实例,必须使他们等待很短的时间。(当然,如果能够给用户控制权限更好,凭借设置任务的优先级)

Dump Writes to Queue
peterk:

第一种类型的请求,将被写入到任务队列,立即得到返回结果。队列将被后台的实例处理。虽然目前这种类型的花费有所上升,但是主要的优势是我基本上得到了对那种写队列被处理的大量控制。AppEngine不会为我加速处理新的前端实例。这样我就可以随意控制想多快,多少钱,来写。将会出现一个延迟,在将数据写入到数据库之前。但是我认为这点可以承受。

Use Cursors
Tim Hoffman

再看看游标,如果你想对一个数据集操作,也没有多大的性能问题的限制或抵消。

Use Pull Queues, Backends, and Cron
Tim Hoffman

我将考虑使用一个pull队列来处理你的任务负载,代替正常的push队列。这种情况下,我们可以用使用计划任务工具来限制任务加速的数量,以及在一个连续模式下使用离线处理方式。想的越多,我觉得这个过程适合后端和计划任务工具,而不是前端和任务队列。

Two Stage Gets Preferred
Google App Engine Post-Preview Pricing FAQ:
这种新的计费模式,仍然是很经济的,对处理获取1000个 keys-only 的查询,和得到500的数据,相比正常的查询(non keys-only)来得到全部1000数据。第一种是更加的经济。获取1000keys+500entities=$0.0001+0.00035=$0.00045;而第二种花费0.0007美元。

Stop the Bots
In Googlebot Spawning New Instances, Jeff Deskins notices something very interesting

当我们着眼于降低在AppEngine的费用时,googlebot抓取页面的速率为12页/s。这将导致另外6个实例被创建。

另一个低优先级 spiky 表现的例子同样导致花费增加,由于每个爬虫都在消耗费用,整个抓取网页的的思路都需要改变——Spiky App Penalty

Jan Z/ Hapara:

处罚“spiky应用”的费用的方式太多。三年前,当我们首次启动一个GAE应用时,看准了下面的三点:伸缩性、以模式付费,简单。

我们的应用是非常“spiky”-单个用户一次产生50次请求,需要服务器快速响应。我们的应用已经在该平台上运行了三年时间,并根据GAE的规则修改了代码,使得代码能够运行在伸缩性和其他的约束条件下,并且运行良好。我们没有其他的选择,如果我们使用EC2或者其他的系统。

这种新的计费模式导致我们有两个麻烦:为空闲的实例付费、目前的模式失去简单性和可预见性

有些人建议,这种新的调度模式需要一个灵活性,来处理小和束缚的应用。你的这种计费模式却没有考虑考到大量用户---首次想用你工具,以及那些利用你的早期限制和约束来开发的人。


无法确定的成本
这种调度程序对编程人员来说是个黑盒,隐藏了核心的空间算法,使得很难理解。不能被控制,不能评理。控制实例和带宽,比控制CPU的应用将更困难。这导致了很多不确定的困惑。难道这就是世界新秩序的一部分吗?

Instance Idea Includes both CPU and RAM

FAQ的作者Greg D关于为什么GAE不为RAM建立一个单独的收费机制

例如我们已经通过charging增加了一个RAM charge。通过拥有一个实例分配的内存量,实质上我们已经在使用那个RAM了。所以收费是收取的使用CPU和RAM的费用。我们在考虑把这两种费用分离出来,这样我们就可以继续charge CPU-hours,然后也可以charge instance-hours(这个不能叫做RAM-hours)。这些都看起来越来越使人迷惑并且这么做也不会更便宜,因此看起来并不太值得去这么做。然而我知道已经有很多关于用这种收费的讨论。无论你把它称之为RAM-hours 或者instance-hours,也不论你是否在顶层为CPU-hours 收费,最后的结果都是一样。对应用程序会根据对其分配的内存量和分配的时间而收取费用。这意味着那些想省钱的应用程序有必要在RAM-hours方面做优化,这在本质上意味着用更少的时间来完成任务。

多任务的回归,宝贝

基于价格的实例,其目标是能尽可能多地利用实例。这需要多线程,因此在容器中可以尽可能多的去执行仿真进程。之前的GAE都是单线程。启动更多的实例是为了处理更多的请求。这显然并不高效,所以我们重新写线程代码,这是实际上是一种很好的方式。启动一个巨大的JVM就是我们为什么要把应用服务器放在首位而远离CGI模型的原因。GAE模型并不盈利是其一点小小的遗憾。

多线程方法的收益很高,以至于GAE指望它们来平衡提高的成本。Brandon Wirtz说:

我刚刚完成了对我的应用程序早期版本的重新编写(从Python到Java)。这不是我最新的app版本,但是这类似于一个已经部署了数月的版本。所有的版本都在做相同的事情,能够兼容各种方式。我还没有运行那个版本太久,但是我已经从20个实例减到1个实例了。当有足够的数据来确认的话,我会在8小时之内给出一个完整的报告。

我完全相信,这个app的规模,将会是整个应用程序规模的一个重要指标。(这次重新编写花费了三个小时的时间,几乎是一句句进行对照编写的)。

内存消耗会随着并发和多线程的应用而提升,因此看到它们如何协同工作讲会是一件很有意思的事情。


相比较 Amazon,GAE 还具备优势吗?

Greg D:

对于仅在RAM的基础上运行的服务进行比较。RAM是指示利用服务来完成任务的诸多因素之一。APP Engine 还包括许多免费的API,不需要管理APP,也不需要运行维护OS等。APP Engine是一个平台,当我们决定使用不同的资源(电子和人力资源)时,那么收费也将有所不同。

Robert Kluin:

当比较价格时,千万不要忘记人力资源的数据存储,可扩展前端,memcache,以及管理这些东西的开销。我曾经管理过分布式的数据库,如果你还没有这么做,那么它比你想象的更有考虑的价值(假设你关心你的数据)。不要忘记管理成本的开销,即使一切运行正常的话,一年也得有几千美元的开销。

Barry Hunter:

对于什么是有价值的,我并不认为拿一个GAE实例比较一个像VPS的实例是公平的。

它们是非常不同的’beasts’.理论上GAE提供更多的东西。Google处理所有的安装、配置以及负载均衡等。

如果仅仅使用相当于十分之一的VPS,那么这就显得有点昂贵。但是一旦你开始需要管理多个VPS,提供负载均衡器,重新提供故障情况等进行备份。所有出现的这种情况均与GAE有关。

所以不要忘记获取一个免费的实例配额。

后端服务是昂贵的
Ugorji:

后端的instances看起来貌似是荒唐的且价格过高的(对于一个256MB/1.2GHZ的Instance来说,每月需要花费115美元)。它们这种过高的价格使得它们对于许多那种可能因为此功能而举债的那些用户而言,是毫无吸引力的,这就造成许多用户去寻找其它的产品。

在某种程度上,貌似我们到了进退不得,左右为难的地步。后端其实是应对那种需要长时间运行且频繁占用CPU的活动的好办法,它可以使我们从那些任务链的当前业务中解放出来,其中每个任务都是在一个固定的时间内完成,或者使用map-reduce操作。然而,后端是如此的昂贵,以至于大部分人都不会去使用它。不幸的是,当前使用前段的instances和task/map-reduce的业务也是如此地昂贵,这是因为我们不得不为超出我们使用的部分额外支付1/4 instance小时税。


性能 = 可伸缩性

FAQ for out of preview pricing changes:

因此,在延时和每个instance每秒可处理的请求数量之间存在这一种直接的关系,举例来说:10ms latency = 100 request/second/instance,100ms latency = 10 request/second/Instance,等等。多线程的instances可以处理许多并发的请求。因此,在CPU消耗和每秒请求数之间也存在一个直接的关系。举例来说,对于一个B4(大约2.4GHZ)instance:消耗10 Mcycles/request = 240 request/second/Instance,100 Mcycles/request = 24 request/second/Instance,等等。这些数字是理想的情况下的,但是它们应该同你能够在一个instance上完成的量十分接近。多线程的instances当前只支持Java,我们计划今年晚些时候支持Python。

Jeff Schnitzer:

由于Google所做的特定的设计决策,高延时请求并不会扩充*on appengine* 。高延时请求在其它平台上扩展的很好——运行Node.js/Tornado/EventMachine等等的分支在应对上万个l延时请求方面毫无问题。甚至传统的java appservers在可接受的限制下处理延时——取决于你正在做什么,使得你可以在每个JBoss instance上应对成百上千个并发请求。


GAE 无法再支持以广告为收入来源的应用
Kaan Soral:

比如说我现在有一个依靠广告收入的应用。并且假设每个请求耗时1秒,任务调度器没有任何问题。因此,我每小时也就是3600秒为一个instance支付$0.05 。因此让我们把那个数字平均到3600个request,并且假设有1800个page views(假设用Ajax做的)。因此1000个page views的开销是:$0.05/1800*1000=0.027$。假如一切没有问题,而且不把后端任务计算在内,尽管我的十分大,我至少需要 0.027$ ecpm。举例来说,土耳其的流量有时ecpms可能会低于0.1$,而且我确定肯定还有其它国家的ecpms有着更低的ecpms,我们的流量费是最佳的。总结一下,看起来如果我使用GAE,貌似我一直会担有开销比收入高的风险……

我若在一个专用服务器上部署应用,通常一个服务器是几乎空闲的,负载基本上是0.5(8个核),有时候是2-3,并且我确定我没有使用它们优化到%20,但是我的成本仍然是收入%10!如果我可以使用一个服务器到最大级,可能达到成本只占%2。在最好的情况下,假设没有任何问题的情况,看起来在GAE上这个比率是%25。

这可能预示着对于移动服务来说,如果想采用GAE作为移动客户端的便宜后端的话看起来并不可行。


混合架构?

Tim Meadowcroft:

或者说是通过云端集成—我希望更多的人通过GAE的用户帐户/认证,把他们的文件存放在一个或更多个CDN上,使用第三方pub-sub服务更新客户机,可能的话将不同服务间的数据(热数据vs引用数据)集成起来,为那些不会遭受流量激增的后台进程保持固定的专用实例等。我希望能够实现抽象服务—能够用于编写完成一种服务的API,并且独立于任何具体平台的库。


Python or Java?

Java 具有即时编译技术JIT,因此假设实例保持足够长的时间使即时编译生效,并假设具有更高的延迟处罚,那么在GAE上,java会比python更受欢迎吗

整个实例的代价计算太复杂

Daniel Florey关于这一切的复杂度的有很好的见解:

有没有一种方法,可以在不必了解程序调度引擎内部的前提下,建立一种简单的代价模型?我认为为消耗的资源付出合理的代价是可以的,但是对于实例/小时的方法,并不认同。这让我感觉像是impl在为我负责。我希望有一种简单的方式(从用户的角度),可以由我负责cpu资源与内存使用的代价,可以对“可扩展性/处理能力”进行预算处理,使程序引擎负责它需要负责的一切,并可以根据设置加速/减缓我的程序。


结论

  • 很幸运GAE在经费削减的灾难中存活了下来。他们保持了自己的持续能力。这需要极大的勇气做出这样巨大的改变。这真的是一件很令人痛心的事情。好消息是,我们仍将看到GAE项目组的开发与创新。坏消息是,我们损失了前几年中一项伟大的创新,基于计费模型的CPU。我们还可以再看到它吗?这个梦想真的覆灭了还是会再次成真?
  • 也许你不应该使用PaaS. PaaS的部分承诺是开发者编程的简单性。在现实中,这种度量是否可能?在GAE中,为了提升性能,开发者们负责在它们的软件中建立了下缓存层,传统的web架构已经使用这种方法很多年了。确保缓存的一致性是一项繁重的工作。我们已经看到了队列游戏是如何被播放,以防止实例陷入不必要的旋转中。使用调度程序开发并不是零代价的。开发的时间是有价值的,这对于使用零代价的PaaS系统来说,是一个重要参数。如果开发者的时间持续花费在优化调度程序上,PaaS系统还会是一个好的选择吗?
  • 云计算才刚上路。在 Cloud Programming Directly Feeds Cost Allocation Back Into Software DesignBuilding Super Scalable Systems: Blade Runner Meets Autonomic Computing In The Ambient Cloud中,我们讨论了在对底层平台的代价梯度回应时,是如何改变的。这些关于如何最有效的使用GAE的新的调度程序的类型讨论进行的很成功。很显然,我们需要在一个更高的抽象层次上进行操作,使此模型具有实用性。当然,我们可以通过添加更多的旋钮,使模型参数化。但那样的话,开发者很快就会被很多具有未知相互作用与后果的选项淹没。必须建立一种新的合成体。
  • 程序和机器的配合不当。需要基于计费的实例,是因为程序与机器资源打包时采用不同大小的容量。虚拟化技术帮助组合了这种不匹配,但是它确实和我们在性能更强的机器上是一样的。需要一个不同的架构以这种方式来开发硬件资源,以使开发者们能够获得他们想要的基于计费的方法。
  • 对可扩展,低成本基础架构的巨大需求。面对这个事实,大多数应用都是勉强度日。它们靠广告支持,在程序商店中收取99美分的费用,或仅有着1%的低转换率。不是所有公司都像Apple, Zynga, 或 Netflix一样。许多很酷的想法需要在一个有利的环境中成长,这正是我们今天缺少的。我们最应该为基础架构做些什么?收取更多的费用? 这也没错。但由于缺少可以以较低成本开发的可承受的基础架构,创新被大大抑制了。看起来GAE无法解决这个问题。但必须有人解决。

相关资料

Topic: 

Acoustid 算法大致流程整理-王鑫

原文:http://oxygene.sk/lukas/2011/01/how-does-chromaprint-work/

  1. 图片在此算法中扮演了一个很重要的角色,当人们“看到”音频时,它通常都是形如下面的波形图:
  2. 但是这种图对分析起来没有什么太大用,更有效的一种表现形式是声谱图,它描述了特定频率的强度随着时间的变化:

    可以通过把原始视频切割为许多重叠的帧并在其上应用傅立叶变换(或者快速傅立叶变换)来得到这种图片。许多声纹识别算法都是利用这种图片来工作的,有的是比较频率和时间的不同,有的则是寻找波峰。

  3. Chromaprint则更近一步将频率转换为音符来处理。Chromaprint只关心音符,而不关注八度音,因此结果就是12音域,每个音符对应一个音域。这种信息被称为“Chroma特征”(其实就是一个12维的特征向量)。再经过一些过滤和标准化,最终会得到下面这种样式的图片:
  4. 既然有了音频的表现形式,那么比较这类图片并计算其相似度也不是太困难的事了,但是如果我们想在数据库中搜索它们,我们则需要压缩它们,也就是需要一个更为紧凑的形式。Chromaprint的方式是在Pairwise Boosted Audio Fingerprint这篇论文中提到的方法上修改的。
  5. 然后你可以想象你拥有一个16×12像素的滑动窗口从左到右来滑过整个图片,每次只滑动一个像素,这样就得到了许多子图。针对每一个子图应用预定义好的16个过滤器来捕获滑过的音符和时间的强度的差别。过滤器就是计算子图的灰度图的特定区域的和,然后比较两个和。有6中不同的区域

    通过使用上面这种类似于掩码的图片,把它置于子图任何一个位置,然后计算黑色和白色区域的和,再同另一个和相减,结果是一个单精度实数。每个过滤器都有3个系数,最终结果会是一个0到3之间的整型数。每个过滤器的系数都是通过机器学习算法在音频文件的训练集上训练得到的。

  6. 现在我们有16个过滤器,每个过滤器都可以把结果编码为2位。我们把这些结果组合在一起,得到一个32位的整型数字。
  7. 如果对所有滑动窗口滑过的子图都应用上述办法,我们就得到了整个音频的声纹了。识别声纹最简单的办法就是针对声纹计算位错误率。

实验结果:

Heaven FLAC
  
  

Heaven 32kbps MP3
  
  

Differences between Heaven FLAC and Heaven 32kbps MP3
  
  

Under The Ice FLAC
  
  

Under The Ice 32kbps MP3
  
  

Differences between Under The Ice FLAC and Under The Ice 32kbps MP3
  
  

Differences between Heaven FLAC and Under The Ice FLAC

由上面可以看出,针对同一首歌的FLAC和MP3差别很小,而不同首歌之间差别很大,结果还是挺好的。

Topic: 
订阅 RSS - sohulinux