离线下载
PDF版 ePub版

yangzhenping · 更新于 2017-11-20 15:00:55

计算资源整合模式

合并多个任务或操作成一个单一的计算单元。这种模式可以提高计算资源的利用率,并降低与云托管的应用程序进行计算处理相关的成本和管理开销。

背景和问题

云应用程序频繁执行各种操作。在某些解决方案也可能是有意义的最初遵循的关注点分离的设计原则,并把这些操作成托管和独立部署(例如,如在微软的 Azure 云服务,独立 Azure 网站不同的角色独立计算单元或单独的虚拟机)。然而,尽管这种策略可以帮助简化溶液的逻辑设计,部署大量计算单元作为同一应用可以提高运行时的托管成本,使系统的管理更加复杂的一部分。

作为一个例子,图1示出了使用多个计算单元被实现的一个云托管解决方案的简化的结构。每个计算单元在其自己的虚拟环境中运行。每个功能已被实现为一个单独的任务(通过任务Ë标任务A)在自己的计算设备上运行。

图1 - 通过使用一组专用计算单元运行在云环境中的任务

每个计算单元消耗的资源收费,即使是闲置或不常使用。因此,这种方法可能不总是最有成本效益的解决方案。

在 Azure 中,这一问题适用于云服务的角色,网站和虚拟机。这些产品在他们自己的虚拟环境中执行。运行的单独作用,网站,或者被设计为执行一组良好定义的操作的虚拟机的集合,但是需要进行通信和协作,作为一个单一的解决方案的一部分,可以是一个资源利用效率低。

解决方案

为了帮助降低成本,提高利用率,提高通信速度,减轻了管理工作有可能将多个任务或操作成一个单一的计算单元。

任务可以根据各种基于由环境提供的功能,以及与这些功能相关的成本的标准进行分组。一种常见的方法是寻找具有关于它们的可扩展性,寿命和加工要求具有相似的任务。分组这些产品一起使它们能够扩展为一个单元。由许多云环境所提供的弹性使一个计算单元的其他实例,以根据业务负载被启动和停止。例如,Azure提供自动缩放,可以适用于云服务的角色,网站和虚拟机。欲了解更多信息,请参阅自动缩放指导。

作为一个计数器的例子来说明如何扩展可以被用于确定哪些操作可能不应该被分组到一起,考虑以下两个任务:

  • 任务 1 轮询发送到队列罕见的,对时间不敏感的信息。
  • 任务 2 处理网络流量的高容量阵阵。

第二任务要求的弹性可能涉及起动和停止的大量的计算单元的实例。应用相同的缩放到第一任务只会导致更多的任务上监听同一队列不频繁的消息,并且是一种资源的浪费。

在许多云环境中,它可以指定在CPU内核,存储器,磁盘空间等的数量而言,以一个计算单元的可用资源。通常,指定的资源越多,就越有成本。对于金融效率,最大限度地工作的一个昂贵的计算单元执行的数量,而不是让它变成无活性在较长时间内是很重要的。

如果存在需要大量的 CPU 功率的短脉冲串的任务,考虑合并这些成一个单一的计算单元,其提供所需的电源。然而,重要的是平衡这种需要保持昂贵资源忙对它们是否过分强调指出可能发生了争用是重要的。长时间运行,计算密集型任务可能不应该共享相同的计算单位,例如。

问题和注意事项

实施该模式时请考虑以下几点:

  • 可扩展性和弹性。许多云解决方案实现的可扩展性和弹性,在运算部的通过启动和停止的情况下,单位的水平。避免了分组在同一计算单元相互矛盾的可扩展性要求的任务。
  • 一生。云计算基础架构可以定期回收托管的计算单元的虚拟环境。当执行一个计算单元内许多长期运行的任务,可能需要对设备进行配置,以防止它被回收,直到这些任务已经完成。可替换地,通过使用一个检查指向的方法,使他们停止干净,并继续在在其中,当所述计算单元被重新启动他们被中断的点的设计的任务。
  • 释放节奏。如果一个任务的执行或配置变化频繁,则可能需要停止计算单位主办的更新的代码,重新配置和重新部署的单元,然后重新启动它。此过程也将需要相同的计算单元中的所有其他任务被停止,重新部署,并重新启动。
  • 安全性。在相同的计算单元的任务可以共享相同的安全上下文,并能够访问相同的资源。必须有高度的任务之间的信任,而且相信,一个任务是不会损坏或其他不利的影响。此外,增加了在一个计算单元可以增加计算单元的攻击面运行的任务的数目;每个任务是否安全的一个最脆弱性。
  • 容错。如果在一个计算单元中的一个任务失败或异常情况,它可能会影响在同一单元内运行的其他任务。例如,如果有一个任务无法正常启动它可能会导致对计算单元失败,整个启动逻辑,并且防止在同一单元的其他任务的运行。
  • 争。避免这种情况,在相同的计算单元争夺资源的任务之间引入的争用。理想情况下,共享相同的计算单元的任务应该表现出不同的资源利用率​​的特征。例如,两个计算密集型任务可能不应该驻留在同一个计算单元,而且消耗大量的内存也不应该两个任务。然而,混合使用需要大量的存储器可以是一个可行的组合任务中计算密集型的任务。

注意

你应该考虑整合计算资源只对已在生产用于在一段时间内,使得操作人员和开发者能够监控系统,并创建热图,它标识了每个任务利用别共资源的系统。此图可以用于确定哪些任务是很好的候选共享计算资源。

  • 复杂性。组合多个任务到一个单一的计算单元增加了复杂性中的代码单元,可能使得更难以进行测试,调试和维护。
  • 稳定的逻辑架构。设计和实施中的代码中的每个任务,以便它不应该需要改变,即使物理环境中任务运行不会改变。
  • 其他策略。整合计算资源的方法只有一个,以帮助减少同时运行多个任务相关的成本。这需要仔细的规划和监测,以确保它仍然是一个有效的办法。其他策略可能更合适,这取决于所执行的工作的性质和所代表这些任务正在运行的用户的位置。例如,工作负荷(如所描述的计算分区指南)的功能分解可能是一个更好的选择。

当使用这个模式

使用这种模式的任务,如果他们在自己的计算单元运行不符合成本效益。如果一个任务花费大量的时间闲置,运行此任务的专用设备可以是昂贵的。

这种模式可能不适合于执行关键容错操作处理高度敏感的或私有数据,并且需要其自身的安全上下文的任务或任务。这些任务应该在他们自己的独立的环境中运行,在一个单独的计算单元。

例子

在 Azure 上构建一个云服务,它可以巩固多任务的处理成一个单一的角色。通常,这是执行的背景或异步处理任务的辅助角色。

注意

在某些情况下它可能会包括在 Web 角色的背景或异步处理任务。这种技术可以有助于降低成本和简化部署,虽然它可以影响由 web 角色所提供的面向公众的接口的可扩展性和响应性。该文章合并多个天青工作者角色成天青 Web 角色包含执行背景或异步处理任务在 Web 角色的详细描述。

的作用是负责启动和停止的任务。当 Azure 结构控制器加载的作用,它引发的启动事件中的作用。您可以覆盖 WebRole 或 WorkerRole 类的 OnStart 方法来处理这个事件,也许是为了初始化数据和其他资源,在这种方法中,任务依赖。

当 OnStart 方法完成后,角色就可以开始响应请求。您可以找到有关使用的 OnStart 和运行方式的作用,在 theApplication 启动进程中的模式与实践指南移动应用程序到云部分的更多信息和指导。

注意

请 OnStart 方法尽量精简的代码。 Azure 不上采取这种方法,完成时间强加任何限制,但作用不能够启动响应发送给它,直到此方法完成的网络请求。

当 OnStart 方法完成后,执行任务的运行方式。在这一点上,该织物控制器能够开始发送请求的作用。 将实际的运行方法创建任务的代码。注意,执行命令的方法可以有效地定义角色实例的生命周期。此方法完成,结构控制器将安排的作用被关闭。

当一个角色关机或再循环,结构控制器可以防止从负载平衡器接收任何更多的传入请求,并提高了停止事件。您可以通过覆盖作用的 onStop 方法捕获这个事件和角色终止前需要进行任何整理起来。

注意

在的 onStop 方法执行的任何操作须在 5 分钟(或者,如果您使用的是本地计算机上的天青模拟器 30 秒)内完成;否则 Azure 结构控制器假定的角色已经停止,并会迫使它停下来。

图 2 示出了一个角色的生命周期,任务和资源,它承载。该任务由运行方法,该方法然后等待任务来完成启动。任务本身,这实现云服务的业务逻辑,可以响应通过天青负载平衡器发布到角色的消息。

图2 - 任务和资源的作用,在Azure云服务的生命周期

在 ComputeResourceConsolidation.Worker 项目 WorkerRole.cs 文件显示了一个如何实现这个模式在 Azure 云服务的例子。

注意: 该 ComputeResourceConsolidation.Worker 项目是 ComputeResourceConsolidation 解决方案,可用于下载本指导意见的一部分。 在运行时被初始化的角色创建所需的取消标记和任务来运行的一个列表中的辅助角色,代码。

public class WorkerRole: RoleEntryPoint  
{  
  // The cancellation token source used to cooperatively cancel running tasks.  
  private readonly CancellationTokenSource cts = new CancellationTokenSource ();  

  // List of tasks running on the role instance.  
  private readonly List<Task> tasks = new List<Task>();  

  // List of worker tasks to run on this role.  
  private readonly List<Func<CancellationToken, Task>> workerTasks    
                        = new List<Func<CancellationToken, Task>>  
    {  
      MyWorkerTask1,  
      MyWorkerTask2  
    };  

  ...  
}  

设置在 MyWorkerTask1 和 MyWorkerTask2 方法来说明如何在同一辅助角色执行不同的任务。下面的代码显示 MyWorkerTask1。这是休眠 30 秒,然后输出一个跟踪消息的简单任务。重复这个过程,直到无限期的任务被取消。在 MyWorkerTask2 代码非常相似。

// A sample worker role task.  
private static async Task MyWorkerTask1(CancellationToken ct)  
{  
  // Fixed interval to wake up and check for work and/or do work.  
  var interval = TimeSpan.FromSeconds(30);  

  try  
  {  
    while (!ct.IsCancellationRequested)  
    {  
      // Wake up and do some background processing if not canceled.  
      // TASK PROCESSING CODE HERE  
      Trace.TraceInformation("Doing Worker Task 1 Work");  

      // Go back to sleep for a period of time unless asked to cancel.  
      // Task.Delay will throw an OperationCanceledException when canceled.  
      await Task.Delay(interval, ct);  
    }  
  }  
  catch (OperationCanceledException)  
  {  
    // Expect this exception to be thrown in normal circumstances or check  
    // the cancellation token. If the role instances are shutting down, a  
    // cancellation request will be signaled.  
    Trace.TraceInformation("Stopping service, cancellation requested");  

    // Re-throw the exception.  
    throw;  
  }  
}  

注意: 通过示例代码示出的方法是一个后台进程的一个常见的实现。在现实世界的应用程序,你可以按照这个结构相同,不同之处在于,你应该把自己的处理逻辑在等待取消请求的循环体。

经过工人的角色已初始化它使用的资源,Run 方法启动两个任务同时,如下图所示。

...  
// RoleEntry Run() is called after OnStart().    
// Returning from Run() will cause a role instance to recycle.  
public override void Run()  
{  
  // Start worker tasks and add them to the task list.  
  foreach (var worker in workerTasks)  
    tasks.Add(worker(cts.Token));  

  Trace.TraceInformation("Worker host tasks started");  
  // The assumption is that all tasks should remain running and not return,   
  // similar to role entry Run() behavior.  
  try  
  {  
    Task.WaitAny(tasks.ToArray());  
  }  
  catch (AggregateException ex)  
  {  
    Trace.TraceError(ex.Message);  

    // If any of the inner exceptions in the aggregate exception   
    // are not cancellation exceptions then re-throw the exception.  
    ex.Handle(innerEx => (innerEx is OperationCanceledException));  
  }  

  // If there was not a cancellation request, stop all tasks and return from Run()  
  // An alternative to cancelling and returning when a task exits would be to   
  // restart the task.  
  if (!cts.IsCancellationRequested)  
  {  
    Trace.TraceInformation("Task returned without cancellation request");  
    Stop(TimeSpan.FromMinutes(5));  
  }  
}  
...  

在该示例中,执行命令方法等待要完成的任务。如果任务被取消,运行方法假定的角色正在关闭,并等待剩下的任务完成(这在终止前等待最多 5 分钟)之前被取消。如果任务失败,由于预期异常,Run 方法将取消该任务。

注意: 需要注意的是,你可以实现 Run 方法更全面的监测和异常处理策略,如重新启动已失败的任务,或者包括代码,使角色停止和启动单个任务。 在以下代码中所示的停止方法时,网络控制器将关闭角色实例(它是从的 onStop 方法调用)被调用。该代码通过取消它优雅地停止每项任务。如果有任何的工作时间超过五分钟就能完成,在 Stop 方法取消处理真正地停止等待和作用被终止。

// Stop running tasks and wait for tasks to complete before returning   
// unless the timeout expires.  
private void Stop(TimeSpan timeout)  
{  
  Trace.TraceInformation("Stop called. Canceling tasks.");  
  // Cancel running tasks.  
  cts.Cancel();  

  Trace.TraceInformation("Waiting for canceled tasks to finish and return");  

  // Wait for all the tasks to complete before returning. Note that the   
  // emulator currently allows 30 seconds and Azure allows five  
  // minutes for processing to complete.  
  try  
  {  
    Task.WaitAll(tasks.ToArray(), timeout);  
  }  
  catch (AggregateException ex)  
  {  
    Trace.TraceError(ex.Message);  

    // If any of the inner exceptions in the aggregate exception   
    // are not cancellation exceptions then re-throw the exception.  
    ex.Handle(innerEx => (innerEx is OperationCanceledException));  
  }  
}