La AWS SDK for Java versión 1.x entró en modo de mantenimiento el 31 de julio de 2024 y estará disponible el 31 de end-of-support
Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Tutorial: Instancias de spot de Amazon EC2
Información general
Las instancias de spot permiten pujar por capacidad de Amazon Elastic Compute Cloud (Amazon EC2) sin utilizar hasta el 90 % frente al precio de instancia bajo demanda y ejecutar las instancias adquiridas, siempre y cuando su puja sea superior al precio de spot actual. Amazon EC2 cambia periódicamente el precio de spot en función de la oferta y la demanda; los clientes cuyas pujas igualen o superen este precio tendrán acceso a las instancias de spot disponibles. Al igual que las instancias bajo demanda y las instancias reservadas, las instancias de spot proporcionan otra opción para obtener una mayor capacidad de cómputo.
Las instancias de spot pueden reducir de forma significativa los costos de Amazon EC2 del procesamiento por lotes, la investigación científica, el procesamiento de imágenes, la codificación de vídeo, el rastreo web y de datos, el análisis financiero y la realización de pruebas. Además, las instancias de spot le permiten obtener acceso a una gran cantidad de capacidad adicional en aquellas situaciones en las que la necesidad de esa capacidad no es urgente.
Para usar instancias de spot, coloque una solicitud de instancia de spot que especifique el precio máximo que está dispuesto a pagar por hora de instancia; esta es su puja. Si el importe de su puja es mayor que el precio de spot actual, se atenderá su solicitud y sus instancias se ejecutarán hasta que decida terminarlas o hasta que el precio de spot sea mayor que su puja (lo que suceda antes).
Es importante tener en cuenta lo siguiente:
-
Con frecuencia pagará por hora un importe inferior al de su puja. Amazon EC2 ajusta el precio de spot periódicamente a medida que llegan las solicitudes y que cambia la oferta disponible. Todo el mundo paga el mismo precio de spot para ese período independientemente de que su puja fuera más alta. Por lo tanto, puede pagar un importe inferior al de su puja, pero nunca pagará un importe superior al de esta.
-
Si ejecuta instancias de spot y su puja ya no coincide con el precio de spot actual ni lo supera, se terminarán sus instancias. Esto significa que querrá asegurarse de que sus cargas de trabajo y aplicaciones son lo suficientemente flexibles para aprovechar esta oportunista capacidad.
Las instancias de spot funcionan exactamente igual que otras instancias Amazon EC2 mientras se ejecutan y, al igual que otras instancias Amazon EC2, se pueden terminar cuando ya no las necesita. Si termina su instancia, pagará por las horas parciales empleadas (como lo haría en el caso de las instancias bajo demanda o reservadas). Sin embargo, si el precio de spot es superior al importe de su puja y Amazon EC2 termina su instancia, no se le cobrará por las horas de uso parciales.
Este tutorial muestra cómo utilizar AWS SDK for Java para realizar las siguientes tareas.
-
Enviar una solicitud de spot
-
Determinar cuándo se atiende la solicitud de spot
-
Cancelar la solicitud de spot
-
Terminar las instancias asociadas
Requisitos previos
Para utilizar este tutorial, debe tener AWS SDK for Java instalado, así como los requisitos previos de instalación básicos. Para obtener más información, consulte Configuración de AWS SDK for Java.
Paso 1: Configuración de las credenciales
Para empezar a usar este ejemplo de código, debe configurar las credenciales de AWS. Consulte Configuración de credenciales y regiones de AWS para desarrollo para ver instrucciones sobre cómo hacerlo.
nota
Le recomendamos que utilice las credenciales de un usuario de IAM para proporcionar estos valores. Para obtener más información, consulte Inscripción en AWS y creación de un usuario de IAM.
Ahora que ha configurado sus opciones, puede empezar a utilizar el código del ejemplo.
Paso 2: Configuración de un grupo de seguridad
Un grupo de seguridad funciona como un firewall que controla el tráfico permitido de entrada y salida de un grupo de instancias. De forma predeterminada, una instancia se inicia sin ningún grupo de seguridad, lo que significa que se denegará todo el tráfico IP entrante, en cualquier puerto TCP. Por lo tanto, antes de enviar una solicitud de spot, vamos a configurar un grupo de seguridad que permita el tráfico de red necesario. A efectos de este tutorial, vamos a crear un nuevo grupo de seguridad llamado "GettingStarted" que permita el tráfico Secure Shell (SSH) desde la dirección IP en la que se ejecuta su aplicación. Para configurar un nuevo grupo de seguridad, debe incluir o ejecutar el siguiente ejemplo de código, que configura el grupo de seguridad mediante programación.
Después, creamos un objeto cliente AmazonEC2
y un objeto CreateSecurityGroupRequest
con el nombre, "GettingStarted" y una descripción para el grupo de seguridad. A continuación, llamamos a la API ec2.createSecurityGroup
para crear el grupo.
Para habilitar el acceso al grupo, creamos un objeto ipPermission
con el intervalo de direcciones IP establecido en la representación CIDR de la subred del equipo local; el sufijo "/10" en la dirección IP indica la subred de la dirección IP especificada. También configuramos el objeto ipPermission
con el protocolo TCP y el puerto 22 (SSH). El último paso consiste en llamar a ec2.authorizeSecurityGroupIngress
con el nombre de nuestro grupo de seguridad y el objeto ipPermission
.
// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Create a new security group. try { CreateSecurityGroupRequest securityGroupRequest = new CreateSecurityGroupRequest("GettingStartedGroup", "Getting Started Security Group"); ec2.createSecurityGroup(securityGroupRequest); } catch (AmazonServiceException ase) { // Likely this means that the group is already created, so ignore. System.out.println(ase.getMessage()); } String ipAddr = "0.0.0.0/0"; // Get the IP of the current host, so that we can limit the Security // Group by default to the ip range associated with your subnet. try { InetAddress addr = InetAddress.getLocalHost(); // Get IP Address ipAddr = addr.getHostAddress()+"/10"; } catch (UnknownHostException e) { } // Create a range that you would like to populate. ArrayList<String> ipRanges = new ArrayList<String>(); ipRanges.add(ipAddr); // Open up port 22 for TCP traffic to the associated IP // from above (e.g. ssh traffic). ArrayList<IpPermission> ipPermissions = new ArrayList<IpPermission> (); IpPermission ipPermission = new IpPermission(); ipPermission.setIpProtocol("tcp"); ipPermission.setFromPort(new Integer(22)); ipPermission.setToPort(new Integer(22)); ipPermission.setIpRanges(ipRanges); ipPermissions.add(ipPermission); try { // Authorize the ports to the used. AuthorizeSecurityGroupIngressRequest ingressRequest = new AuthorizeSecurityGroupIngressRequest("GettingStartedGroup",ipPermissions); ec2.authorizeSecurityGroupIngress(ingressRequest); } catch (AmazonServiceException ase) { // Ignore because this likely means the zone has // already been authorized. System.out.println(ase.getMessage()); }
Tenga en cuenta que solo necesita ejecutar esta aplicación una vez para crear un nuevo grupo de seguridad.
También puede crear el grupo de seguridad mediante AWS Toolkit for Eclipse. Consulte Administración de grupos de seguridad desde AWS Cost Explorer para obtener más información.
Paso 3: Envío de la solicitud de spot
Para enviar una solicitud de spot, primero es necesario determinar el tipo de instancia, la imagen de máquina de Amazon (AMI) y el precio de puja máximo que desea usar. También debe incluir el grupo de seguridad que hemos configurado anteriormente, de modo que pueda iniciar sesión en la instancia si lo desea.
Hay varios tipos de instancia para elegir; vaya a Tipos de instancias Amazon EC2 para obtener una lista completa. En este tutorial, utilizaremos t1.micro, el tipo de instancia más económica disponible. A continuación, determinaremos el tipo de AMI que desea utilizar. Utilizaremos ami-a9d09ed1, la AMI de Amazon Linux más actualizada disponible cuando escribimos este tutorial. La AMI más reciente puede cambiar con el tiempo, pero siempre puede determinar la última versión de la AMI siguiendo estos pasos:
-
Abra la consola de Amazon EC2
. -
Elija el botón Launch Instance (Lanzar instancia).
-
La primera ventana muestra las AMI disponibles. El ID de AMI aparece al lado del título de cada AMI. También puede utilizar la API
DescribeImages
, pero el uso de este comando queda fuera del alcance de este tutorial.
Existen muchas formas de pujar por instancias de spot; para obtener una descripción general de los diferentes enfoques, vea el vídeo Bidding for Spot Instances
-
Reducir el costo por debajo del precio bajo demanda Tiene una tarea de procesamiento por lotes que tardará en ejecutarse una cantidad determinada de horas o días. Sin embargo, es flexible con respecto a cuándo comienza y finaliza. Desea ver si puede completarla por menos del valor del costo de las instancias bajo demanda. Puede examinar el historial de precios de subasta para tipos de instancia mediante la AWS Management Console o la API de Amazon EC2. Para obtener más información, consulte Historial de precios de instancias de spot. Una vez que haya analizado el historial de precios para su tipo de instancia deseado en una zona de disponibilidad especificada, tendrá dos enfoques alternativos para su puja:
-
Podría pujar en el extremo superior del rango de precios de spot (que aún son inferiores al precio bajo demanda), contando con que lo más probable es que su solicitud de spot puntual se atienda y se ejecute durante un tiempo de computación consecutivo suficiente para completar la tarea.
-
O bien, puede especificar la cantidad que está dispuesto a pagar por las instancias de spot como un porcentaje del precio de la instancia bajo demanda, así como combinar muchas instancias lanzadas a lo largo del tiempo a través de una solicitud persistente. Si se supera el precio especificado, la instancia de spot terminará. (Explicaremos cómo automatizar esta tarea más adelante en este tutorial).
-
-
No pagar un importe superior al valor del resultado Tiene una tarea de procesamiento de datos que ejecutar. Conoce las ventajas de los resultados de la tarea lo suficientemente bien como para saber lo valiosos que son en términos de costos de computación. Una vez que haya analizado el historial de precios de spot para el tipo de instancia, podrá elegir un precio de puja en el que el costo del tiempo de computación no sea superior al valor de los resultados de la tarea. Puede crear una puja persistente y permitir su ejecución intermitente a medida que el precio de spot fluctúa en torno a su puja o por debajo de esta.
-
Adquirir capacidad de computación rápidamente Tiene una necesidad a corto plazo no anticipada de capacidad adicional que no está disponible a través de las instancias bajo demanda. Una vez que haya analizado el historial de precios de spot para el tipo de instancia, podrá pujar por encima del precio histórico más alto para tener mayores probabilidades de que su solicitud se atienda con rapidez y continúe computándose hasta completarse.
Una vez que haya elegido el precio de puja, estará listo para solicitar una instancia de spot. Para los fines de este tutorial, pujaremos por el precio bajo demanda (0,03 USD) para maximizar las posibilidades de que se atienda la puja. Puede determinar los tipos de instancias disponibles y los precios bajo demanda para instancias yendo a la página de precios de Amazon EC2. Cuando una instancia de spot está en ejecución, paga el precio de spot vigente durante el período de tiempo en que se ejecutan las instancias. Amazon EC2 define los precios de las instancias de spot y estos se ajustan gradualmente en función de las tendencias a largo plazo de la oferta y la demanda de capacidad de este tipo de instancia. También puede especificar el importe que está dispuesto a pagar por una instancia de spot como porcentaje del precio de la instancia bajo demanda. Para solicitar una instancia de spot, solo tiene que crear su solicitud con los parámetros que eligió anteriormente. Comencemos creando un objeto RequestSpotInstanceRequest
. El objeto de la solicitud requiere el número de instancias que desea para comenzar y el precio de puja. Además, necesita establecer LaunchSpecification
para la solicitud, que incluye el tipo de instancia, el ID de la AMI y el grupo de seguridad que desea utilizar. Una vez rellenada la solicitud, llama al método requestSpotInstances
en el objeto AmazonEC2Client
. En el siguiente ejemplo se muestra cómo solicitar una instancia de spot.
// Create the AmazonEC2 client so we can call various APIs. AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient(); // Initializes a Spot Instance Request RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest(); // Request 1 x t1.micro instance with a bid price of $0.03. requestRequest.setSpotPrice("0.03"); requestRequest.setInstanceCount(Integer.valueOf(1)); // Setup the specifications of the launch. This includes the // instance type (e.g. t1.micro) and the latest Amazon Linux // AMI id available. Note, you should always use the latest // Amazon Linux AMI id or another of your choosing. LaunchSpecification launchSpecification = new LaunchSpecification(); launchSpecification.setImageId("ami-a9d09ed1"); launchSpecification.setInstanceType(InstanceType.T1Micro); // Add the security group to the request. ArrayList<String> securityGroups = new ArrayList<String>(); securityGroups.add("GettingStartedGroup"); launchSpecification.setSecurityGroups(securityGroups); // Add the launch specifications to the request. requestRequest.setLaunchSpecification(launchSpecification); // Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);
Al ejecutarse este código se lanzará una nueva solicitud de instancia de spot. Hay otras opciones que puede usar para configurar las solicitudes de spot. Para obtener más información, consulte Tutorial: Administración avanzada de solicitudes de spot de Amazon EC2 o la clase RequestSpotInstances en la Referencia de la API de AWS SDK for Java.
nota
Se le cobrará por las instancias de spot que se de verdad se lancen, de modo que asegúrese de cancelar cualquier solicitud y terminar las instancias que lance para reducir las tarifas asociadas.
Paso 4: Determinación del estado de la solicitud de spot
A continuación, queremos crear código para esperar hasta que la solicitud de spot alcance el estado "activo" antes de continuar con el último paso. Para determinar el estado de nuestra solicitud de spot, usamos el método describeSpotInstanceRequests para obtener el estado del ID de solicitud de spot que deseamos monitorizar.
El ID de solicitud creado en el paso 2 se inserta en la respuesta a nuestra solicitud requestSpotInstances
. El siguiente ejemplo muestra cómo obtener los ID de solicitud de la respuesta requestSpotInstances
y utilizarlos para rellenar una ArrayList
.
// Call the RequestSpotInstance API. RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest); List<SpotInstanceRequest> requestResponses = requestResult.getSpotInstanceRequests(); // Setup an arraylist to collect all of the request ids we want to // watch hit the running state. ArrayList<String> spotInstanceRequestIds = new ArrayList<String>(); // Add all of the request ids to the hashset, so we can determine when they hit the // active state. for (SpotInstanceRequest requestResponse : requestResponses) { System.out.println("Created Spot Request: "+requestResponse.getSpotInstanceRequestId()); spotInstanceRequestIds.add(requestResponse.getSpotInstanceRequestId()); }
Para monitorizar su ID de solicitud, llame al método describeSpotInstanceRequests
para determinar el estado de la solicitud. A continuación, recorra en bucle la solicitud hasta que deje de tener el estado "abierto". Tenga en cuenta que buscamos un estado distinto de "abierto" en lugar de, por ejemplo, un estado "activo", porque la solicitud podría pasar directamente al estado "cerrado" si surgiera algún problema con los argumentos de la solicitud. El siguiente ejemplo de código proporciona los detalles de cómo realizar esta tarea.
// Create a variable that will track whether there are any // requests still in the open state. boolean anyOpen; do { // Create the describeRequest object with all of the request ids // to monitor (e.g. that we started). DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds); // Initialize the anyOpen variable to false - which assumes there // are no requests open unless we find one that is still open. anyOpen=false; try { // Retrieve all of the requests we want to monitor. DescribeSpotInstanceRequestsResult describeResult = ec2.describeSpotInstanceRequests(describeRequest); List<SpotInstanceRequest> describeResponses = describeResult.getSpotInstanceRequests(); // Look through each request and determine if they are all in // the active state. for (SpotInstanceRequest describeResponse : describeResponses) { // If the state is open, it hasn't changed since we attempted // to request it. There is the potential for it to transition // almost immediately to closed or cancelled so we compare // against open instead of active. if (describeResponse.getState().equals("open")) { anyOpen = true; break; } } } catch (AmazonServiceException e) { // If we have an exception, ensure we don't break out of // the loop. This prevents the scenario where there was // blip on the wire. anyOpen = true; } try { // Sleep for 60 seconds. Thread.sleep(60*1000); } catch (Exception e) { // Do nothing because it woke up early. } } while (anyOpen);
Después de ejecutar este código, su solicitud de instancia de spot se habrá completado o habrá producido un error que se mostrará en la pantalla. En cualquier caso, podemos continuar con el siguiente paso para limpiar todas las solicitudes activas y terminar todas las instancias en ejecución.
Paso 5: Limpieza de las instancias y solicitudes de spot
Por último, tenemos que limpiar nuestras solicitudes e instancias. Esto es importante tanto para cancelar cualquier solicitud pendiente como para terminar cualquier instancia. Las instancias no terminarán con solo cancelarse las solicitudes, lo que significa que se le seguirá cobrando por ellas. Si termina las instancias, es posible que se cancelen las solicitudes de spot, pero hay algunos escenarios (por ejemplo, si usa pujas persistentes), donde terminar las instancias no es suficiente para evitar que la solicitud vuelva a atenderse. Por lo tanto, se recomienda tanto cancelar cualquier puja activa como terminar cualquier instancia en ejecución.
En el siguiente código se muestra cómo cancelar las solicitudes.
try { // Cancel requests. CancelSpotInstanceRequestsRequest cancelRequest = new CancelSpotInstanceRequestsRequest(spotInstanceRequestIds); ec2.cancelSpotInstanceRequests(cancelRequest); } catch (AmazonServiceException e) { // Write out any exceptions that may have occurred. System.out.println("Error cancelling instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }
Para terminar todas las instancias pendientes, necesitará el ID de la instancia asociada a la solicitud que las inició. El siguiente ejemplo se basa en el código original de monitorización de instancias en el que se ha añadido una ArrayList
en la que almacenamos los ID de instancia asociados a la respuesta describeInstance
.
// Create a variable that will track whether there are any requests // still in the open state. boolean anyOpen; // Initialize variables. ArrayList<String> instanceIds = new ArrayList<String>(); do { // Create the describeRequest with all of the request ids to // monitor (e.g. that we started). DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest(); describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds); // Initialize the anyOpen variable to false, which assumes there // are no requests open unless we find one that is still open. anyOpen = false; try { // Retrieve all of the requests we want to monitor. DescribeSpotInstanceRequestsResult describeResult = ec2.describeSpotInstanceRequests(describeRequest); List<SpotInstanceRequest> describeResponses = describeResult.getSpotInstanceRequests(); // Look through each request and determine if they are all // in the active state. for (SpotInstanceRequest describeResponse : describeResponses) { // If the state is open, it hasn't changed since we // attempted to request it. There is the potential for // it to transition almost immediately to closed or // cancelled so we compare against open instead of active. if (describeResponse.getState().equals("open")) { anyOpen = true; break; } // Add the instance id to the list we will // eventually terminate. instanceIds.add(describeResponse.getInstanceId()); } } catch (AmazonServiceException e) { // If we have an exception, ensure we don't break out // of the loop. This prevents the scenario where there // was blip on the wire. anyOpen = true; } try { // Sleep for 60 seconds. Thread.sleep(60*1000); } catch (Exception e) { // Do nothing because it woke up early. } } while (anyOpen);
Usando los ID de instancia almacenados en ArrayList
, termine todas las instancias en ejecución con el siguiente fragmento de código.
try { // Terminate instances. TerminateInstancesRequest terminateRequest = new TerminateInstancesRequest(instanceIds); ec2.terminateInstances(terminateRequest); } catch (AmazonServiceException e) { // Write out any exceptions that may have occurred. System.out.println("Error terminating instances"); System.out.println("Caught Exception: " + e.getMessage()); System.out.println("Reponse Status Code: " + e.getStatusCode()); System.out.println("Error Code: " + e.getErrorCode()); System.out.println("Request ID: " + e.getRequestId()); }
Operación conjunta
Para realizar todas estas operaciones a la vez, ofrecemos un enfoque más orientado a objetos, que combina los pasos mostrados: inicializar el cliente de EC2, enviar la solicitud de spot, determinar el momento en el que las solicitudes de spot ya no tienen el estado abierto y limpiar todas las solicitudes de spot pendientes y las instancias asociadas. Creamos una clase llamada Requests
que realiza estas acciones.
También creamos una clase GettingStartedApp
, que tiene un método principal donde realizamos las llamadas a funciones de alto nivel. En concreto, inicializamos el objeto Requests
descrito anteriormente. Enviamos la solicitud de instancia de spot. A continuación, esperamos a que la solicitud de spot alcance el estado "activo". Por último, limpiamos las solicitudes y las instancias.
El código fuente completo de este ejemplo se puede consultar o descargar en GitHub
¡Enhorabuena! Ha completado el tutorial de introducción al desarrollo de software de instancias de spot con AWS SDK for Java.
Pasos siguientes
Continúe con el Tutorial: Administración avanzada de solicitudes de spot de Amazon EC2.