204 lines
8.3 KiB
Java
204 lines
8.3 KiB
Java
// 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<String, String> 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<String> ips = new ArrayList<>();
|
||
DescribeInstancesResponse response = this.getInfo();
|
||
try {
|
||
DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instances = response.getBody().getInstances();
|
||
List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> instance =
|
||
instances.getInstance();
|
||
for (DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance inst : instance) {
|
||
List<String> 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<SmallNode> nodes = new ArrayList<>();
|
||
for (String ip : ips) {
|
||
Result<ApifoxModel> 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<SmallNode> nodes) {
|
||
// ip num 数量的容器
|
||
Map<String, BigDecimal> 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<MqttServerModel> 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<String> ipSet = arithmet.keySet();
|
||
|
||
BigDecimal finalSum = sum;
|
||
Map<String, Integer> 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<String> 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;
|
||
}
|
||
}
|