本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Amazon EC2 Spot 实例教程
本教程向您演示如何使用Amazon SDK for .NET管理 AAmazon EC2 Spot 实例。
概览
Spot 实例使您能够以低于按需价格请求未使用的 Amazon EC2 容量。这可以显著降低可能中断的应用程序的 EC2 成本。
下面简要概述了如何请求和使用 Spot 实例的简要概述了如何请求和使用 Spot 实例的。
-
创建一个 Spot 实例请求,指定您愿意支付的最高价格。
-
完成请求后,像运行任何其他 Amazon EC2 实例一样运行该实例。
-
随心所欲地运行实例,然后终止它,除非Spot 价格更改会导致您的实例终止。
-
在您不再需要竞价型实例请求时将其清除,这样就不再创建竞价型实例了。
这是竞价型实例的高级概述。您可以在《竞价型实例》中阅读有关竞价型实例的信息,从而更好地了解它们适用于 Linux 实例的 Amazon EC2;或者适用于 Windows 实例的Amazon EC2 用户指南.
关于本教程
在您学习本教程时,您将使用Amazon SDK for .NET执行以下操作:
-
创建竞价型实例请求
-
判定何时执行该 Spot 实例请求
-
取消竞价型实例请求
-
终止相关实例
以下部分提供了此示例的片段和其他信息。这些区域有:示例的完整代码显示在代码片段之后,可以按原样构建和运行。
先决条件
有关 API 和先决条件的信息,请参阅父部分 (使用 Amazon EC2)。
收集你需要的东西
要创建竞价型实例请求,您需要执行以下操作。
-
实例的数量及其实例类型。有几个实例类型可供选择,您可以在适用于 Linux 实例的 Amazon EC2;或者适用于 Windows 实例的Amazon EC2 用户指南. 本教程的默认数字为 1。
-
将用于创建实例的 Amazon 系统映像 (AMI)。有关 AMI 的信息,请参阅适用于 Linux 实例的 Amazon EC2;或者适用于 Windows 实例的Amazon EC2 用户指南. 例如,请阅读有关共享 AMI 的信息适用于 Linux 实例的 Amazon EC2;或者适用于 Windows 实例的Amazon EC2 用户指南.
-
您每小时愿意为支付的最高价格。您可以在上提供了所有实例类型(按需实例和 Spot 实例)的价格Amazon EC2 定价页面
. 本教程的默认价格将在后面解释。
-
如果您想远程连接到实例,请使用具有相应配置和资源的安全组。中介绍了使用 Amazon EC2 中的安全组以及本主题末尾的末尾收集你需要的东西和连接到实例在启动 Amazon EC2 实例. 为简单起见,本教程使用名为的安全组默认类Amazon账户有。
有很多方法可以请求 Spot 实例。以下是常见的策略:
-
提出价格肯定低于按需定价的请求。
-
根据生成的计算值发出请求。
-
进行请求以便尽快获得计算容量。
以下解释引用了中的现货价格历史记录适用于 Linux 实例的 Amazon EC2;或者适用于 Windows 实例的Amazon EC2 用户指南.
您需要进行花费数小时或数天的批处理工作。然而,您可以灵活调整启动和结束时间。您希望看到是否以低于按需实例的成本完成。
您可以通过使用 Amazon EC2 控制台或 Amazon EC2 API 来检查各个类型实例的 Spot 价格历史记录。在您分析了给定可用区内所需实例类型的价格记录之后,您有两种可供选择的方法发出请求:
-
指定在 Spot 价格范围(这仍然低于按需定价)的上端发出请求,预测您单次 Spot 实例请求很有可能会达成,并运行足够的连续计算时间来完成此项工作。
-
指定在 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,它包含在SpotInstanceRequestId
返回者的成员SpotInstanceRequest对象。
确定您的竞价型实例请求的状态
以下片段向您展示如何获取有关您的竞价型实例请求的信息。您可以使用该信息在代码中做出某些决定,例如是否继续等待竞价型实例请求完成。
示例本主题末的末尾显示了正在使用的这段片段。
// // 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 实例的 Amazon EC2;或者适用于 Windows 实例的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); }
清除您的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"); } } }
完成示例
以下代码示例调用前面描述的方法来创建和取消竞价型实例请求并终止竞价型实例。
NuGet 软件包:
编程元素:
-
命名空间Amazon.ec2
Class亚马逊 EC2Client
ClassInstanceType
-
命名空间Amazon.ec2.model
ClassCancelSpotInstanceRequestsRequest
ClassDescribeSpotInstanceRequestsRequest
ClassDescribeSpotInstanceRequestsResponse
ClassInstanceStateChange
ClassLaunchSpecification
ClassRequestSpotInstancesRequest
ClassRequestSpotInstancesResponse
ClassSpotInstanceRequest
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 控制台
以进行确认Spot 实例请求 已取消,并且Spot 实例 已被终止。