本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Amazon EC2 竞价型实例教程
本教程向您展示如何使用 AWS SDK for .NET 来管理 Amazon EC2 竞价型实例。
概述
竞价型实例使您能够以低于按需价格的价格请求未使用的 Amazon EC2 容量。这可以显著EC2降低处理可能被中断的应用程序的成本。
下面简要概述了如何请求和使用竞价型实例。
-
创建竞价型实例请求,指定您愿意支付的最高价格。
-
请求完成后,像运行任何其他 Amazon EC2 实例一样运行该实例。
-
根据需要运行该实例,然后将其终止,除非 Spot 价格发生变化导致实例终止。
-
在不再需要竞价型实例请求时对其进行清理,这样就不会再创建竞价型实例。
这是对竞价型实例整体层面的概述。要更好地了解竞价型实例,请参阅 Amazon EC2 用户指南中的竞价型实例。
关于本教程
在学习本教程时,您可以使用 AWS SDK for .NET 来执行以下操作:
-
创建竞价型实例请求
-
确定何时执行该竞价型实例请求
-
取消竞价型实例请求
-
终止相关实例
以下各节提供了此示例的片段和其它信息。片段后显示了该示例的完整代码,并且可以按原样构建和运行。
先决条件
有关APIs和先决条件的信息,请参阅父部分 (与亚马逊合作 EC2)。
收集所需内容
要创建竞价型实例请求,您需要一些东西。
-
实例数量和其实例类型。有几种实例类型可供选择。有关更多信息,请参阅亚马逊EC2用户指南中的亚马逊EC2实例类型。另请参阅实例类型详细信息和
实例类型浏览器 。 在本教程中,默认数量为 1。
-
将用于创建实例的 Amazon 系统映像 (AMI)。有关信息AMIs,请参阅《亚马逊EC2用户指南》中的亚马逊系统映像 (AMIs)。具体而言,请参阅查找AMI和共享AMIs。
-
您每小时愿意为每个实例支付的最高价格。您可以在 Amazon 定价页面上查看所有实例类型(按需实例和竞EC2价
型实例)的价格。本教程的默认价格将在后面说明。
-
如果您想远程连接到实例,则需要具有适当配置和资源的安全组。在 Amazon 中与安全组合作 EC2中对此进行了描述,并在启动亚马逊EC2实例中提供了有关收集所需内容和连接到实例的信息。为简单起见,本教程使用了所有新 AWS 账户都拥有的名为 default 的安全组。
有很多方法可以请求 Spot 实例。以下是常见策略:
-
提出请求以确保成本低于按需定价。
-
基于最终的计算值提出请求。
-
提出请求以便尽快获得计算容量。
以下解释参考了 Amazon EC2 用户指南中的竞价型实例定价历史记录。
您需要进行花费数小时或数天的批处理工作。然而,您可以灵活调整启动和结束时间。您希望看到是否以低于按需实例的成本完成。
您可以使用亚马逊EC2控制台或亚马逊查看实例类型的现货价格历史记录EC2API。在您分析了给定可用区内所需实例类型的价格记录之后,您有两种可供选择的方法发出请求:
-
指定在 Spot 价格范围(这仍然低于按需定价)的上限发出请求,预测您单次竞价型实例请求很有可能会达成,并运行足够的连续计算时间来完成此项工作。
-
指定在 Spot 价格范围的下限发出请求,随着时间的推移,通过持久的请求,计划结合多种已启动实例。总计一下,该实例会以较低的总成本、花费很长时间来完成这项工作。
您需要进行数据处理工作。您将会对该工作的结果有一个很好的了解,以便于能够让您知道在计算成本方面它们的价值。
当您分析了实例类型的 Spot 价格历史记录之后,选择一个计算时间成本不高于该工作结果成本的价格。由于 Spot 价格的波动,该价格可能会达到或低于您的请求,所以您要创建一个持久请求,并允许它间歇运行。
您对附加容量有一个无法预料的短期需求,该容量不能通过按需实例获取。当您分析了实例类型的 Spot 价格历史记录之后,您选择高于历史最高价格的价格,以大幅提高完成您请求的可能性,并继续计算,直到完成实例。
收集所需内容并选择策略后,就可以请求竞价型实例了。对于本教程,默认的最高 Spot 实例价格设置为与按需价格相同(本教程为 0.003 美元)。以这种方式设置价格可最大限度地提高请求被执行的机会。
创建竞价型实例请求
以下代码片段向您展示了如何使用之前收集的元素创建竞价型实例请求。
本主题末尾的示例显示了此片段的使用情况。
// // 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,它包含在返回SpotInstanceRequest对象的SpotInstanceRequestId
成员中。
确定您的竞价型实例请求的状态
以下代码片段向您展示了如何获取有关您竞价型实例请求的信息。您可以使用这些信息在代码中做出某些决定,例如是否继续等待竞价型实例请求得到满足。
本主题末尾的示例显示了此片段的使用情况。
// // 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、其状态和状态代码。有关竞价型实例请求状态代码的更多信息,请参阅 Amazon EC2 用户指南中的竞价请求状态。
清理您的竞价型实例请求
当您不再需要请求竞价型实例时,请务必取消任何未处理的请求,以防止这些请求被重新执行。以下代码片段演示了如何取消一个竞价型实例请求。
本主题末尾的示例显示了此片段的使用情况。
// // 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"); } } }
完整代码
以下代码示例调用前面描述的方法来创建和取消竞价型实例请求并终止竞价型实例。
NuGet 包裹:
编程元素:
-
命名空间 Amazon。 EC2
Amazon 上课 EC2Client
班级 InstanceType
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"); } } } } }
额外注意事项
-
运行本教程后,最好登录 Amazon EC2 控制台
,验证竞价型实例请求 是否已取消,竞价型实例 是否已终止。