This topic describes how to use Alibaba Cloud Elastic Compute Service (ECS) SDK for Java to call the DescribeAvailableResource operation to query available resources, call the DescribeSpotPriceHistory operation to query the historical prices of preemptible instances, and call the CreateInstance operation to create a preemptible instance.

Prerequisites

  • The version of Alibaba Cloud ECS SDK for Java is V4.2.0 or later.
  • The image to be used to create a preemptible instance contains all the environment dependencies that are required to run the instance. We recommend that you use a custom image to create a preemptible instance to ensure that the instance can process business data. In this example, the image ID is m-bp146shijn7hujkui9***.
  • Call the DescribeRegions operation to query the region where you want to create ECS instances. In this example, the region is cn-hangzhou.
  • Call the DescribeInstanceTypes operation to query the instance type that you want to select. In this example, the instance type is ecs.g5.large. For more information, see Instance families.

Background information

Preemptible instances help you build cost-effective solutions to process business data. When you create a preemptible instance, you can set a maximum hourly price to bid for a specified instance type. If your price is higher than the market price at purchase, your instance is created and billed at the market price. Preemptible instances are used to control computing costs and are suitable for stateless applications. For more information, see Overview.

Procedure

  1. Encapsulate an ApiCaller.java class to initialize a profile and a client and add the exception handling logic.
    public class ApiCaller {
        IClientProfile profile;
        IAcsClient client;
    
        public ApiCaller() {
            profile = DefaultProfile.getProfile("cn-hangzhou", AKSUtil.accessKeyId, AKSUtil.accessKeySecret);
            client = new DefaultAcsClient(profile);
        }
    
        public  <T extends AcsResponse> T doAction(AcsRequest<T> var1) {
            try {
                return  client.getAcsResponse(var1);
            } catch (ServerException e) {
                e.printStackTrace();
            } catch (ClientException e) {
                System.out.println("ErrCode:" + e.getErrCode());
                System.out.println("ErrMsg:" + e.getErrMsg());
                System.out.println("RequestId:" + e.getRequestId());
            }
            return null;
        }
     }
  2. Call the DescribeAvailableResource operation to query the instance types that are available in the specified region.
    public class DescribeAvailableResourceSample {
    
        public static void main(String[] args) {
    
            ApiCaller caller = new ApiCaller();
            DescribeAvailableResourceRequest request = new DescribeAvailableResourceRequest();
            // Call the DescribeRegionsRequest operation to obtain the region ID. 
            request.setRegionId("cn-hangzhou");
            request.setDestinationResource("InstanceType");
            // Required. Set the InstanceChargeType parameter to PostPaid. 
            request.setInstanceChargeType("PostPaid");
            // Required. Set the SpotStrategy parameter for the preemptible instance. 
            request.setSpotStrategy("SpotAsPriceGo");
            // Specify the zone in which to create the instance. If you do not specify a zone ID, all zones in which preemptible instances can be created are queried. 
            request.setZoneId("cn-hangzhou-h");
            // Specify the instance type. If you do not specify an instance type, all instance types that can be selected to create preemptible instances are queried. 
            request.setInstanceType("ecs.g5.large");
            request.setSystemDiskCategory("cloud_ssd");
            request.setNetworkCategory("vpc");
    
            DescribeAvailableResourceResponse response = caller.doAction(request);
            System.out.println(JSON.toJSONString(response));
        }
    }
    Sample success responses:
    {
        "RequestId": "D8491D5E-AB8A-4E22-BDB4-EEEE1F1C8241",
        "AvailableZones": {
            "AvailableZone": [
                {
                    "Status": "Available",
                    "RegionId": "cn-hangzhou",
                    "AvailableResources": {
                        "AvailableResource": [
                            {
                                "Type": "InstanceType",
                                "SupportedResources": {
                                    "SupportedResource": [
                                        {
                                            "Status": "Available",
                                            "Value": "ecs.g5.large",
                                            "StatusCategory": "WithStock"
                                        }
                                    ]
                                }
                            }
                        ]
                    },
                    "ZoneId": "cn-hangzhou-h",
                    "StatusCategory": "WithStock"
                }
            ]
        }
    }
  3. Optional. Call the DescribeSpotPriceHistory operation to query the historical prices of preemptible instances.
    Note The DescribeSpotPriceHistory operation allows you to obtain the historical prices for up to the last 30 days.
    public class DescribeSpotPriceHistorySample {
    
        public static void main(String[] args) {
    
            ApiCaller caller = new ApiCaller();
            List<DescribeSpotPriceHistoryResponse.SpotPriceType> result = new ArrayList<DescribeSpotPriceHistoryResponse.SpotPriceType>();
            int offset = 0;
            while (true) {
                DescribeSpotPriceHistoryRequest request = new DescribeSpotPriceHistoryRequest();
                // Required. Specify the region ID. 
                request.setRegionId("cn-hangzhou");
                // Required. Specify the zone ID. 
                request.setZoneId("cn-hangzhou-b");
                // Required. Specify the instance type. 
                request.setInstanceType("ecs.g5.large");
                // Required. Specify the network type. 
                request.setNetworkType("vpc");
                // Optional. Specify the start of the time range to query. By default, the time range is three hours. 
                // request.setStartTime("2017-09-20T08:45:08Z");
                // Optional. Specify the end of the time range to query. If the end time is not specified, the default end time is the current time. 
                // request.setEndTime("2017-09-28T08:45:08Z");
                request.setOffset(offset);
                DescribeSpotPriceHistoryResponse response = caller.doAction(request);
                if (response != null && response.getSpotPrices() != null) {
                    result.addAll(response.getSpotPrices());
                }
                if (response.getNextOffset() == null || response.getNextOffset() == 0) {
                    break;
                } else {
                    offset = response.getNextOffset();
                }
            }
            if (!result.isEmpty()) {
                for (DescribeSpotPriceHistoryResponse.SpotPriceType spotPriceType : result) {
                    System.out.println(spotPriceType.getTimestamp() + "--->spotPrice:" + spotPriceType.getSpotPrice() + "---->originPrice:" + spotPriceType.getOriginPrice());
                }
                System.out.println(result.size());
            } else {
            }
    
        }
    
    }
    Sample success responses:
    2017-09-26T06:28:55Z--->spotPrice:0.24---->originPrice:1.2
    2017-09-26T14:00:00Z--->spotPrice:0.36---->originPrice:1.2
    2017-09-26T15:00:00Z--->spotPrice:0.24---->originPrice:1.2
    2017-09-27T14:00:00Z--->spotPrice:0.36---->originPrice:1.2
    2017-09-27T15:00:00Z--->spotPrice:0.24---->originPrice:1.2
    2017-09-28T14:00:00Z--->spotPrice:0.36---->originPrice:1.2
    2017-09-28T15:00:00Z--->spotPrice:0.24---->originPrice:1.2
    2017-09-29T06:28:55Z--->spotPrice:0.24---->originPrice:1.2
  4. Call the CreateInstance operation to create a preemptible instance.

    To create multiple preemptible instances at a time, you can call the RunInstances operation. For more information, see Batch create ECS instances.

    public class CreateInstanceSample {
    
        public static void main(String[] args) {
    
            ApiCaller caller = new ApiCaller();
    
            CreateInstanceRequest request = new CreateInstanceRequest();
            // Specify the region ID. 
            request.setRegionId("cn-hangzhou");
            // Specify the zone ID. 
            request.setZoneId("cn-hangzhou-h"); 
            // Specify the ID of the security group. 
            request.setSecurityGroupId("sg-bp11nhf94ivkdxwb2***");
            // Specify the image ID. We recommend that you use a custom image to create a preemptible instance. 
            request.setImageId("m-bp146shijn7hujkui9***");
            // Specify the ID of the vSwitch that is in the same virtual private cloud (VPC) as the security group. 
            request.setVSwitchId("vsw-bp164cyonthfudn9kj***");
    
            // Specify the instance type that you want to purchase. 
            request.setInstanceType("ecs.g5.large"); 
    
            // Specify the category of the system disk. Valid values: cloud_essd, cloud_ssd, cloud_efficiency, and cloud. 
            request.setSystemDiskCategory("cloud_ssd");
            request.setSystemDiskSize(40);
    
            // Required. Set the InstanceChargeType parameter to PostPaid. 
            request.setInstanceChargeType("PostPaid");
            // Set the SpotStrategy parameter to SpotWithPriceLimit. You can also set the SpotStrategy parameter to SpotAsPriceGo to use the system-provided pay-as-you-go price as the maximum bidding price. In this case, you do not need to specify the SpotPriceLimit parameter. 
            request.setSpotStrategy("SpotWithPriceLimit");
            // If you set the SpotStrategy parameter to SpotWithPriceLimit, the maximum bidding price that you specify must be higher than the market price at purchase. Otherwise, the instance cannot be created. 
            request.setSpotPriceLimit(0.25F);
    
            // Set the Amount parameter to 2 to create two preemptible instances. By default, only one preemptible instance is created if this parameter is not set. 
            // request.setAmount(2);
    
            CreateInstanceResponse response = caller.doAction(request);
            System.out.println(response.getInstanceId());
    
        }
    }
  5. Query the recycle time of the preemptible instance.
    Note Preemptible instances can be recycled. We recommend that you configure a service interruption solution or a load balancing mechanism when you create a preemptible instance. This can avoid problems if the preemptible instance is released.
    • Method 1: Run the following command in the operating system of the preemptible instance to query the recycle time of the instance based on the instance metadata:
      curl http://100.100.100.200/latest/meta-data/instance/spot/termination-time
      Note If the command output is empty, you can continue to use the preemptible instance. If the command output contains a point in time that follows the format of yyyy-MM-ddTHH:mm:ssZ and is displayed in UTC, the preemptible instance is recycled at that point in time. Example: 2015-01-05T18:02:00Z.
    • Method 2: Call the DescribeInstances operation to check whether the instance is in the Pending Release state based on the returned OperationLocks parameter.
      public class DescribeInstancesSample {
        public static void main(String[] args) throws InterruptedException {
      
            ApiCaller caller = new ApiCaller();
            JSONArray allInstances = new JSONArray();
            allInstances.addAll(Arrays.asList("i-bp18hgfai8ekoqwo0***", "i-bp1ecbyds24ij63w1***"));
      
            while (!allInstances.isEmpty()) {
      
                DescribeInstancesRequest request = new DescribeInstancesRequest();
                request.setRegionId("cn-hangzhou");
                // Specify an instance ID to make the query more efficient. 
                request.setInstanceIds(allInstances.toJSONString());
                DescribeInstancesResponse response = caller.doAction(request);
                List<DescribeInstancesResponse.Instance> instanceList = response.getInstances();
      
                if (instanceList != null && !instanceList.isEmpty()) {
                    for (DescribeInstancesResponse.Instance instance : instanceList) {
                        System.out.println("result:instance:" + instance.getInstanceId() + ",was created in zone:" + instance.getZoneId());
                        if (instance.getOperationLocks() != null) {
                            for (DescribeInstancesResponse.Instance.LockReason lockReason : instance.getOperationLocks()) {
                                System.out.println("instance: " + instance.getInstanceId() + "-->lockReason:" + lockReason.getLockReason() + ",instanceStatus:" + instance.getStatus());
                                if ("Recycling".equals(lockReason.getLockReason())) {
                                    // The recycle time of the instance is returned, and the ID of the recycled instance is deleted from the instance ID list. 
                                    System.out.println("Preemptible instance will be recycled immediately, instance id: " + instance.getInstanceId());
                                    allInstances.remove(instance.getInstanceId());
                                }
                            }
                        }
                    }
                    System.out.print("Try describeInstancesRequest again later...");
                    Thread.sleep(2 * 60 * 1000);
                } else {
                    break;
                }
            }
        }
      }

      If the following response is returned, the preemptible instance has entered the Pending Release state:

      instance: i-bp1ecbyds24ij63w1***-->lockReason:Recycling,instanceStatus:Stopped
      Preemptible instance will be recycled immediately, instance id: i-bp1ecbyds24ij63w1***
    • Method 3: Call the DescribeSystemEventAttribute operation of CloudMonitor to query the recycle time of the preemptible instance.
      public class DescribeSystemEventAttribute {
      
          public static void main(String[] args) {
              DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<accessKeyId>", "<accessSecret>");
              IAcsClient client = new DefaultAcsClient(profile);
      
              DescribeSystemEventAttributeRequest request = new DescribeSystemEventAttributeRequest();
                  // Specify the region ID. 
              request.setRegionId("cn-hangzhou");
                  // Specify the cloud service. 
              request.setProduct("ecs");
                  // Specify the start of the time range to query. 
              request.setStartTime("1574064240000");
      
              try {
                  DescribeSystemEventAttributeResponse response = client.getAcsResponse(request);
                  System.out.println(new Gson().toJson(response));
              } catch (ServerException e) {
                  e.printStackTrace();
              } catch (ClientException e) {
                  System.out.println("ErrCode:" + e.getErrCode());
                  System.out.println("ErrMsg:" + e.getErrMsg());
                  System.out.println("RequestId:" + e.getRequestId());
              }
      
          }
      }

      If the following response is returned, the preemptible instance has entered the Pending Release state:

      {
          "SystemEvents": {
              "SystemEvent": [
                  {
                      "Name": "Instance:PreemptibleInstanceInterruption",
                      "Status": "Normal",
                      "Time": 1574064244000,
                      "Product": "ECS",
                      "ResourceId": "acs:ecs:cn-hangzhou:133160284996****:instance/i-bp19w6o2tqa9jvoh8***",
                      "RegionId": "cn-hangzhou",
                      "Level": "WARN",
                      "Content": "{\"action\":\"delete\",\"instanceId\":\"i-bp19w6o2tqa9jvoh8***\"}",
                      "GroupId": "0",
                      "InstanceName": "i-bp19w6o2tqa9jvoh8***"
                  }
              ]
          },
          "Message": "200",
          "RequestId": "D4730844-EF73-4856-BFF3-1BDAE8E54C81",
          "Success": true,
          "Code": "200"
      }