阿里雲搶佔例項OpenApi入門實踐

抹達發表於2017-10-23

阿里雲競價例項OpenApi入門實踐

目的

本文目標是介紹開發者如何通過阿里雲ECS SDK,合理快速的建立需要的搶佔例項

準備工作:

  • 首先要熟悉瞭解阿里雲SDK的基礎知識和呼叫方法,可以參考SDK 使用說明
  • Spot競價例項程式碼需要依賴的ECS SDK版本4.2.0 以上,
  • 以JAVA POM依賴舉例,修改引入pom依賴:
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>3.2.8</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-ecs</artifactId>
    <version>4.2.0</version>
</dependency>



## 哪些地域與規格可以購買競價例項:

> 典型一個場景,我需要建立一批價格便宜量又足的計算資源,做業務資料處理。
但我不知道去哪個地域去建立需要的計算資源。
我們需要規劃下對計算資源的大致需求:
1. 地域,建立的競價例項哪個地域建立。
2. 規格  根據你的業務需求確定什麼樣規格例項

> 但是由於目前aliyun 每個地域因為售賣比率不同,每個地域可用對外開放售賣的規格存在很大差異。
所以建議通過DesribeZones介面來獲取您的賬戶可建立的地域與規格資訊,幫助您選擇地域和規格。
* API名稱: DesribeZones
* API說明:https://help.aliyun.com/document_detail/25610.html
* 程式碼示例:

>  OpenApiCaller.java

public class OpenApiCaller {

IClientProfile profile;
IAcsClient client;

public OpenApiCaller() {
    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 (Throwable e) {
        e.printStackTrace();
        return null;
    }
}


> DescribeZonesSample.java

public class DescribeZonesSample {

public static void main(String[] args) {

    OpenApiCaller caller = new OpenApiCaller();
    DescribeZonesRequest request = new DescribeZonesRequest();
    request.setRegionId("cn-zhangjiakou");//可以通過DescribeRegionsRequest獲取每個地域的regionId
    request.setSpotStrategy("SpotWithPriceLimit");//對於查詢是否可購買競價例項此項必填
    request.setInstanceChargeType("PostPaid");//後付費模式,競價例項必須是後付費模式
    DescribeZonesResponse response = caller.doAction(request);
    System.out.println(JSON.toJSONString(response));

}

}

輸出結果:

{

"requestId": "388D6321-E587-470C-8CFA-8985E2963DAE",
"zones": [
    {

        "localName": "華北 3 可用區 A",
        "zoneId": "cn-zhangjiakou-a",
        "availableDiskCategories": [
            "cloud_ssd",
            "cloud_efficiency"
        ],
        "availableInstanceTypes": [
            "ecs.e4.large",
            "ecs.n4.4xlarge",
            "ecs.sn2.medium",
            "ecs.i1.2xlarge",
            "ecs.se1.2xlarge",
            "ecs.n4.xlarge",
            "ecs.se1ne.2xlarge",
            "ecs.se1.large",
            "ecs.sn2.xlarge",
            "ecs.se1ne.xlarge",
            "ecs.xn4.small",
            "ecs.sn2ne.4xlarge",
            "ecs.se1ne.4xlarge",
            "ecs.sn1.medium",
            "ecs.n4.8xlarge",
            "ecs.mn4.large",
            "ecs.e4.2xlarge",
            "ecs.mn4.2xlarge",
            "ecs.mn4.8xlarge",
            "ecs.n4.2xlarge",
            "ecs.e4.xlarge",
            "ecs.sn2ne.large",
            "ecs.sn2ne.xlarge",
            "ecs.sn1ne.large",
            "ecs.n4.large",
            "ecs.sn1.3xlarge",
            "ecs.e4.4xlarge",
            "ecs.sn1ne.2xlarge",
            "ecs.e4.small",
            "ecs.i1.4xlarge",
            "ecs.se1.4xlarge",
            "ecs.sn2ne.2xlarge",
            "ecs.sn2.3xlarge",
            "ecs.i1.xlarge",
            "ecs.n4.small",
            "ecs.sn1ne.4xlarge",
            "ecs.mn4.4xlarge",
            "ecs.sn1ne.xlarge",
            "ecs.se1ne.large",
            "ecs.sn2.large",
            "ecs.i1-c5d1.4xlarge",
            "ecs.sn1.xlarge",
            "ecs.sn1.large",
            "ecs.mn4.small",
            "ecs.mn4.xlarge",
            "ecs.se1.xlarge"
        ],
        "availableResourceCreation": [
            "VSwitch",
            "IoOptimized",
            "Instance",
            "Disk"
        ],
        "availableResources": [
            {
                "dataDiskCategories": [
                    "cloud_ssd",
                    "cloud_efficiency"
                ],
                "instanceGenerations": [
                    "ecs-3",
                    "ecs-2"
                ],
                "instanceTypeFamilies": [
                    "ecs.mn4",
                    "ecs.sn1",
                    "ecs.sn2",
                    "ecs.sn1ne",
                    "ecs.xn4",
                    "ecs.i1",
                    "ecs.se1",
                    "ecs.e4",
                    "ecs.n4",
                    "ecs.se1ne",
                    "ecs.sn2ne"
                ],
                "instanceTypes": [
                    "ecs.n4.4xlarge",
                    "ecs.sn2.medium",
                    "ecs.i1.2xlarge",
                    "ecs.se1.2xlarge",
                    "ecs.n4.xlarge",
                    "ecs.se1ne.2xlarge",
                    "ecs.se1.large",
                    "ecs.sn2.xlarge",
                    "ecs.se1ne.xlarge",
                    "ecs.xn4.small",
                    "ecs.sn2ne.4xlarge",
                    "ecs.se1ne.4xlarge",
                    "ecs.sn1.medium",
                    "ecs.n4.8xlarge",
                    "ecs.mn4.large",
                    "ecs.mn4.2xlarge",
                    "ecs.mn4.8xlarge",
                    "ecs.n4.2xlarge",
                    "ecs.sn2ne.large",
                    "ecs.sn2ne.xlarge",
                    "ecs.sn1ne.large",
                    "ecs.n4.large",
                    "ecs.sn1.3xlarge",
                    "ecs.sn1ne.2xlarge",
                    "ecs.e4.small",
                    "ecs.i1.4xlarge",
                    "ecs.se1.4xlarge",
                    "ecs.sn2ne.2xlarge",
                    "ecs.sn2.3xlarge",
                    "ecs.i1.xlarge",
                    "ecs.n4.small",
                    "ecs.sn1ne.4xlarge",
                    "ecs.mn4.4xlarge",
                    "ecs.sn1ne.xlarge",
                    "ecs.se1ne.large",
                    "ecs.sn2.large",
                    "ecs.i1-c5d1.4xlarge",
                    "ecs.sn1.xlarge",
                    "ecs.sn1.large",
                    "ecs.mn4.small",
                    "ecs.mn4.xlarge",
                    "ecs.se1.xlarge"
                ],
                "ioOptimized": true,
                "networkTypes": [
                    "vpc"
                ],
                "systemDiskCategories": [
                    "cloud_ssd",
                    "cloud_efficiency"
                ]
            }
        ],
        "availableVolumeCategories": [
            "san_ssd",
            "san_efficiency"
        ]
    }
]

}



## 通過查詢spot歷史價格介面來獲得最佳價效比的地域,規格資訊

通過上一步我們可以基本確定哪個可用區可以生產的哪些具體規格,有了這些資訊就可以通過
DescribeSpotPriceHistory介面查詢獲取價格歷史變化,最多允許獲取30天內的價格變化資料。
* API名稱:DescribeSpotPriceHistory
* API文件:https://help.aliyun.com/document_detail/60400.html
* 程式碼例項:DescribeSpotPriceHistorySample.java

public class DescribeSpotPriceHistorySample {

public static void main(String[] args) {

    OpenApiCaller caller = new OpenApiCaller();
    List<DescribeSpotPriceHistoryResponse.SpotPriceType> result = new ArrayList<DescribeSpotPriceHistoryResponse.SpotPriceType>();
    int offset = 0;
    while (true) {
        DescribeSpotPriceHistoryRequest request = new DescribeSpotPriceHistoryRequest();
        request.setRegionId("cn-hangzhou");//可以通過DescribeRegionsRequest獲取可購買的每個地域的regionId
        request.setZoneId("cn-hangzhou-b");//可用區必填
        request.setInstanceType("ecs.sn2.medium");//參考DescribeZones 返回的例項型別,必填
        request.setNetworkType("vpc");//參考DescribeZones 返回的網路型別,必填

// request.setIoOptimized(“optimized”);//是否Io優化型別,DescribeZones 返回的IoOptimized,選填
// request.setStartTime(“2017-09-20T08:45:08Z”);//價格開始時間,選填,預設3天內資料
// 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 {
    }

}

}


* 返回結果

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


* 重複以上步驟,您可以判斷出該規格資源在可用區的價格變化趨勢和最近價格。
* 簡單的策略通過平均價格和最高價格來決定是否可以接受購買該spot例項。
* 當然從最小成本出發,可以通過更加合理的資料模型來分析價歷史價格資料,隨時調整建立資源的規格和可用區,到達最佳價效比。


## 建立Spot例項

通過以上過程,我們最終得到可以建立的資源的地域資訊,規格屬性,磁碟,網路等資訊。
現在就可以開始真正建立競價例項了。
* API名稱:CreateInstance
* 建議您提前在控制檯或者openapi方式 在需要建立vm資源的地區建立好vpc專有網路,獲取建立引數vswitchId
* 建議您提前在控制檯或者openapi方式 在需要建立vm資源的地區建立安全組,獲取建立引數:SecurityGroupId

* 介面文件:https://help.aliyun.com/document_detail/25499.html
* 示例程式碼:CreateInstaneSample.java

public class CreateInstaneSample {

public static void main(String[] args) {
    OpenApiCaller caller = new OpenApiCaller();
    CreateInstanceRequest request = new CreateInstanceRequest();
    request.setRegionId("cn-hangzhou");//地域Id
    request.setZoneId("cn-hangzhou-b"); //可用區Id
    request.setSecurityGroupId("sg-bp11nhf94ivkdxwb2gd4");//提前建立的安全組Id
    request.setImageId("centos_7_03_64_20G_alibase_20170818.vhd");//建議選擇您自己在該地域準備的自定義映象
    request.setVSwitchId("vsw-bp164cyonthfudn9kj5br");//vpc 型別需要虛擬路由Id

    request.setInstanceType("ecs.sn2.medium"); //填入您詢價後需要購買的規格
    request.setIoOptimized("optimized");//參考 DescirbeZones返回引數
    request.setSystemDiskCategory("cloud_ssd");//參考 DescirbeZones返回引數,多選一 cloud_ssd,cloud_efficiency,cloud
    request.setSystemDiskSize(40);

    request.setInstanceChargeType("PostPaid");//競價例項必須後付費
    request.setSpotStrategy("SpotWithPriceLimit");//SpotWithPriceLimit出價模式,SpotAsPriceGo不用出價,最高按量付費價格
    request.setSpotPriceLimit(0.25F);//SpotWithPriceLimit出價模式生效,使用者您能接受的最高價格,單元元每小時,必須高於當前的公共價格才能成功

    CreateInstanceResponse response = caller.doAction(request);
    System.out.println(response.getInstanceId());

}

}


## spot例項中斷

* 競價例項可能會因為價格因素或者其他ecs內部庫存因素會強制回收競價資源,此時會觸發spot的中斷
* 在真正開始釋放vm前 vm 會進入鎖定狀態, 提示vm 將會被自動回收,您可以針對vm 回收狀態來自動化處理例項的退出邏輯
* 目前spot的中斷鎖定狀態可以通過2種方式來感知
1.  vpc 例項可以通過metadata 來獲取

* metadata訪問示例:

curl `http://100.100.100.200/latest/meta-data/instance/spot/termination-time`
返回格式示例:2015-01-05T18:02:00Z,時間為UTC時間,如果返回為空,說明可持續使用


2.  通過查詢 describeInstances 返回的OperationLocks 感知是否vm進入準備回收狀態

* openapi獲取鎖定狀態程式碼示例: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-bp18hgfai8ekoqwo0y2n", "i-bp1ecbyds24ij63w146c"));
    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-bp1ecbyds24ij63w146c–>lockReason:Recycling,vmStatus:Stopped
spot instance will be recycled immediately, instance id:i-bp1ecbyds24ij63w146c


## 啟動,關機,釋放 SPOT競價例項

啟動,停止,釋放例項Spot 例項和其他例項沒有任何區別,本文不再介紹,請參看相關api文件即可。


相關文章