master
liuyunhu 2024-04-18 22:40:49 +08:00
parent 720a6c7949
commit 71fbd04a65
14 changed files with 397 additions and 266 deletions

View File

@ -70,12 +70,12 @@ public class AliYunEcsService {
.setRegionId(regionId);
DescribeInstancesResponse resp = this.client.describeInstances(describeInstancesRequest);
java.util.List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> instances = resp.body.instances.instance;
com.aliyun.teaconsole.Client.log(regionId + " 下 ECS 实例列表:");
log.info(regionId + " 下 ECS 实例列表:");
//存储结果的List
ArrayList<String> result = new ArrayList<>();
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance instance : instances) {
com.aliyun.teaconsole.Client.log("主机名:" + instance.hostName + " 实例ID" + instance.instanceId + " CPU" + instance.cpu + " 内存:" + instance.memory + " MB 规格:" + instance.instanceType + " 系统:" + instance.OSType + "(" + instance.OSName + ") 状态:" + instance.status);
log.info("主机名:" + instance.hostName + " 实例ID" + instance.instanceId + " CPU" + instance.cpu + " 内存:" + instance.memory + " MB 规格:" + instance.instanceType + " 系统:" + instance.OSType + "(" + instance.OSName + ") 状态:" + instance.status);
result.add(instance.instanceId);
}

View File

@ -1,69 +0,0 @@
package com.lyh.common.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/16
* @Description:
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class InstancesInformation {
/*
* log.info("查询第{" + count + "}个实例的ID:" + item.getInstanceId());
log.info("名称:" + item.getInstanceName());
log.info("状态:" + item.getStatus());
log.info("公网IP:" + UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()));
log.info("私网IP:" + UserUtil.removeBrackets(item.getVpcAttributes().getPrivateIpAddress().ipAddress.toString()));
log.info("创建时间:" + item.getCreationTime());
log.info("到期时间:" + item.getExpiredTime());
log.info("是否可以回收:" + (item.getRecyclable() ? "是" : "否") + "\n\n");
* */
/*
* ID
* */
private String instanceId;
/*
*
* */
private String instanceName;
/*
*
* */
private String status;
/*
* IP
* */
private String publicIpAddress;
/*
* IP
* */
private String privateIpAddress;
/*
*
* */
private String creationTime;
/*
*
* */
private String expiredTime;
/*
*
* */
private Boolean recyclable;
}

View File

@ -0,0 +1,56 @@
package com.lyh.gateway.cache;
import com.alibaba.fastjson2.JSON;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import com.lyh.gateway.mode.IpAndLoadCount;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description: IP
*/
@Component
public class GatewayIpAndLoadCountCache extends GatewayCacheAbs<String> {
private final static String gatewayIpAndLoadCountKey = "ipAndCount";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: [gatewayNodeIps]
* @Return: void
**/
public void put(List<IpAndLoadCount> ipAndLoadCounts) {
this.remove();
redisService.setCacheList(encode(gatewayIpAndLoadCountKey), ipAndLoadCounts);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: java.util.List<java.lang.String>
**/
public List<IpAndLoadCount> get() {
List<Object> cacheList = redisService.getCacheList(encode(gatewayIpAndLoadCountKey));
return JSON.parseArray(JSON.toJSONString(cacheList), IpAndLoadCount.class);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: void
**/
public void remove() {
redisService.deleteObject(encode(gatewayIpAndLoadCountKey));
}
}

View File

@ -0,0 +1,56 @@
package com.lyh.gateway.cache;
import com.alibaba.fastjson2.JSON;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import com.lyh.gateway.mode.IpAndWeight;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description: IP
*/
@Component
public class GatewayIpAndLoadWeightCache extends GatewayCacheAbs<String> {
private final static String gatewayIpAndWeightKey = "ipAndWeight";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: [gatewayNodeIps]
* @Return: void
**/
public void put(List<IpAndWeight> ipAndWeights) {
this.remove();
redisService.setCacheList(encode(gatewayIpAndWeightKey), ipAndWeights);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: java.util.List<java.lang.String>
**/
public List<IpAndWeight> get() {
List<Object> cacheList = redisService.getCacheList(encode(gatewayIpAndWeightKey));
return JSON.parseArray(JSON.toJSONString(cacheList), IpAndWeight.class);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: void
**/
public void remove() {
redisService.deleteObject(encode(gatewayIpAndWeightKey));
}
}

View File

@ -1,57 +0,0 @@
package com.lyh.gateway.cache;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description:
*/
@Component
public class GatewayLoadNodeCache extends GatewayCacheAbs<String> {
private final static String gatewayLoadNodeKey = "node";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Description:
* @Date: 2024/4/18 16:12
* @Param: [nodeList]
* @Return: void
**/
public void put(List<String> nodeList) {
redisService.deleteObject(encode(gatewayLoadNodeKey));
redisService.setCacheList(encode(gatewayLoadNodeKey), nodeList);
}
/*
* @Description:
* @Date: 2024/4/18 16:12
* @Param: []
* @Return: java.util.List<java.lang.String>
**/
public List<String> get() {
return redisService.getCacheList(encode(gatewayLoadNodeKey));
}
/*
* @Description:
* @Date: 2024/4/18 16:13
* @Param: []
* @Return: java.lang.String
**/
public String getByIndex(Long index) {
if (null == index || 100 < index) {
throw new RuntimeException("下标违法0-100");
}
return redisService.getCacheList(encode(gatewayLoadNodeKey), index);
}
}

View File

@ -0,0 +1,53 @@
package com.lyh.gateway.cache;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description: IP
*/
@Component
public class GatewayLoadNodeIpCache extends GatewayCacheAbs<String> {
private final static String gatewayLoadNodeIpKey = "ip";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: [gatewayNodeIps]
* @Return: void
**/
public void put(List<String> gatewayNodeIps) {
this.remove();
redisService.setCacheList(encode(gatewayLoadNodeIpKey), gatewayNodeIps);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: java.util.List<java.lang.String>
**/
public List<String> get() {
return redisService.getCacheList(encode(gatewayLoadNodeIpKey));
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: void
**/
public void remove() {
redisService.deleteObject(encode(gatewayLoadNodeIpKey));
}
}

View File

@ -1,66 +0,0 @@
package com.lyh.gateway.cache;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description:
*/
@Component
public class GatewayLoadSeriesCache extends GatewayCacheAbs<String> {
//redis Key
private final static String gatewayLoadSeriesKey = "series";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Date: 2024/4/18 15:35
* @Description: bean
* @Param: []
* @Return: void
**/
@PostConstruct
public void init() {
redisService.setCacheObject(encode(gatewayLoadSeriesKey), 0L);
}
/*
* @Description:
* @Date: 2024/4/18 15:56
* @Param: []
* @Return: java.lang.Long
**/
public Long get() {
return redisService.getCacheObject(encode(gatewayLoadSeriesKey));
}
/*
* @Description:
* @Date: 2024/4/18 15:38
* @Param: []
* @Return:
**/
public Long incrementAndGet() {
return redisService.increment(encode(gatewayLoadSeriesKey), 1L);
}
/*
* @Description:
* @Date: 2024/4/18 15:57
* @Param: []
* @Return: void
**/
public void reset() {
this.init();
}
}

View File

@ -1,9 +1,12 @@
package com.lyh.gateway.cache;
import com.alibaba.fastjson2.JSON;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import com.lyh.gateway.mode.GatewayNodeInfo;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
@ -12,11 +15,13 @@ import org.springframework.stereotype.Component;
*/
@Component
public class GatewayNodeCache extends GatewayCacheAbs<String> {
//redis Key前缀
public class GatewayNodeInfoCache extends GatewayCacheAbs<String> {
//redis Key
private final static String gatewayLoadInfoKey = "info";
@Override
public String getPre() {
return "gateway:node:info:";
return "gateway:node:";
}
/*
@ -26,8 +31,9 @@ public class GatewayNodeCache extends GatewayCacheAbs<String> {
* @Param:
* @Return: void
**/
public void put(GatewayNodeInfo gatewayNodeInfo) {
redisService.setCacheObject(encode(gatewayNodeInfo.getNodeId()), gatewayNodeInfo);
public void put(List<GatewayNodeInfo> gatewayNodeInfos) {
this.remove();
redisService.setCacheList(encode(gatewayLoadInfoKey), gatewayNodeInfos);
}
/*
@ -37,8 +43,10 @@ public class GatewayNodeCache extends GatewayCacheAbs<String> {
* @Param: id
* @Return:
**/
public GatewayNodeInfo get(String nodeId) {
return redisService.getCacheObject(encode(nodeId));
public List<GatewayNodeInfo> get() {
List<Object> cacheList = redisService.getCacheList(encode(gatewayLoadInfoKey));
return JSON.parseArray(JSON.toJSONString(cacheList), GatewayNodeInfo.class);
}
/*
@ -48,7 +56,7 @@ public class GatewayNodeCache extends GatewayCacheAbs<String> {
* @Param: id
* @Return: void
**/
public void remove(String nodeId) {
redisService.deleteObject(encode(nodeId));
public void remove() {
redisService.deleteObject(encode(gatewayLoadInfoKey));
}
}

View File

@ -0,0 +1,54 @@
package com.lyh.gateway.cache;
import com.lyh.gateway.cache.abs.GatewayCacheAbs;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @ProjectName: LoadCenter
* @Author: LiuYunHu
* @CreateTime: 2024/4/18
* @Description: IP
*/
@Component
public class GatewayNodeOrderCache extends GatewayCacheAbs<String> {
private final static String gatewayNodeOrderKey = "nodeOrder";
@Override
public String getPre() {
return "gateway:load:";
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: [gatewayNodeIps]
* @Return: void
**/
public void put(List<String> gatewayNodeOrders) {
this.remove();
redisService.setCacheList(encode(gatewayNodeOrderKey), gatewayNodeOrders);
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: java.util.List<java.lang.String>
**/
public List<String> get() {
return redisService.getCacheList(encode(gatewayNodeOrderKey));
}
/*
* @Description:
* @Date: 2024/4/18 21:37
* @Param: []
* @Return: void
**/
public void remove() {
redisService.deleteObject(encode(gatewayNodeOrderKey));
}
}

View File

@ -17,9 +17,31 @@ import lombok.NoArgsConstructor;
@Builder
public class GatewayNodeInfo {
/*
* id
* log.info("查询第{" + count + "}个实例的ID:" + item.getInstanceId());
log.info("名称:" + item.getInstanceName());
log.info("状态:" + item.getStatus());
log.info("公网IP:" + UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()));
log.info("私网IP:" + UserUtil.removeBrackets(item.getVpcAttributes().getPrivateIpAddress().ipAddress.toString()));
log.info("创建时间:" + item.getCreationTime());
log.info("到期时间:" + item.getExpiredTime());
log.info("是否可以回收:" + (item.getRecyclable() ? "是" : "否") + "\n\n");
* */
/*
* ID
* */
private String nodeId;
private String instanceId;
/*
*
* */
private String instanceName;
/*
*
* */
private String status;
/*
* IP
@ -27,7 +49,22 @@ public class GatewayNodeInfo {
private String publicIpAddress;
/*
* IP
* IP
* */
private String privateIpAddress;
/*
*
* */
private String creationTime;
/*
*
* */
private String expiredTime;
/*
*
* */
private Boolean recyclable;
}

View File

@ -1,4 +1,4 @@
package com.lyh.common.domain;
package com.lyh.gateway.mode;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.lyh.common.domain;
package com.lyh.gateway.mode;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,15 +1,15 @@
package com.lyh.service.impl;
import com.alibaba.fastjson2.JSON;
import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody;
import com.lyh.common.aliyun.service.AliYunEcsService;
import com.lyh.common.domain.InstancesInformation;
import com.lyh.common.domain.IpAndLoadCount;
import com.lyh.common.domain.IpAndWeight;
import com.lyh.common.domain.resp.Result;
import com.lyh.common.redis.service.RedisService;
import com.lyh.common.utils.mqtt.MqttUtil;
import com.lyh.common.utils.user.UserUtil;
import com.lyh.gateway.cache.*;
import com.lyh.gateway.mode.GatewayNodeInfo;
import com.lyh.gateway.mode.IpAndLoadCount;
import com.lyh.gateway.mode.IpAndWeight;
import com.lyh.service.LoadCenterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -38,6 +38,35 @@ public class LoadCenterServiceImpl implements LoadCenterService {
@Autowired
private AliYunEcsService aliYunEcsService;
/*
*
* */
@Autowired
private GatewayNodeInfoCache gatewayNodeInfoCache;
/*
* IP
* */
@Autowired
private GatewayLoadNodeIpCache gatewayLoadNodeIpCache;
/*
* IP
* */
@Autowired
private GatewayIpAndLoadCountCache gatewayIpAndLoadCountCache;
/*
* IP
* */
@Autowired
private GatewayIpAndLoadWeightCache gatewayIpAndLoadWeightCache;
/*
* IP
* */
@Autowired
private GatewayNodeOrderCache gatewayNodeOrderCache;
/*
* @Author: LiuYunHu
@ -48,53 +77,42 @@ public class LoadCenterServiceImpl implements LoadCenterService {
**/
@Override
public Result<String> getAssignedServer() {
//从缓存中获取实例公网IP列表
if (redis.getCacheList("实例IP列表:").isEmpty()) {
throw new RuntimeException("实例IP列表为空");
}
//将结果转成JSON串
String string = JSON.toJSONString(redis.getCacheList("实例IP列表:"));
//再转成String泛型 的 List
List<String> ecsIPList = JSON.parseArray(string, String.class);
//获取所有实例公网的IP列表
this.getNodeIPList();
//通过IP列表 获取各个IP对应的负载量
List<IpAndLoadCount> ipAndLoadCounts = this.getIpAndLoadCounts(ecsIPList);
this.getIpAndLoadCounts();
//通过IP和对应的负载量计算出IP对应的权重
List<IpAndWeight> ipAndWeights = this.getIpAndWeights(ipAndLoadCounts);
this.getIpAndWeights();
//通过IP和权重计算负载节点的IP列表
List<String> loadNodeList = this.getLoadNodeListByIpAndWeights(ipAndWeights);
//通过IP和权重计算负载节点的IP序列列表
this.getLoadNodeOrderListByIpAndWeights();
//获取缓存里最后一个IP进行返回
//获取序列缓存里最后一个IP进行返回
//最后一个IP进行返回
String result = loadNodeList.get(loadNodeList.size() - 1);
List<String> nodeOrderList = gatewayNodeOrderCache.get();
String result = nodeOrderList.get(nodeOrderList.size() - 1);
return Result.success(result);
}
/*
* @Author: LiuYunHu
* @Date: 2024/4/17 17:14
* @Description: IP
* @Description:
* @Date: 2024/4/18 21:18
* @Param: []
* @Return: List<String>
* @Return: void
**/
@PostConstruct
@Scheduled(cron = "0/2 * * * * ?")
public void getEcsIPList() {
@Scheduled(cron = "0/5 * * * * ?")
public void getNodeInfos() {
int count = 0;
//存IP的List
ArrayList<String> ecsIPList = new ArrayList<>();
//新建List用于redis存储实例信息
ArrayList<InstancesInformation> instancesInformations = new ArrayList<>();
ArrayList<GatewayNodeInfo> gatewayNodeInfos = new ArrayList<>();
try {
//获取上海区的实例ID列表
@ -107,6 +125,7 @@ public class LoadCenterServiceImpl implements LoadCenterService {
}
ids = ids.substring(0, ids.length() - 1);
//查询所有ID实例的详细信息
List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> response = aliYunEcsService.queryInstancesInformation(ids);
@ -132,8 +151,8 @@ public class LoadCenterServiceImpl implements LoadCenterService {
log.info("是否可以回收:" + (item.getRecyclable() ? "是" : "否") + "\n\n");
//存入集合
instancesInformations.add(
new InstancesInformation(
gatewayNodeInfos.add(
new GatewayNodeInfo(
item.getInstanceId(),
item.getInstanceName(),
item.getStatus(),
@ -145,28 +164,52 @@ public class LoadCenterServiceImpl implements LoadCenterService {
)
);
//获取添加的实例的公网ip
String ip = UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString());
ecsIPList.add(ip);
count++;
}
} catch (Exception e) {
log.error("获取实例ID列表失败{}", e.getMessage());
throw new RuntimeException(e);
throw new RuntimeException("获取实例列表失败:" + e.getMessage());
}
log.info("实例信息列表:{}", gatewayNodeInfos);
//存入缓存
gatewayNodeInfoCache.put(gatewayNodeInfos);
}
/*
* @Author: LiuYunHu
* @Date: 2024/4/17 17:14
* @Description: IP
* @Param: []
* @Return: List<String>
**/
public void getNodeIPList() {
//存IP的List
ArrayList<String> nodeIPList = new ArrayList<>();
//从缓存中拿到实例信息列表
List<GatewayNodeInfo> gatewayNodeInfoList = gatewayNodeInfoCache.get();
if (gatewayNodeInfoList.isEmpty()) {
throw new RuntimeException("实例信息列表为空!");
}
//缓存数据
redis.deleteObject("服务器信息:");
redis.setCacheList("服务器信息:", instancesInformations);
gatewayNodeInfoList.forEach(item -> {
//获取IP
String ip = item.getPublicIpAddress();
//存入集合
nodeIPList.add(ip);
});
log.info("实例公网IP列表:{}", nodeIPList);
//将IP列表存入redis
redis.deleteObject("实例IP列表:");
redis.setCacheList("实例IP列表:", ecsIPList);
gatewayLoadNodeIpCache.put(nodeIPList);
log.info("实例公网IP列表:{}", ecsIPList);
}
@ -177,19 +220,25 @@ public class LoadCenterServiceImpl implements LoadCenterService {
* @Param: ecsIPList
* @Return: List<IpAndLoadCount>
**/
public List<IpAndLoadCount> getIpAndLoadCounts(List<String> ecsIPList) {
public void getIpAndLoadCounts() {
//从缓存中获取实例公网IP列表
List<String> nodeIPList = gatewayLoadNodeIpCache.get();
if (nodeIPList.isEmpty()) {
throw new RuntimeException("实例公网IP列表为空");
}
//存各个 服务器的负载量
ArrayList<IpAndLoadCount> ipAndLoadCounts = new ArrayList<>();
//拿到IP后获取各个IP的负载量
ecsIPList.forEach(ip -> {
nodeIPList.forEach(ip -> {
int fetchLoad = mqttUtil.getFetchLoad(ip);
ipAndLoadCounts.add(new IpAndLoadCount(ip, fetchLoad));
});
log.info("各个IP的负载量{}", ipAndLoadCounts);
return ipAndLoadCounts;
gatewayIpAndLoadCountCache.put(ipAndLoadCounts);
}
@ -200,7 +249,14 @@ public class LoadCenterServiceImpl implements LoadCenterService {
* @Param: ipAndLoadCountList
* @Return: List<IpAndWeight>
**/
public List<IpAndWeight> getIpAndWeights(List<IpAndLoadCount> ipAndLoadCounts) {
public void getIpAndWeights() {
//从缓存中获取公网IP和负载量列表
List<IpAndLoadCount> ipAndLoadCounts = gatewayIpAndLoadCountCache.get();
if (ipAndLoadCounts.isEmpty()) {
throw new RuntimeException("负载量列表为空!");
}
//求出空负载的总量
int emptyLoadCount = 0;
for (IpAndLoadCount ipAndLoadCount : ipAndLoadCounts) {
@ -221,17 +277,23 @@ public class LoadCenterServiceImpl implements LoadCenterService {
log.info("实例IP和对应的权重{}", ipAndWeights);//[IpAndWeight(nodeIp=47.102.158.233, weight=55), IpAndWeight(nodeIp=47.102.123.209, weight=44)]
return ipAndWeights;
gatewayIpAndLoadWeightCache.put(ipAndWeights);
}
/*
* @Author: LiuYunHu
* @Date: 2024/4/17 20:02
* @Description: IPIP TODO
* @Description: IPIP
* @Param: []
* @Return:
**/
public List<String> getLoadNodeListByIpAndWeights(List<IpAndWeight> ipAndWeights) {
public void getLoadNodeOrderListByIpAndWeights() {
//从缓存中获取公网IP和权重列表
List<IpAndWeight> ipAndWeights = gatewayIpAndLoadWeightCache.get();
if (ipAndWeights.isEmpty()) {
throw new RuntimeException("负载节点IP和权重列表为空");
}
ArrayList<String> loadNodeList = new ArrayList<>();
int sum = ipAndWeights.stream()
@ -266,12 +328,9 @@ public class LoadCenterServiceImpl implements LoadCenterService {
}
}
//节点IP列表存入缓存
redis.deleteObject("work:node:gateway");
redis.setCacheList("work:node:gateway", loadNodeList);
log.info("负载节点的IP列表{}", loadNodeList);
return loadNodeList;
log.info("负载节点的IP序列列表{}", loadNodeList);
//节点IP序列存入缓存
gatewayNodeOrderCache.put(loadNodeList);
}
}

View File

@ -72,7 +72,7 @@ public class Test {
**/
@org.junit.jupiter.api.Test
public void releaseInstances() throws Exception {
aliYunEcsService.releaseInstances("i-uf65dwndeh5u4cmpl1ff,i-uf68ar6qiqmgetp67a5q");
aliYunEcsService.releaseInstances("i-uf662hanv9a05kyvooo5");
}
/*