// This file is auto-generated, don't edit it. Thanks. package com.mobai.openApi; import com.alibaba.fastjson2.JSON; import com.aliyun.ecs20140526.models.DescribeInstancesResponse; import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody; import com.aliyun.tea.TeaException; import com.mobai.domain.MqttServerModel; import com.mobai.domain.Result; import com.mobai.domain.flux.ApifoxModel; import com.mobai.service.FluxGetInfoService; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.*; @Log4j2 @Component public class SelectInstances { @Autowired private FluxGetInfoService fluxGetInfoService; @Autowired private RedisTemplate redisTemplate; /** * 使用AK&SK初始化账号Client * * @return Client * @throws Exception */ public static com.aliyun.ecs20140526.Client createClient() throws Exception { // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。 // 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378657.html。 com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 .setAccessKeyId("LTAI5t7vsLXtqTJKve7JipnX") // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。 .setAccessKeySecret("AIyMaSTKQtsB1V5sVqlNAGbQzxgXnS"); // Endpoint 请参考 https://api.aliyun.com/product/Ecs config.endpoint = "ecs.cn-zhangjiakou.aliyuncs.com"; return new com.aliyun.ecs20140526.Client(config); } // 通过接口获取数据 public DescribeInstancesResponse getInfo() { DescribeInstancesResponse describeInstancesResponse = null; try { com.aliyun.ecs20140526.Client client = SelectInstances.createClient(); com.aliyun.ecs20140526.models.DescribeInstancesRequest describeInstancesRequest = new com.aliyun.ecs20140526.models.DescribeInstancesRequest() // .setImageId("m-8vb8qnidv34yj3nbirhc") .setRegionId("cn-zhangjiakou"); com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); describeInstancesResponse = client.describeInstancesWithOptions(describeInstancesRequest, runtime); } catch (Exception e) { throw new RuntimeException(e); } return describeInstancesResponse; } //1分钟 @Scheduled(cron = "0 0/1 * * * ? ") //10秒 // @Scheduled(cron = "0/10 * * * * ? ") public void saveIps() throws Exception { List ips = new ArrayList<>(); DescribeInstancesResponse response = this.getInfo(); try { DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instances = response.getBody().getInstances(); List instance = instances.getInstance(); for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance inst : instance) { List ipAddress = inst .getPublicIpAddress() .getIpAddress(); if (ipAddress.isEmpty()) { continue; } else { ipAddress.forEach(ip -> ips.add(ip)); } } log.info("当前实例ip为{}", ips); } catch (TeaException error) { // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message log.error("错误信息::{}", error.getMessage()); // 诊断地址 log.warn("诊断地址::{}", error.getData().get("Recommend")); com.aliyun.teautil.Common.assertAsString(error.message); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message log.error("错误信息::{}", error.getMessage()); // 诊断地址 if (error.getData() == null) { log.error("错误信息::{}", "error.getData()为空"); } else { log.error("诊断地址::{}", error.getData().get("Recommend")); } com.aliyun.teautil.Common.assertAsString(error.message); } List nodes = new ArrayList<>(); for (String ip : ips) { Result info = fluxGetInfoService.getInfo(ip); // 获取连接总数 String string = redisTemplate.opsForValue().get("onlineCar-" + ip); long connectSize = Long.parseLong(string == null ? "0" : string); log.info("{}::{}", ip, connectSize); //添加到一个容器 nodes.add(new SmallNode(ip, connectSize)); } //负载均横方法 this.getArithmetic(nodes); } /** * 负载均衡算法 * * @param nodes */ private void getArithmetic(List nodes) { // ip num 数量的容器 Map arithmet = new HashMap<>(); BigDecimal sum = new BigDecimal(0); //获取所有的 键 for (SmallNode node : nodes) { BigDecimal value = BigDecimal.valueOf(80 - node.getNum()); //获取总量 sum = sum.add(value); arithmet.put(node.getIp(), value); }// 根据权重总和计算每个节点的特定比例 log.info("总可负载量:{}", arithmet); List ips = new ArrayList<>(); //获取每个ip的分配率 for (String ip : arithmet.keySet()) { //概率 BigDecimal probability = arithmet.get(ip).divide(sum, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)); arithmet.put(ip, probability); log.info("{}可负载率(权重值):{}", ip, probability); } Set ipSet = arithmet.keySet(); BigDecimal finalSum = sum; Map map = new HashMap<>(); // 转换成数量 ipSet.forEach(ip -> map.put(ip, arithmet.get(ip).multiply(finalSum).intValue() / 100)); Long i = 0L; log.info("ip对应可分配车辆:{}", map); int sumInit = map.values().stream().mapToInt(num -> num).sum(); while (true) { ipSet = map.keySet(); Iterator iterator = ipSet.iterator(); i++; while (iterator.hasNext()) { MqttServerModel mqttServerModel = new MqttServerModel(); String ip = iterator.next(); for (SmallNode node : nodes) { if (node.ip.equals(ip)) mqttServerModel = new MqttServerModel(ip, "topic" + nodes.indexOf(node)); } ips.add(mqttServerModel); int i1 = map.get(ip) - 1; map.put(ip, i1); if (i1 == 0) { iterator.remove(); map.remove(ip); } } if (ips.size() == sumInit) { break; } } redisTemplate.opsForList().leftPush("fluxMq", JSON.toJSONString(ips)); // 可负载IP轮询排列 log.info("排列ip,{}", ips); Boolean mqttIp = redisTemplate.delete("mqttIp"); ips.forEach(mqtt -> redisTemplate.opsForList().leftPush("mqttIp", JSON.toJSONString(mqtt))); } @Data @AllArgsConstructor @NoArgsConstructor class SmallNode { private String ip; private long num; } }