From d7c5b3a4d4293f98c12175fa9be3b9d75538b55e Mon Sep 17 00:00:00 2001 From: Su ZeJing <3039179835@qq.com> Date: Sun, 21 Apr 2024 16:28:30 +0800 Subject: [PATCH] n --- pom.xml | 10 +- .../common/aliyun/config/AliConfig.java | 8 +- .../common/aliyun/model/InstanceConfig.java | 5 +- .../aliyun/service/AliYunEcsService.java | 66 ++-- .../aliyun/gateway/model/GatewayNodeInfo.java | 36 +- .../loadCenter/aliyun/handle/HandleCache.java | 342 +++++++++++++++--- .../aliyun/job/LoadCenterController.java | 103 ------ .../loadCenter/aliyun/job/ScheduledTask.java | 137 +++++++ .../service/impl/GatewayLoadServiceImpl.java | 21 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + src/main/resources/application.yml | 3 +- 11 files changed, 540 insertions(+), 192 deletions(-) delete mode 100644 src/main/java/com/loadCenter/aliyun/job/LoadCenterController.java create mode 100644 src/main/java/com/loadCenter/aliyun/job/ScheduledTask.java diff --git a/pom.xml b/pom.xml index 986f6b9..1a47e35 100644 --- a/pom.xml +++ b/pom.xml @@ -8,9 +8,9 @@ vehicle 1.0-SNAPSHOT - 20 - 20 - 2.7.18 + 17 + 17 + 2.7.13 UTF-8 @@ -218,8 +218,4 @@ - - - - diff --git a/src/main/java/com/loadCenter/aliyun/common/aliyun/config/AliConfig.java b/src/main/java/com/loadCenter/aliyun/common/aliyun/config/AliConfig.java index 046c3a3..0821377 100644 --- a/src/main/java/com/loadCenter/aliyun/common/aliyun/config/AliConfig.java +++ b/src/main/java/com/loadCenter/aliyun/common/aliyun/config/AliConfig.java @@ -17,18 +17,16 @@ import org.springframework.context.annotation.Configuration; * @Author ZeJinG.Su */ @Configuration -@ConfigurationProperties(prefix = "config.aliyun") @Data @AllArgsConstructor @NoArgsConstructor -@ToString -@SuperBuilder +@ConfigurationProperties(prefix = "config.ali") public class AliConfig { /** * 阿里云access-key-id */ - private String accessKetId; + private String accessKeyId; /** * 阿里云access-key-secret */ @@ -42,7 +40,7 @@ public class AliConfig { @Bean public Client createEcsClient(AliConfig aliConfig) throws Exception { Config config = new Config() - .setAccessKeyId(aliConfig.getAccessKetId()) + .setAccessKeyId(aliConfig.getAccessKeyId()) .setAccessKeySecret(aliConfig.getAccessKeySecret()) .setRegionId(aliConfig.getRegionId()); return new Client(config); diff --git a/src/main/java/com/loadCenter/aliyun/common/aliyun/model/InstanceConfig.java b/src/main/java/com/loadCenter/aliyun/common/aliyun/model/InstanceConfig.java index 3812457..1b8a261 100644 --- a/src/main/java/com/loadCenter/aliyun/common/aliyun/model/InstanceConfig.java +++ b/src/main/java/com/loadCenter/aliyun/common/aliyun/model/InstanceConfig.java @@ -5,7 +5,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** - *创建实例的参数映射yml + * @ClassName InstanceConfig + * @Description 创建实例的参数映射yml + * @Author ZeJinG.Su + * @Date 10:39 2024/4/20 */ @Data @Configuration diff --git a/src/main/java/com/loadCenter/aliyun/common/aliyun/service/AliYunEcsService.java b/src/main/java/com/loadCenter/aliyun/common/aliyun/service/AliYunEcsService.java index 9c71cf1..4a23949 100644 --- a/src/main/java/com/loadCenter/aliyun/common/aliyun/service/AliYunEcsService.java +++ b/src/main/java/com/loadCenter/aliyun/common/aliyun/service/AliYunEcsService.java @@ -40,7 +40,11 @@ public class AliYunEcsService { } - //区域实例集合 + /** + * 区域实例集合 + * @return + * @throws Exception + */ public List getIDList() throws Exception { List regionIds = com.aliyun.darabonbastring.Client.split(aliConfig.getRegionId(), ",", 50); @@ -63,7 +67,11 @@ public class AliYunEcsService { return result; } - //释放实例 + /** + * 释放实例 + * @param instanceIds + * @throws Exception + */ public void releaseInstances(String instanceIds) throws Exception { // 实例名称,支持使用通配符*进行模糊搜索 @@ -96,7 +104,15 @@ public class AliYunEcsService { DeleteInstances(client, aliConfig.getRegionId(), instanceIds, force); } - //查询需要删除实例 + /** + * 查询需要删除实例 + * @param client + * @param regionId + * @param instanceIds + * @param instanceName + * @return + * @throws Exception + */ public static DescribeInstancesResponse DescribeInstances(Client client, String regionId, String instanceIds, String instanceName) throws Exception { DescribeInstancesRequest req = new DescribeInstancesRequest() .setRegionId(regionId) @@ -110,7 +126,12 @@ public class AliYunEcsService { return resp; } - //修改实例删除保护 + /** + * 修改实例删除保护 + * @param client + * @param instatnceId + * @throws Exception + */ public static void ModifyInstanceAttribute(Client client, String instatnceId) throws Exception { ModifyInstanceAttributeRequest req = new ModifyInstanceAttributeRequest() .setInstanceId(instatnceId) @@ -119,7 +140,14 @@ public class AliYunEcsService { com.aliyun.teaconsole.Client.log("--------------------" + instatnceId + "释放保护取消成功--------------------"); } - //执行释放实例 + /** + * 执行释放实例 + * @param client + * @param regionId + * @param instanceIds + * @param force + * @throws Exception + */ public static void DeleteInstances(Client client, String regionId, String instanceIds, String force) throws Exception { DeleteInstancesRequest req = new DeleteInstancesRequest() .setRegionId(regionId) @@ -131,34 +159,22 @@ public class AliYunEcsService { } - //创建实例(创建成功后自启动) + /** + * 创建实例(创建成功后自启动) + * @return + * @throws Exception + */ public String createAndRunInstance() throws Exception { - //获取实例规格 - // 地域Id String regionId = aliConfig.getRegionId(); - // 镜像 ID,启动实例时选择的镜像资源。 String imageId = instanceConfig.getImageId(); - // 实例规格 String instanceType = instanceConfig.getInstanceType(); - // 新创建实例所属于的安全组 ID。 String securityGroupId = instanceConfig.getSecurityGroupId(); - // 虚拟交换机 ID。 String vSwitchId = instanceConfig.getVSwitchId(); - // 公网出带宽最大值,单位为 Mbit/s。取值范围:0~100。 默认值:0。 Integer internetMaxBandwidthOut = com.aliyun.darabonbanumber.Client.parseInt(instanceConfig.getInternetMaxBandwidthOut()); - // 网络计费类型。取值范围: - // PayByBandwidth: 按固定带宽计费。 - // PayByTraffic: 按使用流量计费。 - // 默认值:PayByTraffic。 String internetChargeType = instanceConfig.getInternetChargeType(); - // 系统盘大小 String size = instanceConfig.getSize(); - // 系统盘的云盘种类 String category = instanceConfig.getCategory(); - // ECS实例的计费方式 - // PrePaid:包年包月 - // PostPaid:按量付费 String instanceChargeType = instanceConfig.getInstanceChargeType(); @@ -213,7 +229,11 @@ public class AliYunEcsService { } - //查询实例信息 + /** + * 查询实例信息 + * @param instanceIds + * @return + */ public List queryInstancesInformation(String instanceIds) { DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest() diff --git a/src/main/java/com/loadCenter/aliyun/gateway/model/GatewayNodeInfo.java b/src/main/java/com/loadCenter/aliyun/gateway/model/GatewayNodeInfo.java index e357236..61ed884 100644 --- a/src/main/java/com/loadCenter/aliyun/gateway/model/GatewayNodeInfo.java +++ b/src/main/java/com/loadCenter/aliyun/gateway/model/GatewayNodeInfo.java @@ -16,18 +16,42 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class GatewayNodeInfo { /** - * 节点ID + * 实例ID */ - private String nodeId; + private String instanceId; /** - * 公网IP地址 + * 名称 */ - private String publicIdAddress; + private String instanceName; /** - * 内网IP地址 + * 状态 */ - private String privateIdAddress; + private String status; + /** + * 公网IP + */ + private String publicIpAddress; + + /** + * 私网IP + */ + private String privateIpAddress; + + /** + * 创建时间 + */ + private String creationTime; + + /** + * 到期时间 + */ + private String expiredTime; + + /** + * 是否可回收 + */ + private Boolean recyclable; } diff --git a/src/main/java/com/loadCenter/aliyun/handle/HandleCache.java b/src/main/java/com/loadCenter/aliyun/handle/HandleCache.java index db5705f..8e2d211 100644 --- a/src/main/java/com/loadCenter/aliyun/handle/HandleCache.java +++ b/src/main/java/com/loadCenter/aliyun/handle/HandleCache.java @@ -10,13 +10,14 @@ import com.loadCenter.aliyun.gateway.model.NodeLoadNum; import com.loadCenter.aliyun.gateway.model.NodeLoadWeight; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; /** * @ClassName HandleCache @@ -29,60 +30,313 @@ import java.util.List; @Component @AllArgsConstructor public class HandleCache { - @Autowired - private MqttUtil mqttUtil; - @Autowired - private AliYunEcsService aliYunEcsService; + private final MqttUtil mqttUtil; - /* - * 操作网关节点缓存 - * */ - @Autowired - private GatewayNodeInfoCache gatewayNodeInfoCache; - /* + private final AliYunEcsService aliYunEcsService; + + /** + * 网关节点缓存操作 + */ + private final GatewayNodeInfoCache gatewayNodeInfoCache; + + /** * 操作负载节点IP缓存 - * */ - @Autowired - private GatewayNodeIPCache gatewayNodeIpCache; + */ + private final GatewayNodeIPCache gatewayNodeIPCache; - /* - * 操作负载节点ID缓存 - * */ - @Autowired - private GatewayNodeIDCache gatewayNodeIdCache; + /** + * 操作节点ID缓存 + */ + private final GatewayNodeIDCache gatewayNodeIDCache; - /* - * 操作实例IP和负载量缓存 - * */ - @Autowired - private GatewayIpLoadCountKey gatewayIpLoadCountKey; + /** + * 操作节点权重缓存 + */ + private final GatewayWeightCache gatewayWeightCache; - /* - * 操作实例IP和权重缓存 - * */ - @Autowired - private GatewayWeightCache gatewayWeightCache; + /** + * 操作节点IP负载计数缓存 + */ + private final GatewayIpLoadCountKey gatewayIpLoadCountKey; - /* - * 操作实例IP序列缓存 - * */ - @Autowired - private GatewayOrderCache gatewayOrderCache; + /** + * 操作节点ID排序缓存 + */ + private final GatewayOrderCache gatewayOrderCache; -// //刷新所有的缓存 -// @Scheduled(cron = "0/2 * * * * ?") -// public void refreshAllCache() { -// this.getNodeIDList(); -// this.getNodeInfos(); -// this.getNodeIPList(); -// this.getIpAndLoadCounts(); -// this.getIpAndWeights(); -// this.getLoadNodeOrderListByIpAndWeights(); -// } + /** + * 定时任务,每隔5秒执行一次 + */ + @Scheduled(fixedRate = 5000) + public void handleCache() { + //节点列表缓存刷新 + this.getNodeIDList(); + //实例信息缓存刷新 + this.getNodeInfo(); + //节点公网IP列表缓存刷新 + this.getNodeIPList(); + //各个IP的负载量缓存刷新 + this.getIpAndLoadCounts(); + //各个IP的权重缓存刷新 + this.getIpAndWeights(); + //负载节点IP序列缓存刷新 + this.getLoadNodeOrderListByIpAndWeights(); + } + + /** + * 获取节点ID列表 + */ + @PostConstruct + public void getNodeIDList(){ + try { + //获取实例列表 + List idList = aliYunEcsService.getIDList(); + //为空则创建新节点 + if(idList == null || idList.isEmpty()){ + aliYunEcsService.createAndRunInstance(); + } + log.info("实例ID列表:{}", idList); + gatewayNodeIDCache.put(idList); + } catch (Exception e) { + log.error("获取实例ID列表失败:" + e.getMessage()); + log.error(e.getMessage()); + } + } + + /** + * 获取实例信息 + */ + public void getNodeInfo() { + Long count = 0L; + + ArrayList gatewayNodeInfos = new ArrayList<>(); + + try { + + //获取ID集合 + List ecsIDList = gatewayNodeIDCache.get(); + if (ecsIDList == null || ecsIDList.isEmpty()) { + log.error("实例ID为空"); + return; + } + + StringBuilder ids = new StringBuilder(); + for (String id : ecsIDList) { + ids.append(id).append(","); + } + ids = new StringBuilder(ids.substring(0, ids.length() - 1)); + + //查询所有ID实例的详细信息 + List response = aliYunEcsService.queryInstancesInformation(ids.toString()); + for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance item : response) { + log.info("查询第{}个实例的ID:{}" ,count+1, item.getInstanceId()); + + log.info("地域ID:{}",item.getRegionId()); + + log.info("CPU核心数:{}", item.getCpu()); + + log.info("内存大小:{}MB", item.getMemory()); + + log.info("公网出带宽值:{}Mbit/s",item.getInternetMaxBandwidthOut() + ""); + + 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()); + + log.info("实例名称:{}",item.getInstanceName()); + + log.info("实例状态:{}",item.getStatus()); + + log.info("-----------------------------分割线-----------------------------------"+"/n/n/n"); + + + //实例状态为运行中才加入列表 + //停止的实例不加入列表 + if(item.getStatus().equals("Stopped")){ + //停止的实例不加入列表 + log.info("实例状态为停止,不加入列表"); + continue; + } + //运行中 + if (item.getStatus().equals("Running")) { + //存入集合 + gatewayNodeInfos.add( + new GatewayNodeInfo( + item.getInstanceId(), + item.getInstanceName(), + item.getStatus(), + UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()), + UserUtil.removeBrackets(item.getVpcAttributes().getPrivateIpAddress().ipAddress.toString()), + item.getCreationTime(), + item.getExpiredTime(), + item.getRecyclable() + ) + ); + count++; + } + } + + + } catch (Exception e) { + throw new RuntimeException("获取实例列表失败:" + e.getMessage()); + } + log.info("实例信息列表:{}", gatewayNodeInfos); + + //存入缓存 + gatewayNodeInfoCache.put(gatewayNodeInfos); + + } + + /** + * 获取节点公网IP列表 + */ + public void getNodeIPList() { + //存IP的List + ArrayList nodeIPList = new ArrayList<>(); + + //从缓存中拿到实例信息列表 + List gatewayNodeInfoList = gatewayNodeInfoCache.get(); + + if (gatewayNodeInfoList.isEmpty()) { + log.error("实例信息列表为空!"); + return; + } + + gatewayNodeInfoList.forEach(item -> { + //获取IP + String ip = item.getPublicIpAddress(); + //存入集合 + nodeIPList.add(ip); + }); + + + log.info("实例公网IP列表:{}", nodeIPList); + + //将IP列表存入redis + gatewayNodeIPCache.put(nodeIPList); + + } + + /** + * 获取各个IP的负载量 + */ + public void getIpAndLoadCounts() { + //从缓存中获取实例公网IP列表 + List nodeIPList = gatewayNodeIPCache.get(); + if (nodeIPList.isEmpty()) { + log.error("实例公网IP列表为空!"); + return; + } + + //存各个 服务器的负载量 + ArrayList ipAndLoadCounts = new ArrayList<>(); + + //拿到IP后,获取各个IP的负载量 + nodeIPList.forEach(ip -> { + ipAndLoadCounts.add(mqttUtil.getFetchLoad(ip)); + }); + + log.info("各个IP的负载量:{}", ipAndLoadCounts); + + gatewayIpLoadCountKey.put(ipAndLoadCounts); + } + + /** + * 计算各个IP的权重 + */ + public void getIpAndWeights() { + //从缓存中获取公网IP和负载量列表 + List ipAndLoadCounts = gatewayIpLoadCountKey.get(); + if (ipAndLoadCounts.isEmpty()) { + log.error("负载量列表为空!"); + return; + } + + + //求出空负载的总量 + int emptyLoadCount = 0; + for (NodeLoadNum ipAndLoadCount : ipAndLoadCounts) { + //假设使用2/8原则 一个节点最多能有100个连接 + emptyLoadCount += (80 - ipAndLoadCount.getLoadNum()); + } + + //存储IP和对应的权重 + ArrayList ipAndWeights = new ArrayList<>(); + for (NodeLoadNum ipAndLoadCount : ipAndLoadCounts) { + + NodeLoadWeight ipAndWeight = new NodeLoadWeight( + ipAndLoadCount.getIpName(), + (80 - ipAndLoadCount.getLoadNum()) * 100 / emptyLoadCount + ); + ipAndWeights.add(ipAndWeight); + } + + log.info("实例IP和对应的权重:{}", ipAndWeights);//[IpAndWeight(nodeIp=47.102.158.233, weight=55), IpAndWeight(nodeIp=47.102.123.209, weight=44)] + + gatewayWeightCache.put(ipAndWeights); + } + + /** + * 获取负载节点IP序列 + */ + public void getLoadNodeOrderListByIpAndWeights() { + //从缓存中获取公网IP和权重列表 + List ipAndWeights = gatewayWeightCache.get(); + if (ipAndWeights.isEmpty()) { + log.error("负载节点IP和权重列表为空!"); + return; + } + + ArrayList loadNodeList = new ArrayList<>(); + + Long sum = ipAndWeights.stream() + .mapToLong(NodeLoadWeight::getWeight) + .sum(); + if (sum < 100) { + List list = ipAndWeights.stream() + .sorted(Comparator.comparingLong(NodeLoadWeight::getWeight).reversed()) + .collect(Collectors.toList()); + + //给权重高的节点 权重再加一个 + int countWeight = 0; + for (Long i = sum; i < 100; i++) { + NodeLoadWeight ipAndWeight = list.get(countWeight++ % list.size()); + ipAndWeight.setWeight(ipAndWeight.getWeight() + 1); + } + } + + whFor: + while (true) { + for (NodeLoadWeight ipAndWeight : ipAndWeights) { + Long weight = ipAndWeight.getWeight(); + if (weight > 0) { + loadNodeList.add(ipAndWeight.getIpName()); + } + ipAndWeight.setWeight(weight - 1); + } + + Long sum1 = ipAndWeights.stream() + .mapToLong(NodeLoadWeight::getWeight) + .sum(); + if (sum1 <= 0) { + break whFor; + } + } + + + //IP序列存入缓存 + gatewayOrderCache.put(loadNodeList); + } } diff --git a/src/main/java/com/loadCenter/aliyun/job/LoadCenterController.java b/src/main/java/com/loadCenter/aliyun/job/LoadCenterController.java deleted file mode 100644 index daa017c..0000000 --- a/src/main/java/com/loadCenter/aliyun/job/LoadCenterController.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.loadCenter.aliyun.job; - -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import com.loadCenter.aliyun.common.aliyun.service.AliYunEcsService; -import lombok.extern.log4j.Log4j2; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import com.loadCenter.aliyun.common.redis.service.RedisService; -import java.util.Set; - - -/** - * @ClassName LoadCenterController - * @Author ZeJinG.Su - */ -@Component -@Log4j2 -public class LoadCenterController { - int aa=0; - int bb=0; - @Autowired - StringRedisTemplate redisTemplate; - - @Autowired - private RedisService redisService; - @Autowired - private AliYunEcsService aliYunEcsService; - - /* - * 30秒扫描一次服务器,负载情况 - */ - @Scheduled(cron = "0/5 * * * * ?") - public void scheduleECS() throws Exception { - //假设这里出现了超出预设连接数大于80%,则进行扩容 - OkHttpClient client = new OkHttpClient(); - Set ipCacheSet = redisService.getCacheZSet("ECS"); - log.info("共有个"+ipCacheSet.size()+"服务器"); - - for (String ip : ipCacheSet) { - - String URL = "http://"+ip+":8080/public/cluster"; - Request request = new Request.Builder() - .url(URL) - .get() - .addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)") - .addHeader("Accesstoken", "") - .build(); - - try { - Response response = client.newCall(request).execute(); - - JSONArray jsonArray = JSONArray.parseArray(response.body().string()); - JSONObject jsonObject = jsonArray.getJSONObject(0); - JSONObject mqttInfo = jsonObject.getJSONObject("mqttInfo"); - int connectSize = mqttInfo.getIntValue("connectSize"); - - log.info("服务器:"+ip+"-车辆连接数:"+connectSize); - - redisService.setCacheZSet("ECS", ip,connectSize); - - if (connectSize>=5){ - aa++; - log.info("服务器:"+ip+"-----"+aa+"=="+ipCacheSet.size()+"就可以扩容"); - - if (aa==ipCacheSet.size()){ - - log.info("服务器个数:"+ipCacheSet.size()+",-----循环第"+aa+"次,相等了,需要扩容"); - log.info("执行扩容机制"); - - log.info("扩容中休眠5秒,再返回,确保先创建,确保查询得到结果-------"); - Thread.sleep(5000); - - - log.info("实例id和公网ip存入redis"); - aa=0; - } - - } else { - - aa=0; - } - - - } catch (Exception e) { - e.printStackTrace(); - } - - - } - - - } - - - - -} diff --git a/src/main/java/com/loadCenter/aliyun/job/ScheduledTask.java b/src/main/java/com/loadCenter/aliyun/job/ScheduledTask.java new file mode 100644 index 0000000..c970148 --- /dev/null +++ b/src/main/java/com/loadCenter/aliyun/job/ScheduledTask.java @@ -0,0 +1,137 @@ +package com.loadCenter.aliyun.job; + +import com.loadCenter.aliyun.common.aliyun.service.AliYunEcsService; +import com.loadCenter.aliyun.gateway.cache.GatewayIpLoadCountKey; +import com.loadCenter.aliyun.gateway.cache.GatewayNodeIDCache; +import com.loadCenter.aliyun.gateway.cache.GatewayNodeInfoCache; +import com.loadCenter.aliyun.gateway.model.GatewayNodeInfo; +import com.loadCenter.aliyun.gateway.model.NodeLoadNum; +import lombok.extern.log4j.Log4j2; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + + +/** + * @ClassName ScheduledTask + * @Author ZeJinG.Su + */ +@Component +@Log4j2 +public class ScheduledTask { + + /* + * 阿里云api接口类 + * */ + private final AliYunEcsService aliYunEcsService; + + /* + * 操作缓存 + * */ + private final GatewayIpLoadCountKey gatewayIpLoadCountKey; + + private final GatewayNodeIDCache gatewayNodeIdCache; + + private final GatewayNodeInfoCache gatewayNodeInfoCache; + + public ScheduledTask(AliYunEcsService aliYunEcsService, GatewayIpLoadCountKey gatewayIpLoadCountKey, GatewayNodeIDCache gatewayNodeIdCache, GatewayNodeInfoCache gatewayNodeInfoCache) { + this.aliYunEcsService = aliYunEcsService; + this.gatewayIpLoadCountKey = gatewayIpLoadCountKey; + this.gatewayNodeIdCache = gatewayNodeIdCache; + this.gatewayNodeInfoCache = gatewayNodeInfoCache; + } + + + @Scheduled(cron = "0/10 * * * * ?") + /** + * 动态扩容 + */ + public void dynamicExpansion() { + //先获取所有的负载列表 + List ipAndLoadCounts = gatewayIpLoadCountKey.get(); + if (ipAndLoadCounts.isEmpty()) { + log.error("负载量列表为空!"); + return; + } + + //计算所有节点的负载 + Long connectSize = ipAndLoadCounts.stream().mapToLong(NodeLoadNum::getLoadNum).sum(); + + //求出平均值 + Long avg = connectSize / ipAndLoadCounts.size(); + + if (avg >= 80) { + //执行节点扩容 + + //返回实例的ID + String instanceId; + try { + instanceId = aliYunEcsService.createAndRunInstance(); + } catch (Exception e) { + throw new RuntimeException("节点扩容失败!" + e.getMessage()); + } + + if (!instanceId.isEmpty()) { + log.info("扩容 成功!扩容的节点ip为:" + instanceId); + } + } else { + log.info("暂时不需要扩容"); + } + } + + + @Scheduled(cron = "0/10 * * * * ?") + /** + * 动态缩容 + */ + public void dynamicReduction() { + //求出所有的节点ID + List nodeIds = gatewayNodeIdCache.get(); + + //如果节点数量小于等于1,则不执行缩容,至少保留一个节点 + if (nodeIds.size() <= 1) { + log.info("暂无节点可删除!"); + return; + } + + + //先获取所有的负载列表 + List ipAndLoadCounts = gatewayIpLoadCountKey.get(); + if (ipAndLoadCounts.size() <= 1) { + log.error("负载列表为空!"); + return; + } + + //获取节点信息(IP)集合 + List gatewayNodeInfoList = gatewayNodeInfoCache.get(); + if (gatewayNodeInfoList.isEmpty()) { + log.error("节点信息为空!"); + return; + } + + //判断哪个节点的负载小于30 + + for (GatewayNodeInfo gatewayNodeInfo : gatewayNodeInfoList) {//获取节点的IP + String ip = gatewayNodeInfo.getPublicIpAddress(); + //获取当前循环节点的负载 + Long loadCount = ipAndLoadCounts.stream().filter(ipAndLoadCount -> ipAndLoadCount.getIpName().equals(ip)).findFirst().get().getLoadNum(); + //判断节点的负载是否小于30 + if (loadCount < 30) { + //对这个节点进行缩容 + String instanceId = gatewayNodeInfo.getInstanceId(); + try { + aliYunEcsService.releaseInstances(instanceId); + } catch (Exception e) { + throw new RuntimeException("节点缩容失败!" + e.getMessage()); + } + log.info("节点缩容成功"); + //一次只删除一个节点 + break; + } + } + + } + + +} diff --git a/src/main/java/com/loadCenter/aliyun/service/impl/GatewayLoadServiceImpl.java b/src/main/java/com/loadCenter/aliyun/service/impl/GatewayLoadServiceImpl.java index 86f2f1e..f938e37 100644 --- a/src/main/java/com/loadCenter/aliyun/service/impl/GatewayLoadServiceImpl.java +++ b/src/main/java/com/loadCenter/aliyun/service/impl/GatewayLoadServiceImpl.java @@ -2,22 +2,41 @@ package com.loadCenter.aliyun.service.impl; import com.loadCenter.aliyun.common.aliyun.config.Result; +import com.loadCenter.aliyun.gateway.cache.GatewayOrderCache; import com.loadCenter.aliyun.gateway.model.GatewayNodeInfo; +import com.loadCenter.aliyun.handle.HandleCache; import com.loadCenter.aliyun.service.GatewayLoadService; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; +import java.util.List; + @Service @AllArgsConstructor public class GatewayLoadServiceImpl implements GatewayLoadService { private final Long nodeLength = 100L; + /** + * 负载节点列表 + */ + private final HandleCache handleCache; + /** + * 负载节点信息列表 + */ + private final GatewayOrderCache gatewayOrderCache; + /** + * 获取负载节点的IP序列列表,并返回最后一个IP进行返回 + * @return + */ @Override public Result getAssignedServer() { + handleCache.getLoadNodeOrderListByIpAndWeights(); + List nodeOrderList = gatewayOrderCache.get(); + String result = nodeOrderList.get(nodeOrderList.size() - 1); - return null; + return Result.success(result); } } diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 8192759..a9747b5 100644 --- a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,2 +1,3 @@ com.loadCenter.aliyun.common.redis.configure.RedisConfig com.loadCenter.aliyun.common.redis.service.RedisService + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e1391fb..4528a6d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,10 +1,9 @@ -# Tomcat server: port: 9010 Spring: redis: host: 10.10.25.3 -# host: 127.0.0.1 + # host: 127.0.0.1 port: 6379 password: fffdev