Amazon EC2 Spot 实例教程 - Amazon SDK for .NET
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

是否要将 .NET 应用程序部署到Amazon通过几个简单点击即可? 尝试我们的新.NET CLI 工具为了简化部署体验!阅读我们的博客帖子然后提交反馈GitHub

有关更多信息,请参阅部署工具

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Amazon EC2 Spot 实例教程

本教程向您演示如何使用Amazon SDK for .NET以管理 Amazon EC2 Spot 实例。

Overview

您可以请求未使用的 Amazon EC2 容量,以低于按需价格提出。这可以显著降低可能中断的应用程序的 EC2 成本。

下面简要概述了如何请求和使用 Spot 实例。

  1. 创建 Spot 实例请求,指定您愿意支付的最高价格。

  2. 当请求完成后,请像运行任何其他 Amazon EC2 实例一样运行该实例。

  3. 只要你想运行该实例,然后终止它,除非Spot 价格更改以便实例为您终止。

  4. 当您不再需要竞价型实例请求时清理它,以便不再创建竞价型实例。

这是对竞价型实例的非常高层次的概述。您可以通过阅读竞价型实例中的有关竞价型实例的更好地了解它们Linux 的 EC2 用户指南或者适用于 Windows 的 EC2 用户指南.

关于本教程

在遵循本教程时,您将使用Amazon SDK for .NET执行以下操作:

  • 创建 Spot 实例请求

  • 确定何时执行 Spot 实例请求

  • 取消 Spot 实例请求

  • 终止相关实例

以下各节提供了本示例的代码片段和其他信息。这些区域有:例子的完整代码显示在片段之后,可以按原样构建和运行。

Prerequisites

有关 API 和先决条件的信息,请参阅父节 (使用 Amazon EC2)。

收集你需要的东西

要创建 Spot 实例请求,需要几个东西。

  • 您愿意为实例小时支付的最高价格。您可以在Amazon EC2 定价页面. 稍后将解释本教程的默认价格。

有很多方法可以请求 Spot 实例。以下是常见的策略:

  • 提出的成本肯定低于按需定价的请求。

  • 基于生成的计算值提出请求。

  • 提出请求以便尽快获得计算能力。

以下解释参考了中的竞价价格历史记录Linux 的 EC2 用户指南或者适用于 Windows 的 EC2 用户指南.

您需要进行花费数小时或数天的批处理工作。然而,您可以灵活调整启动和结束时间。您希望看到是否以低于按需实例的成本完成。

您可以通过使用 Amazon EC2 控制台或 Amazon EC2 API 来检查各个类型实例的 Spot 价格历史记录。在您分析了给定可用区内所需实例类型的价格记录之后,您有两种可供选择的方法发出请求:

  • 指定在 Spot 价格范围(这仍然低于按需定价)的上限发出请求,预测您单次 Spot 实例请求很有可能会达成,并运行足够的连续计算时间来完成此项工作。

  • 指定在 Spot 价格范围的下限发出请求,随着时间的推移,通过持久的请求,计划结合多种已启动实例。总计一下,该实例会以较低的总成本、花费很长时间来完成这项工作。

您需要进行数据处理工作。您对该工作结果的价值有一个很好的了解,以便于能够让您知道在计算成本方面它们的价值。

当您分析了实例类型的 Spot 价格历史记录之后,选择一个计算时间成本不高于该工作结果成本的价格。由于 Spot 价格的波动,该价格可能会达到或低于您的请求,所以您要创建一个持久请求,并允许它间歇运行。

您对附加容量有一个无法预料的短期需求,该容量不能通过按需实例获取。当您分析了实例类型的 Spot 价格历史记录之后,选择高于历史最高价格的价格,以大幅提高完成您请求的可能性,并继续计算,直到完成实例。

当您收集了所需内容并选择策略之后,您就可以请求一个 Spot 实例了。对于本教程,默认的最高 Spot 实例价格设置为与按需价格相同(本教程为 0.003 美元)。以这种方式设置价格可最大限度地提高请求被执行的机会。

创建 Spot 实例请求

以下代码段向您展示了如何使用之前收集的元素创建竞价型实例请求。

这个示例本主题末尾显示了这个片段正在使用中。

// // Method to create a Spot Instance request private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest( IAmazonEC2 ec2Client, string amiId, string securityGroupName, InstanceType instanceType, string spotPrice, int instanceCount) { var launchSpecification = new LaunchSpecification{ ImageId = amiId, InstanceType = instanceType }; launchSpecification.SecurityGroups.Add(securityGroupName); var request = new RequestSpotInstancesRequest{ SpotPrice = spotPrice, InstanceCount = instanceCount, LaunchSpecification = launchSpecification }; RequestSpotInstancesResponse result = await ec2Client.RequestSpotInstancesAsync(request); return result.SpotInstanceRequests[0]; }

此方法返回的重要值是竞价型实例请求 ID,该 ID 包含在SpotInstanceRequestId返回的成员SpotInstanceRequest对象。

注意

您将为启动的任何竞价型实例收取费用。为了避免不必要的成本,一定要取消任何请求终止任何实例.

确定您的 Spot 实例请求的状态

以下代码段向您展示了如何获取有关竞价型实例请求的信息。您可以使用该信息在代码中做出某些决策,例如是否继续等待竞价型实例请求得到满足。

这个示例本主题末尾显示了这个片段正在使用中。

// // Method to get information about a Spot Instance request, including the status, // instance ID, etc. // It gets the information for a specific request (as opposed to all requests). private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); return describeResponse.SpotInstanceRequests[0]; }

该方法返回有关竞价型实例请求的信息,例如实例 ID、状态和状态码。您可以在Linux 的 EC2 用户指南或者适用于 Windows 的 EC2 用户指南.

清除您的 Spot 实例请求

当您不再需要请求竞价型实例时,重要的是要取消任何未完成的请求,以防止这些请求重新执行。以下代码段显示了如何取消 Spot 实例请求。

这个示例本主题末尾显示了这个片段正在使用中。

// // Method to cancel a Spot Instance request private static async Task CancelSpotInstanceRequest( IAmazonEC2 ec2Client, string requestId) { var cancelRequest = new CancelSpotInstanceRequestsRequest(); cancelRequest.SpotInstanceRequestIds.Add(requestId); await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest); }

清除您的 Spot 实例

为避免不必要的成本,您必须终止从 Spot 实例请求启动的所有实例;简要取消 Spot 实例请求不会终止您的实例,这意味着您需要继续为它们支付费用。下面的代码段演示了如何在获取活动 Spot 实例的实例标识符之后终止实例。

这个示例本主题末尾显示了这个片段正在使用中。

// // Method to terminate a Spot Instance private static async Task TerminateSpotInstance( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); // Retrieve the Spot Instance request to check for running instances. DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); // If there are any running instances, terminate them if( (describeResponse.SpotInstanceRequests[0].Status.Code == "request-canceled-and-instance-running") || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active)) { TerminateInstancesResponse response = await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{ InstanceIds = new List<string>(){ describeResponse.SpotInstanceRequests[0].InstanceId } }); foreach (InstanceStateChange item in response.TerminatingInstances) { Console.WriteLine($"\n Terminated instance: {item.InstanceId}"); Console.WriteLine($" Instance state: {item.CurrentState.Name}\n"); } } }

代码完成

以下代码示例调用前面描述的方法来创建和取消竞价型实例请求并终止竞价型实例。

using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using Amazon.EC2; using Amazon.EC2.Model; namespace EC2SpotInstanceRequests { class Program { static async Task Main(string[] args) { // Some default values. // These could be made into command-line arguments instead. var instanceType = InstanceType.T1Micro; string securityGroupName = "default"; string spotPrice = "0.003"; int instanceCount = 1; // Parse the command line arguments if((args.Length != 1) || (!args[0].StartsWith("ami-"))) { Console.WriteLine("\nUsage: EC2SpotInstanceRequests ami"); Console.WriteLine(" ami: the Amazon Machine Image to use for the Spot Instances."); return; } // Create the Amazon EC2 client. var ec2Client = new AmazonEC2Client(); // Create the Spot Instance request and record its ID Console.WriteLine("\nCreating spot instance request..."); var req = await CreateSpotInstanceRequest( ec2Client, args[0], securityGroupName, instanceType, spotPrice, instanceCount); string requestId = req.SpotInstanceRequestId; // Wait for an EC2 Spot Instance to become active Console.WriteLine( $"Waiting for Spot Instance request with ID {requestId} to become active..."); int wait = 1; var start = DateTime.Now; while(true) { Console.Write("."); // Get and check the status to see if the request has been fulfilled. var requestInfo = await GetSpotInstanceRequestInfo(ec2Client, requestId); if(requestInfo.Status.Code == "fulfilled") { Console.WriteLine($"\nSpot Instance request {requestId} " + $"has been fulfilled by instance {requestInfo.InstanceId}.\n"); break; } // Wait a bit and try again, longer each time (1, 2, 4, ...) Thread.Sleep(wait); wait = wait * 2; } // Show the user how long it took to fulfill the Spot Instance request. TimeSpan span = DateTime.Now.Subtract(start); Console.WriteLine($"That took {span.TotalMilliseconds} milliseconds"); // Perform actions here as needed. // For this example, simply wait for the user to hit a key. // That gives them a chance to look at the EC2 console to see // the running instance if they want to. Console.WriteLine("Press any key to start the cleanup..."); Console.ReadKey(true); // Cancel the request. // Do this first to make sure that the request can't be re-fulfilled // once the Spot Instance has been terminated. Console.WriteLine("Canceling Spot Instance request..."); await CancelSpotInstanceRequest(ec2Client, requestId); // Terminate the Spot Instance that's running. Console.WriteLine("Terminating the running Spot Instance..."); await TerminateSpotInstance(ec2Client, requestId); Console.WriteLine("Done. Press any key to exit..."); Console.ReadKey(true); } // // Method to create a Spot Instance request private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest( IAmazonEC2 ec2Client, string amiId, string securityGroupName, InstanceType instanceType, string spotPrice, int instanceCount) { var launchSpecification = new LaunchSpecification{ ImageId = amiId, InstanceType = instanceType }; launchSpecification.SecurityGroups.Add(securityGroupName); var request = new RequestSpotInstancesRequest{ SpotPrice = spotPrice, InstanceCount = instanceCount, LaunchSpecification = launchSpecification }; RequestSpotInstancesResponse result = await ec2Client.RequestSpotInstancesAsync(request); return result.SpotInstanceRequests[0]; } // // Method to get information about a Spot Instance request, including the status, // instance ID, etc. // It gets the information for a specific request (as opposed to all requests). private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); return describeResponse.SpotInstanceRequests[0]; } // // Method to cancel a Spot Instance request private static async Task CancelSpotInstanceRequest( IAmazonEC2 ec2Client, string requestId) { var cancelRequest = new CancelSpotInstanceRequestsRequest(); cancelRequest.SpotInstanceRequestIds.Add(requestId); await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest); } // // Method to terminate a Spot Instance private static async Task TerminateSpotInstance( IAmazonEC2 ec2Client, string requestId) { var describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.SpotInstanceRequestIds.Add(requestId); // Retrieve the Spot Instance request to check for running instances. DescribeSpotInstanceRequestsResponse describeResponse = await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest); // If there are any running instances, terminate them if( (describeResponse.SpotInstanceRequests[0].Status.Code == "request-canceled-and-instance-running") || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active)) { TerminateInstancesResponse response = await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{ InstanceIds = new List<string>(){ describeResponse.SpotInstanceRequests[0].InstanceId } }); foreach (InstanceStateChange item in response.TerminatingInstances) { Console.WriteLine($"\n Terminated instance: {item.InstanceId}"); Console.WriteLine($" Instance state: {item.CurrentState.Name}\n"); } } } } }

其他注意事项