本文介紹了如何使用阿里雲 ECS SDK 合理快速地建立並管理搶佔式執行個體。
準備工作
在執行操作之前,您需要:
- 瞭解能滿足您業務要求的執行個體規格和地域。
- 熟悉瞭解阿里雲 ECS SDK 的基礎知識和調用方法。詳細資料,請參考 SDK 使用說明。
注意:
搶佔式執行個體代碼需要依賴的 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>
查詢地域及可用的執行個體規格
使用 OpenAPI DescribeZones 查詢可以建立搶佔式執行個體的地域以及可用的執行個體規格。範例程式碼如下所示。
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"
]
}
]
}
查詢搶佔式執行個體的曆史價格
使用 OpenAPI DescribeSpotPriceHistory 查詢搶佔式執行個體最近 30 天的價格變化資料,獲得最佳性價比的地域和規格資訊,範例程式碼(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");//是否 I/O 優化類型,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
重複以上步驟,您可以判斷出該規格資源在可用性區域的價格變化趨勢和最近價格。
說明:
您可以通過平均價格和最高價格來決定是否可以接受購買該搶佔式執行個體,也可以通過更加合理的資料模型來分析曆史價格資料,隨時調整建立資源的規格和可用性區域,到達最佳性價比。
建立搶佔式執行個體
在建立搶佔式執行個體之前,您需要完成以下工作:
- 如果您使用自訂鏡像建立搶佔式執行個體,必須已經 建立自訂鏡像。
- 在控制台 建立安全性群組,或者使用 OpenAPI CreateSecurityGroup 建立安全性群組,並獲取安全性群組 ID(SecurityGroupId)。
- 在控制台建立 VPC 和 交換器,或者使用 OpenAPI CreateVpc 和 CreateVSwitch 建立,並獲取交換器 ID(VSwitchId)。
使用 OpenAPI CreateInstance 建立搶佔式執行個體。範例程式碼(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());
}
}
回收搶佔式執行個體
當搶佔式執行個體可能會因為價格因素或者市場供需變化而被強制回收。此時會觸發搶佔式執行個體的中斷。釋放前,搶佔式執行個體會進入鎖定狀態,提示執行個體將會被自動回收。您可以針對執行個體回收狀態自動化處理執行個體的退出邏輯。
目前,您可以通過以下任一種方式來獲取搶佔式執行個體的中斷鎖定狀態:
通過 執行個體元資料 獲取。運行以下命令:
curl 'http://100.100.100.200/latest/meta-data/instance/spot/termination-time'
如果返回為空,說明執行個體可持續使用。如果返回類似
2015-01-05T18:02:00Z
格式的資訊(UTC 時間),說明執行個體將於這個時間釋放。使用 OpenAPI 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-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
其他動作
您還可以啟動、停止、釋放搶佔式執行個體。具體的操作與一般隨用隨付執行個體沒有區別。可以參考 OpenAPI 文檔:
- 啟動執行個體:StartInstance
- 停止執行個體:StopInstance
- 釋放執行個體:DeleteInstance