抢占式实例可能会因为价格因素或者市场供需变化而被强制回收,此时会触发抢占式实例的中断。回收前,抢占式实例会进入锁定状态,提示实例将会被自动回收。本文介绍如何查询抢占式实例中断事件,您可以针对实例回收状态自动化处理实例的退出逻辑。

通过云监控SDK查询抢占式实例中断事件

以云监控Java SDK为例,介绍如何查询抢占式实例中断事件。

  1. 接入云监控SDK,具体操作请参见Java SDK使用手册
  2. 通过SDK查询系统事件。
    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.IAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.exceptions.ServerException;
    import com.aliyuncs.profile.DefaultProfile;
    import com.google.gson.Gson;
    import java.util.*;
    import com.aliyuncs.cms.model.v20190101.*;
    
    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();
            request.setRegionId("cn-hangzhou");
            request.setProduct("ECS");
            request.setEventType("StatusNotification");
            request.setName("Instance:PreemptibleInstanceInterruption");
            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());
            }
        }
    }
  3. 根据返回结果判断抢占式实例中断事件。

    事件通知的JSON格式如下所示。

    {
      "ver": "1.0",
      "id": "2256A988-0B26-4E2B-820A-8A********E5",
      "product": "ECS",
      "resourceId": "acs:ecs:cn-hangzhou:169070********30:instance/i-bp1ecr********5go2go",
      "level": "INFO",
      "name": "Instance:PreemptibleInstanceInterruption",
      "userId": "169070********30",
      "eventTime": "20190409T121826.922+0800",
      "regionId": "cn-hangzhou",
      "content": {
        "instanceId": "i-bp1ecr********5go2go",  
        "action": "delete"                       
      }
    }
    content字段解释如下表所示。
    字段 说明 示例值
    instanceId 抢占式实例ID。 i-bp1ecr********5go2go
    action 抢占式实例的操作事件。取值delete表示抢占式实例中断,将被强制回收。 delete

通过实例元数据获取查询抢占式实例中断事件

  1. 远程连接ECS实例。连接方式请参见连接方式概述
  2. 执行以下命令查询实例元数据。
    curl 'http://100.100.100.200/latest/meta-data/instance/spot/termination-time'
    • 如果返回为空,说明实例可持续使用。
    • 如果返回类似2015-01-05T18:02:00Z格式的信息(UTC时间),说明实例将于这个时间回收。

通过API查询抢占式实例中断事件

使用DescribeInstances,根据返回的OperationLocks判断实例是否进入待回收状态。

代码示例(DescribeInstancesSample.java)如下所示。
public class DescribeInstancesSample {
  public static void main(String[] args) throws InterruptedException {
      OpenApiCaller caller = new OpenApiCaller();
      JSONArray allInstances = new JSONArray();
      allInstances.addAll(Arrays.asList("i-bp18hgfai8ekoqwo0***", "i-bp1ecbyds24ij63w1***"));
      while (!allInstances.isEmpty()) {
          DescribeInstancesRequest request = new DescribeInstancesRequest();
          request.setRegionId("cn-hangzhou");
          request.setInstanceIds(allInstances.toJSONString());//指定实例ID,效率最高
          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() + ",az:" + instance.getZoneId());
                  if (instance.getOperationLocks() != null) {
                      for (DescribeInstancesResponse.Instance.LockReason lockReason : instance.getOperationLocks()) {
                          System.out.println("instance:" + instance.getInstanceId() + "-->lockReason:" + lockReason.getLockReason() + ",vmStatus:" + instance.getStatus());
                          if ("Recycling".equals(lockReason.getLockReason())) {
                              //do your action
                              System.out.println("spot instance will be recycled immediately, instance id:" + instance.getInstanceId());
                              allInstances.remove(instance.getInstanceId());
                          }
                      }
                  }
              }
              System.out.print("try describeInstances again later ...");
              Thread.sleep(2 * 60 * 1000);
          } else {
              break;
          }
      }
  }
}
触发回收时输出结果如下:
instance:i-bp1ecbyds24ij63w****-->lockReason:Recycling,vmStatus:Stopped
spot instance will be recycled immediately, instance id:i-bp1ecbyds24ij63w****