diff --git a/src/main/java/com/loadcenter/service/impl/LoadCenterServiceImpl.java b/src/main/java/com/loadcenter/service/impl/LoadCenterServiceImpl.java index b1c631e..36564b9 100644 --- a/src/main/java/com/loadcenter/service/impl/LoadCenterServiceImpl.java +++ b/src/main/java/com/loadcenter/service/impl/LoadCenterServiceImpl.java @@ -12,16 +12,18 @@ import com.loadcenter.common.utils.mqtt.MqttUtil; import com.loadcenter.service.LoadCenterService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; /** - * @ClassName LoadCenterServiceImpl - * @Description 负载中心业务实现层 - * @Author Can.J - * @Date 2024/4/16 + * @ClassName LoadCenterServiceImpl + * @Description 负载中心业务实现层 + * @Author Can.J + * @Date 2024/4/16 */ @Service @Slf4j @@ -33,73 +35,143 @@ public class LoadCenterServiceImpl implements LoadCenterService { @Autowired private AliYunEcsService aliYunEcsService; + @Scheduled(cron = "0/2 * * * * ?") + public void refreshECSIPListCache() { + getECSIPList(); + } + /** * 获取 分配的一个服务器IP + * * @return */ @Override public Result getAssignedServer() { + //从缓存中获取实例公网IP列表 + if (redis.getCacheList("实例IP列表:").isEmpty()) { + throw new RuntimeException("实例IP列表为空!"); + } + //将结果转成JSON串 + String string = JSON.toJSONString(redis.getCacheList("实例IP列表:")); + //再转成String泛型 的 List + List escIPList = JSON.parseArray(string, String.class); + //通过IP列表 获取各个IP对应的负载量 + List ipAndLoadCounts = this.getIpAndLoadCounts(escIPList); + + //通过IP和对应的负载量,计算出IP对应的权重 + List ipAndWeights = this.getIpAndWeights(ipAndLoadCounts); + + //通过IP和权重,计算负载节点的IP列表 + List loadNodeList = this.getLoadNodeListByIpAndWeights(ipAndWeights); + + //获取缓存里最后一个IP进行返回 + //最后一个IP进行返回 + String result = loadNodeList.get(loadNodeList.size() - 1); + return Result.success(result); + } + + /** + * 获取所有实例公网的IP列表 + */ + @PostConstruct + public void getECSIPList() { //存IP的List - ArrayList ipList = new ArrayList<>(); - //获取张家口区的实例ID列表 + ArrayList ecsIPList = new ArrayList<>(); + try { + //获取张家口区的实例ID列表 + List ecsIDList = aliYunEcsService.getIDList(); - List idList = aliYunEcsService.getIDList(); - idList.forEach(id -> { - //调用方法,获取对应ID实例的IP - try { - List result = aliYunEcsService.queryInstancesInformation(id); + //将ID进行拼接,用逗号分隔 + String ids = ""; + for (String id : ecsIDList) { + ids += id + ","; + } + ids = ids.substring(0, ids.length() - 1); - //获取集合第一个的属性 - DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance response = result.get(0); - - //获取添加的实例的公网ip - String instanceIp = UserUtil.removeBrackets(response.getPublicIpAddress().getIpAddress().toString()); - ipList.add(instanceIp); - - } catch (Exception e) { - log.error(e.getMessage()); - } + List response = aliYunEcsService.queryInstancesInformation(ids); + response.forEach(item -> { + //获取添加的实例的公网ipe + String ip = UserUtil.removeBrackets(item.getPublicIpAddress().getIpAddress().toString()); + ecsIPList.add(ip); }); } catch (Exception e) { - log.error(e.getMessage()); + log.error("获取实例ID列表失败:{}", e.getMessage()); + throw new RuntimeException(e); } - - log.info(JSON.toJSONString(ipList)); - //将IP列表存入redis - redis.deleteObject("服务器列表:"); - redis.setCacheList("服务器列表:", ipList); + redis.deleteObject("实例IP列表:"); + redis.setCacheList("实例IP列表:", ecsIPList); + log.info("实例公网IP列表:{}", ecsIPList); + } + + + /** + * @ClassName LoadCenterServiceImpl + * @Description 通过IP获取各个IP的负载量 + * @Author Can.J + * @Date 2024/4/18 + */ + public List getIpAndLoadCounts(List ecsIPList) { //存各个 服务器的负载量 ArrayList ipAndLoadCounts = new ArrayList<>(); - ipList.forEach(ip -> { - //拿到IP后,获取各个IP的负载量 + //拿到IP后,获取各个IP的负载量 + ecsIPList.forEach(ip -> { int fetchLoad = mqttUtil.getFetchLoad(ip); ipAndLoadCounts.add(new IpAndLoadCount(ip, fetchLoad)); }); + log.info("各个IP的负载量:{}", ipAndLoadCounts); + + return ipAndLoadCounts; + } + + + /** + * @ClassName LoadCenterServiceImpl + * @Description 通过IP和对应的负载量,计算出IP对应的权重 + * @Author Can.J + * @Date 2024/4/18 + */ + public List getIpAndWeights(List ipAndLoadCounts) { //求出空负载的总量 int emptyLoadCount = 0; for (IpAndLoadCount ipAndLoadCount : ipAndLoadCounts) { - //假设使用2/8原则 + //假设使用2/8原则 一个节点最多能有100个连接 emptyLoadCount += (80 - ipAndLoadCount.getLoadCount()); } //存储IP和对应的权重 ArrayList ipAndWeights = new ArrayList<>(); for (IpAndLoadCount ipAndLoadCount : ipAndLoadCounts) { - IpAndWeight ipAndWeight = new IpAndWeight(ipAndLoadCount.getIp(), (80 - ipAndLoadCount.getLoadCount()) * 100 / emptyLoadCount); + IpAndWeight ipAndWeight = new IpAndWeight( + ipAndLoadCount.getIp(), + (80 - ipAndLoadCount.getLoadCount()) * 100 / emptyLoadCount + ); ipAndWeights.add(ipAndWeight); } - log.info(JSON.toJSONString(ipAndWeights)); + log.info("实例IP和对应的权重:{}", ipAndWeights);//[IpAndWeight(nodeIp=47.102.158.233, weight=55), IpAndWeight(nodeIp=47.102.123.209, weight=44)] + return ipAndWeights; + } + + + /** + * @ClassName LoadCenterServiceImpl + * @Description 通过IP和权重,计算负载节点的IP列表 + * @Author Can.J + * @Date 2024/4/18 14:09 + */ + public List getLoadNodeListByIpAndWeights(List ipAndWeights) { ArrayList loadNodeList = new ArrayList<>(); - int sum = ipAndWeights.stream().mapToInt(IpAndWeight::getWeight).sum(); + int sum = ipAndWeights.stream() + .mapToInt(IpAndWeight::getWeight) + .sum(); if (sum < 100) { List list = ipAndWeights.stream().sorted(((o1, o2) -> o2.getWeight() - o1.getWeight())).toList(); @@ -128,16 +200,14 @@ public class LoadCenterServiceImpl implements LoadCenterService { break whFor; } } + //节点IP列表存入缓存 redis.deleteObject("work:node:gateway"); redis.setCacheList("work:node:gateway", loadNodeList); - //获取缓存里最后一个IP进行返回 - //最后一个IP进行返回 - String result = loadNodeList.get(loadNodeList.size() - 1); - return Result.success(result); + log.info("负载节点的IP列表:{}", loadNodeList); + return loadNodeList; } - }