云计算设计模式翻译(五):Compute Resource Consolidation Pattern,consolidation


    这个模式所做的事情概括一下就是把多个不同的任务和操作合并到一个计算单元中,从而使云计算应用提高计算资源利用率,降低管理开销和任务之间连接交互的开销。

PS:我这里对后文中所翻译的“计算单元”做个小小的注释,这里的计算单元可以认为是逻辑的运行容器,可以是基于cgroup的各种container,也可以是像Storm中的worker,Spark中的Executor等等。这个模式除了在自己设计分布式系统时能作为参考,在使用像Storm或Spark这样的框架时也很具有参考意义,可以帮助配置优化整个计算框架的调度机制(比如Storm就支持自定义调度机制)。

CONTEXT AND PROBLEM

    一个云计算应用会频繁地进行不同的计算操作。在一些解决方案中,在系统设计初期,遵循关注点分离设计原则,将不同的操作运行在完全独立部署的计算单元中是很有意义的。然而,尽管这种策略能够简化业务逻辑设计,但是将同一个云计算应用的各个部分部署大量计算单元上会大大提高运行时开销并增加系统管理复杂度。

    下图这个例子展示的是用了多个计算单元的云计算应用架构。每个计算单元运行在自己独立的虚拟环境中。每个功能都是由运行在自己独立计算单元中的独立任务实现。


    每个计算单元即使在空闲或者压力很小的情况下都会占用资源,因此这并不是一种最划算的解决方案。

SOLUTION

    为了减小系统开销、提高资源利用率、提升通信速度、降低系统管理难度,我们也许可以将不同的任务或操作合并到一个计算单元中来执行。

    可以根据系统提供的特征信息以及组合这些特征信息的开销来对任务进行分组。一个用于判断相近任务的通用方法是关注任务的扩展性、生命周期以及运行所需要的条件(资源)。将这些任务归类到一起后就能当做一个单元来衡量。而云平台的弹性特点可以根据负载来以这些经过组合的计算单元为单位来进行扩展。

下面举个反例来展示如何利用任务的扩展性来确定哪些任务不应该被归类到一起:

    有两个任务:任务1用来监听队列中一种非常罕见的消息;任务2用于网络中大量的通信事件。第二个任务对系统弹性要求很高,很可能会根据网络流量大小增加或减少对应的计算单元;但如果依照第二个任务增加计算单元的比例来同时增加第一个任务的计算单元,就会导致系统中多了很多监听器来监听那种罕见消息,这显然是没有意义的(也就是说第一种任务对不需要经常扩展计算资源,而第二种任务经常要求增减计算资源,如果把它们分组在一起然后一起增减计算资源会导致不必要的浪费)。  

    在很多云计算环境中是可以为计算单元指定特定的资源的,比如cpu核、内存、硬盘空间等等。一般来说,绑定的资源越多,绑定所需要的开销就会越大。所以从效率上来说,要尽量延长一个拥有大量资源的计算单元的执行时间,使其保持在尽可能长的时间里不失效(即需要使拥有大量计算资源的计算单元保持忙碌状态,多分配任务到这里面去)。

    如果有一堆任务需要在一个突发时间内占用大量CPU资源,那么就要将这些任务尽可能地合并到一起,然后申请一个拥有足够多资源的计算单元来执行它们。然而,在系统压力过大时(也就是说现有资源不足以同时满足所有任务)要平衡这一要求(译者YY一下:比如可以把这些任务不止划分成一个组而是多个组,然后采用一些调度比如分批执行,这样一来虽然分批但是CPU是跑满了)以防出现资源竞争。与之不同的是,一些长时间持续运行的计算密集型任务不应该被划分到同一个计算单元中运行。

Issues and Considerations

在考虑如何实现这个模式时需要注意一下几点:

1.扩展性和弹性:很多云集算平台中通过支持计算单元的动态增删来实现系统的扩展性和弹性特点,因此在对任务进行分组时务必不能将扩展性弹性特征不同的任务分在一起(前文例子可以证明)。

2.生命周期:一些云计算平台会周期性地回收计算单元的虚拟化环境(资源)。但这种设计下一般来说当系统中有需要长时间执行的任务运行时,需要将其所在的计算单元配置成不会被回收,除非任务已经执行完成。一种替代手段是采用check-pointing,当计算单元被终止时任务会暂停,做一个check point,然后当计算单元被恢复后又能从这个点开始继续运行。

3.Release Cadency:如果计算单元中有任务的配置或者业务代码经常性发生变化,那么就会导致需要经常停止计算单元,然后更新业务代码、更新任务配置并重新载入任务,最后重启计算单元。但当这种情况出现时,同一个计算单元中的计算任务也随之受到影响,随着计算单元的暂停重启而重启。所以对于那种经常性发生变化的任务要把它独立出去以免对其他任务造成过大影响。

4.安全性:在同一个计算单元的任务一般来说会在同一个安全控制上下文中工作,并共享访问资源的权限。因此,被分配到一起的任务必须相互之间高度可信,并保证某个任务不会对其他任务造成不好的影响。另外,如果一个计算单元中分配的任务越多,那么当这个计算单元被攻击时收到的危害就越大,而计算单元中漏洞最多的任务会成为整个计算单元中所有任务的短板。

5.计算单元的容错:一个计算单元中的某个任务如果出现异常,那么则很有可能对同一计算单元中的其他任务造成影响,比方说在一个不好的设计中某个任务如果启动失败了,那么很可能整个计算单元的启动逻辑都会被影响。因此需要考虑到做好计算单元级别的容错,避免由于单个任务的失败对其他任务产生影响。

6.竞争处理:使用中要避免将两个会产生资源竞争的任务分配在一起,在理想情况中,被分配在一起的任务应该有不同的资源利用特点。举个例子,两个计算密集型的任务就最好不要被分配在一起,类似的两个都需要消耗大量内存的任务也最好不要被分配到一起,这种情况中把计算密集任务和需要消耗大量内存的任务放在一起就是一个很好的组合(比较一下这种情况与前文那种突发大压力情况下策略的不同)。

7.复杂性:使用这种模式时会把不同的task混在一起放到一个计算单元中来运行,相比传统设计来说这种方法必然会使计算单元中的程序逻辑变得复杂,从而提升维护、调试、测试难度。

8.保持逻辑架构稳定:使用过程中要优化每个任务的设计使它能在日后尽可能地保持不变。

9.其他:合并计算资源只是用于降低并发运行任务开销的方法之一。这个方法需要进行严格的计划和监管以确保其发挥出理想的效果。根据系统的不同特征或者运行环境特点,有时一些其他策略可能会更加有用,所以不能局限于这一种模式。


相关内容