diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 98d47c0..f11e788 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -3,6 +3,8 @@ + + diff --git a/.idea/misc.xml b/.idea/misc.xml index 82dbec8..dc19a8b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,10 @@ + + + + + diff --git a/VehicleSimulation/src/main/java/com/Demo1.java b/VehicleSimulation/src/main/java/com/Demo1.java new file mode 100644 index 0000000..e6384c3 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/Demo1.java @@ -0,0 +1,112 @@ +package com; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.DoubleStream; + +/** + * @ClassName demo_01 + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 14:44 + */ +public class Demo1 { + /** + * 主函数示例,展示了如何从一个HashMap中提取信息, + * 计算权重总和,按权重分配特定数量的节点,并进行相应的排序和归约。 + * + * @param args 命令行参数(未使用) + */ + public static void main(String[] args) { + // 初始化一个HashMap,存储节点ID及其对应的权重 + HashMap< String, Double > nodeMap = new HashMap<> ( ){{ + put ( "node_1",0.35 ); + put ( "node_2",0.53 ); + put ( "node_3",0.17 ); + put ( "node_4",0.46 ); + }}; + + // 将节点Map转换为NodeInfo对象的List + List< NodeInfo > nodeInfoList = nodeMap.entrySet ( ) + .stream ( ).map ( NodeInfo::new ) + .toList ( ); + System.out.println (nodeInfoList ); + + // 计算所有节点权重的总和 + double sum = nodeInfoList.stream ( ) + .flatMapToDouble ( nodeInfo -> DoubleStream.of ( nodeInfo.getWeight ( ) ) ) + .sum ( ); + System.out.println (sum ); + + // 根据权重总和计算每个节点的特定比例 + BigDecimal spec = new BigDecimal ( 100 ).divide ( new BigDecimal ( sum ), 2, BigDecimal.ROUND_HALF_UP ); + + + // 使用计算出的比例,为每个节点分配整数数量 + Map< String, Integer > collect = nodeInfoList.stream ( ).collect ( Collectors.toMap ( NodeInfo::getId, + nodeInfo -> spec.multiply ( BigDecimal.valueOf ( nodeInfo.getWeight ( ) ) ).setScale ( 0, RoundingMode.DOWN ).intValue (), + (o1, o2) -> o1 ) ); + System.out.println (collect ); + + // 计算已分配节点数量的总和 + int reduce = collect.values ( ).stream ( ).reduce ( 0, Integer::sum ); + System.out.println (reduce ); + + // 计算剩余的未分配节点数量 + int free=100-reduce; + + // 为剩余的未分配节点分配数量 + nodeInfoList.stream () + .sorted ( Comparator.comparingInt ( o->o.getWeight ().intValue () ) ) + .limit ( free ) + .forEach ( nodeInfo -> { + collect.put ( nodeInfo.getId (),collect.get ( nodeInfo.getId ())+1 ); + } ); + System.out.println (collect ); + + // 准备一个字符串数组,以存储最终的节点分配结果 + String[] nodeArray = new String[100]; + int intArrCursor= -1; + + // 将分配了数量的节点填充到字符串数组中,直到数组满或所有节点都已处理完毕 + while (collect.size ()>1){ + Iterator< Map.Entry< String, Integer > > specMapIterator = collect.entrySet ( ).iterator ( ); + while (specMapIterator.hasNext ()){ + Map.Entry< String, Integer > entry = specMapIterator.next ( ); + Integer value = entry.getValue ( ); + if (value>0){ + nodeArray[++intArrCursor] = entry.getKey ( ); + entry.setValue ( value-1 ); + } + if (value==0){ + specMapIterator.remove (); + } + } + } + System.out.println (collect ); + System.out.println (Arrays.toString ( nodeArray ) ); + } +} +class NodeInfo{ + private String id; + private Double weight; + + public NodeInfo (String id, Double weight){ + this.id=id; + this.weight=weight; + } + + public NodeInfo (Map.Entry entry){ + this.id=entry.getKey (); + this.weight=entry.getValue ()*100; + } + + public String getId(){ + return id; + } + public Double getWeight(){ + return weight; + } +} diff --git a/VehicleSimulation/src/main/java/com/muyu/config/ConfirmCallbackConfig.java b/VehicleSimulation/src/main/java/com/muyu/config/ConfirmCallbackConfig.java new file mode 100644 index 0000000..d161182 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/config/ConfirmCallbackConfig.java @@ -0,0 +1,48 @@ +//package com.muyu.config; +// +//import org.springframework.amqp.rabbit.connection.CorrelationData; +//import org.springframework.amqp.rabbit.core.RabbitTemplate; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.PostConstruct; +// +///** +// * 消息发送确认配置 消息发送到交换机的确认 +// */ +//@Component +//public class ConfirmCallbackConfig implements RabbitTemplate.ConfirmCallback { +// +// @Autowired +// private RabbitTemplate rabbitTemplate; +// +// /** +// * @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执 +// * @PostConstruct bean 被初始化的时候执行的方法的注解 +// * @PreDestory bean 被销毁的时候执行的方法的注解 +// */ +// @PostConstruct +// public void init() { +// rabbitTemplate.setConfirmCallback(this); +// } +// +// /** +// * 交换机不管是否收到消息的一个回调方法 +// * +// * @param correlationData 消息相关数据 +// * @param ack 交换机是否收到消息 +// * @param cause 失败原因 +// */ +// @Override +// public void confirm(CorrelationData correlationData, boolean ack, String cause) { +// if (ack) { +// // 消息投递到 broker 的状态,true表示成功 +// System.out.println("消息发送成功!"); +// } else { +// // 发送异常 +// System.out.println("发送异常原因 = " + cause); +// // TODO 可以将消息 内容 以及 失败的原因 记录到 日志表中 +// } +// } +// +//} diff --git a/VehicleSimulation/src/main/java/com/muyu/config/RabbitAdminConfig.java b/VehicleSimulation/src/main/java/com/muyu/config/RabbitAdminConfig.java new file mode 100644 index 0000000..98d4be1 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/config/RabbitAdminConfig.java @@ -0,0 +1,53 @@ +//package com.muyu.config; +// +//import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +//import org.springframework.amqp.rabbit.connection.ConnectionFactory; +//import org.springframework.amqp.rabbit.core.RabbitAdmin; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +// +///** +// * RabbitAdmin是RabbitMQ的一个Java客户端库,它提供了管理RabbitMQ资源的功能。它是通过与RabbitMQ服务器进行交互来执行管理操作的。 +// */ +//@Configuration +//public class RabbitAdminConfig { +// +// @Value("${spring.rabbitmq.host}") +// private String host; +// @Value("${spring.rabbitmq.username}") +// private String username; +// @Value("${spring.rabbitmq.password}") +// private String password; +// @Value("${spring.rabbitmq.virtualhost}") +// private String virtualhost; +// +// /** +// * 构建 RabbitMQ的连接工厂 +// * @return +// */ +// @Bean +// public ConnectionFactory connectionFactory() { +// CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); +// connectionFactory.setAddresses(host); +// connectionFactory.setUsername(username); +// connectionFactory.setPassword(password); +// connectionFactory.setVirtualHost(virtualhost); +// // 配置发送确认回调时,次配置必须配置,否则即使在RabbitTemplate配置了ConfirmCallback也不会生效 +// connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED); +// connectionFactory.setPublisherReturns(true); +// return connectionFactory; +// } +// +// /** +// * 自己初始化 RabbitAdmin +// * @param connectionFactory +// * @return +// */ +// @Bean +// public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) { +// RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); +// rabbitAdmin.setAutoStartup(true); +// return rabbitAdmin; +// } +//} diff --git a/VehicleSimulation/src/main/java/com/muyu/config/RabbitmqConfig.java b/VehicleSimulation/src/main/java/com/muyu/config/RabbitmqConfig.java new file mode 100644 index 0000000..1c218cc --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/config/RabbitmqConfig.java @@ -0,0 +1,15 @@ +//package com.muyu.config; +// +//import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +//import org.springframework.amqp.support.converter.MessageConverter; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +// +//@Configuration +//public class RabbitmqConfig { +// // 消息转换配置 +// @Bean +// public MessageConverter jsonMessageConverter() { +// return new Jackson2JsonMessageConverter(); +// } +//} diff --git a/VehicleSimulation/src/main/java/com/muyu/config/ReturnCallbackConfig.java b/VehicleSimulation/src/main/java/com/muyu/config/ReturnCallbackConfig.java new file mode 100644 index 0000000..c034f45 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/config/ReturnCallbackConfig.java @@ -0,0 +1,34 @@ +//package com.muyu.config; +// +//import org.springframework.amqp.core.ReturnedMessage; +//import org.springframework.amqp.rabbit.core.RabbitTemplate; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.PostConstruct; +// +///** +// * 消息发送到队列的确认 一旦消息发送到队列失败 则会执行 returnedMessage 方法 +// */ +//@Component +//public class ReturnCallbackConfig implements RabbitTemplate.ReturnsCallback { +// +// @Autowired +// private RabbitTemplate rabbitTemplate; +// +// @PostConstruct // @PostContruct是spring框架的注解,在⽅法上加该注解会在项⽬启动的时候执⾏该⽅法,也可以理解为在spring容器初始化的时候执 +// public void init() { +// rabbitTemplate.setReturnsCallback(this); +// } +// +// /** +// * 消息发送到 队列失败 执行的 方法 +// * @param returnedMessage the returned message and metadata. +// */ +// @Override +// public void returnedMessage(ReturnedMessage returnedMessage) { +// System.out.println("消息" + returnedMessage.getMessage().toString() + "被交换机" + returnedMessage.getExchange() + "回退!" +// + "退回原因为:" + returnedMessage.getReplyText()); +// // 回退了所有的信息,可做补偿机制 记录到 数据库 +// } +//} diff --git a/VehicleSimulation/src/main/java/com/muyu/constants/RabbitMQOneConstants.java b/VehicleSimulation/src/main/java/com/muyu/constants/RabbitMQOneConstants.java new file mode 100644 index 0000000..a3bac53 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/constants/RabbitMQOneConstants.java @@ -0,0 +1,22 @@ +package com.muyu.constants; + +/** + * @ClassName RabbitMQOneConstants + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 22:04 + */ +public class RabbitMQOneConstants { + /** + * 验证码 + */ + public static final String SEND_CODE="send_code_queue"; + + + //发送短消息队列名称 + public static final String SEND_SHORT_MESSAGE_QUEUE_NAME = "send_short_message"; + + + //查看的日志队列名称 + public static final String QUERY_LOG_QUEUE_NAME = "query_log_message"; +} diff --git a/VehicleSimulation/src/main/java/com/muyu/consumer/ConnectionConsumer.java b/VehicleSimulation/src/main/java/com/muyu/consumer/ConnectionConsumer.java new file mode 100644 index 0000000..a5c9c67 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/consumer/ConnectionConsumer.java @@ -0,0 +1,25 @@ +package com.muyu.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.rabbitmq.client.Channel; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +/** + * @ClassName ConnectionConsumer + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 21:57 + */ +@Component +public class ConnectionConsumer { + + @RabbitListener(queuesToDeclare = @Queue(name = "ADD_LOG_AAA")) + public void receive(Message message, Channel channel) { + ObjectMapper mapper = new ObjectMapper ( ); +// mapper.convertValue ( messageConverter. ) + + } +} diff --git a/VehicleSimulation/src/main/java/com/muyu/domain/ServerNode.java b/VehicleSimulation/src/main/java/com/muyu/domain/ServerNode.java index 3f45a79..2319f37 100644 --- a/VehicleSimulation/src/main/java/com/muyu/domain/ServerNode.java +++ b/VehicleSimulation/src/main/java/com/muyu/domain/ServerNode.java @@ -12,6 +12,16 @@ import lombok.Data; @Data @AllArgsConstructor public class ServerNode { + /** + * ip地址 + */ private String ip; + /** + * 端口号 + */ private Integer port; + /** + * 服务器的负载百分比 + */ + private Double loadPercentage; } diff --git a/VehicleSimulation/src/main/java/com/muyu/loadcenter/common/AccessPool.java b/VehicleSimulation/src/main/java/com/muyu/loadcenter/common/AccessPool.java new file mode 100644 index 0000000..870f6a2 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/loadcenter/common/AccessPool.java @@ -0,0 +1,50 @@ +package com.muyu.loadcenter.common; + +import com.muyu.domain.model.MqttServerModel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.log4j.Log4j2; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @ClassName AccessPool + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 22:39 + */ +@Data +@NoArgsConstructor +@Log4j2 +public class AccessPool { + private static Integer sequence = 0; + + private static Map accessPools = new HashMap<> (); + + public static void initAccessPools(List mqttServerModels){ + accessPools = mqttServerModels.stream().collect( Collectors.toMap(MqttServerModel::getBroker, Function.identity())); + } + + public static void addAccessPool(MqttServerModel mqttServerModel){ + accessPools.put(mqttServerModel.getBroker(),mqttServerModel); + } + + public static void lookAccessPools(){ + accessPools.forEach((k,v)->{ + log.info("key:"+k+" value:"+v.toString()); + }); + } + + public static MqttServerModel getMqttServerModel(){ + if (sequence == accessPools.size()){ + sequence = 0; + } + Set strings = accessPools.keySet(); + return accessPools.get(strings.toArray()[sequence++]); + } +} diff --git a/VehicleSimulation/src/main/java/com/muyu/service/LoadCenterService.java b/VehicleSimulation/src/main/java/com/muyu/service/LoadCenterService.java new file mode 100644 index 0000000..c68adf2 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/service/LoadCenterService.java @@ -0,0 +1,14 @@ +package com.muyu.service; + +import com.muyu.common.Result; + +/** + * @ClassName LoadCenterService + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 22:35 + */ +public interface LoadCenterService { + Result getDescribeInstances(); + +} diff --git a/VehicleSimulation/src/main/java/com/muyu/service/impl/LoadCenterServiceImpl.java b/VehicleSimulation/src/main/java/com/muyu/service/impl/LoadCenterServiceImpl.java new file mode 100644 index 0000000..2ce858b --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/service/impl/LoadCenterServiceImpl.java @@ -0,0 +1,29 @@ +package com.muyu.service.impl; + +import com.muyu.common.Result; +import com.muyu.service.LoadCenterService; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +import static com.muyu.utils.ECSTool.runEcsInstance; + +/** + * @ClassName LoadCenterServiceImpl + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/27 22:36 + */ +@Service +@Log4j2 +public class LoadCenterServiceImpl implements LoadCenterService { + @Override + public Result getDescribeInstances() { + try { + runEcsInstance("cn-zhangjiakou", "lt-8vbepqjihmawbkqcwkcm"); + return Result.success (); + } catch (Exception e) { + log.error ( "getDescribeInstances error:{}", e ); + throw new RuntimeException ( e ); + } + } +} diff --git a/VehicleSimulation/src/main/java/com/muyu/service/impl/VechileServiceImpl.java b/VehicleSimulation/src/main/java/com/muyu/service/impl/VechileServiceImpl.java index f667ace..46431be 100644 --- a/VehicleSimulation/src/main/java/com/muyu/service/impl/VechileServiceImpl.java +++ b/VehicleSimulation/src/main/java/com/muyu/service/impl/VechileServiceImpl.java @@ -142,8 +142,8 @@ public class VechileServiceImpl extends ServiceImpl impl public ServerNode assignServerNode(String vehicleId) { // 这里为了简化,我们随机选择一个节点 List< ServerNode > serverNodes = Arrays.asList ( - new ServerNode ( "192.168.1.1", 8080 ), - new ServerNode ( "192.168.1.2", 8081 ) + new ServerNode ( "192.168.1.1", 8080,0.23 ), + new ServerNode ( "192.168.1.2", 8081 ,0.50) ); if (serverNodes.isEmpty()) { diff --git a/VehicleSimulation/src/main/java/com/muyu/utils/ECSTool.java b/VehicleSimulation/src/main/java/com/muyu/utils/ECSTool.java new file mode 100644 index 0000000..ba46698 --- /dev/null +++ b/VehicleSimulation/src/main/java/com/muyu/utils/ECSTool.java @@ -0,0 +1,99 @@ +package com.muyu.utils; +import com.aliyun.ecs20140526.Client; +import com.aliyun.ecs20140526.models.RunInstancesRequest; +import com.aliyun.tea.TeaException; +import com.aliyun.teaopenapi.models.Config; +import com.aliyun.teautil.models.RuntimeOptions; +import lombok.SneakyThrows; +import okhttp3.*; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + + +/** + * ECS工具类,提供创建ECS实例的功能 + */ +public class ECSTool { + /** + * 创建ECS客户端 + * @return ECS客户端实例 + * @throws Exception 如果配置信息不正确或网络问题,将抛出异常 + * 注意:此方法用于演示,实际使用时请替换为安全的鉴权方式,如STS + * 更多鉴权访问方式参考:https://help.aliyun.com/document_detail/378657.html + */ + public static Client createClient() throws Exception { + // 配置ECS客户端的基本信息,包括访问密钥和endpoint + Config config = new Config() + .setAccessKeyId("LTAI5tPTk3MFkmCGBbnQgmrM") // 示例Access Key ID,实际使用时应从环境变量获取 + .setAccessKeySecret("q7rLjxrI0SLBXlvNT4VmYcHCNCY2p6"); // 示例Access Key Secret,实际使用时应从环境变量获取 + config.endpoint = "ecs.cn-zhangjiakou.aliyuncs.com"; // 设置ECS服务的访问地址 + // 创建并返回ECS客户端实例 + return new Client(config); + } + + /** + * 创建并运行ECS实例 + * @param regionId 地域ID + * @param launchTemplateId 启动模板ID + * @throws Exception 如果调用API时发生错误,将抛出异常 + */ + public static void runEcsInstance(String regionId, String launchTemplateId) throws Exception { + // 创建ECS客户端 + Client client = ECSTool.createClient(); + // 设置运行实例的请求参数 + RunInstancesRequest runInstancesRequest = new RunInstancesRequest() + .setRegionId(regionId) + .setLaunchTemplateId(launchTemplateId); + // 创建运行选项 + RuntimeOptions runtime = new RuntimeOptions(); + + try { + // 调用API运行实例 + client.runInstancesWithOptions(runInstancesRequest, runtime); + } catch (Exception error) { + // 处理API调用过程中出现的异常 + System.out.println(error.getMessage()); + if (error instanceof TeaException) { + // 处理特定类型的异常,如TeaException + TeaException teaError = (TeaException) error; + System.out.println(teaError.getData().get("Recommend")); // 打印诊断推荐链接 + com.aliyun.teautil.Common.assertAsString(teaError.getMessage()); // 断言错误信息 + } else { + // 处理其他类型的异常 + System.out.println(error.getMessage()); + } + } + } + public static void main(String[] args) throws Exception { + List argsList = Arrays.asList(args); + // 示例调用,实际使用时需要传入 区域 ID 和 启动模板 ID + runEcsInstance("cn-zhangjiakou", "lt-8vbepqjihmawbkqcwkcm"); + } + +// @SneakyThrows +// public static void main(String[] args) { +// OkHttpClient client = new OkHttpClient.Builder() +// .build(); +// +// // 注意:GET请求通常不需要MediaType和RequestBody +// Request request = new Request.Builder() +// .url("http://fluxmq.muyu.icu/public/cluster") +// .method("GET", null) // 对于GET请求,通常不需要设置RequestBody,所以传入null +// .addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)") +// .addHeader("Access-Token", "2f68dbbf-519d-4f01-9636-e2421b68f379") // 确保使用正确的头部名称和令牌值 +// .build(); +// +// try (Response response = client.newCall(request).execute()) { +// if (!response.isSuccessful()) { +// throw new IOException("Unexpected code " + response); +// } else { +// // 打印响应体 +// System.out.println(response ); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +} diff --git a/VehicleSimulation/src/main/resources/application.yml b/VehicleSimulation/src/main/resources/application.yml index 0d919e5..0dd47ed 100644 --- a/VehicleSimulation/src/main/resources/application.yml +++ b/VehicleSimulation/src/main/resources/application.yml @@ -1,6 +1,18 @@ server: port: 82 spring: + rabbitmq: + host: 111.229.102.61 + port: 5672 + username: guest + password: guest + virtual-host: / + listener: + simple: + prefetch: 1 + acknowledge-mode: manual # 接收 消费 消息手动确认 + direct: + acknowledge-mode: manual # 接收 消费 消息手动确认 mvc: static-path-pattern: /static/** @@ -86,7 +98,7 @@ forest: # 服务器配置 mqtt: server: - host: tcp://47.92.65.101:1883 + host: tcp://39.100.87.192:1883 topic: test1 admin: host: http://127.0.0.1:${server.port} diff --git a/ZhiLian-LoadBalancing/pom.xml b/ZhiLian-LoadBalancing/pom.xml new file mode 100644 index 0000000..14798f7 --- /dev/null +++ b/ZhiLian-LoadBalancing/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + com.fei + open-api + 1.0-SNAPSHOT + + + ZhiLian-LoadBalancing + + + 17 + 17 + UTF-8 + + + + + com.aliyun + ecs20140526 + 5.1.8 + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.47 + + + com.squareup.okhttp3 + okhttp + + + org.mybatis + mybatis-spring + 3.0.0 + compile + + + + + diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/LoadBalancingApplication.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/LoadBalancingApplication.java new file mode 100644 index 0000000..06e210c --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/LoadBalancingApplication.java @@ -0,0 +1,12 @@ +package com.zhiLian; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +@SpringBootApplication +public class LoadBalancingApplication { + public static void main(String[] args) { + SpringApplication.run ( LoadBalancingApplication.class ); + } +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/Result.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/Result.java new file mode 100644 index 0000000..8a75ab7 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/Result.java @@ -0,0 +1,83 @@ +package com.zhiLian.common; + +import lombok.Data; + +import java.io.Serializable; + + + +@Data +public class Result implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 成功 + * ================================================================================================================= + */ + public static final int SUCCESS = ResultConstants.SUCCESS; + + /** + * 失败 + * ================================================================================================================= + */ + public static final int FAIL = ResultConstants.ERROR; + + /** + * 返回状态码 + * ================================================================================================================= + */ + private int code; + + /** + * 响应信息 + * ================================================================================================================= + */ + private String msg; + + /** + * 响应数据 + * ================================================================================================================= + */ + private T data; + + public static Result success() { + return restResult(null, SUCCESS, ResultConstants.SUCCESS_MSG); + } + + public static Result success(T data) { + return restResult(data, SUCCESS, ResultConstants.SUCCESS_MSG); + } + + public static Result success(T data, String msg) { + return restResult(data, SUCCESS, msg); + } + + public static Result error() { + return restResult(null, FAIL, ResultConstants.ERROR_MSG); + } + + public static Result error(String msg) { + return restResult(null, FAIL, msg); + } + + public static Result error(T data) { + return restResult(data, FAIL, ResultConstants.ERROR_MSG); + } + + public static Result error(T data, String msg) { + return restResult(data, FAIL, msg); + } + + public static Result error(int code, String msg) { + return restResult(null, code, msg); + } + + private static Result restResult(T data, int code, String msg) { + Result apiResult = new Result<>(); + apiResult.setCode(code); + apiResult.setData(data); + apiResult.setMsg(msg); + return apiResult; + } +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/ResultConstants.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/ResultConstants.java new file mode 100644 index 0000000..a15f1ca --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/common/ResultConstants.java @@ -0,0 +1,22 @@ +package com.zhiLian.common; + + + + +public class ResultConstants { + + /** + * 成功标记 + * ================================================================================================================= + */ + public static final Integer SUCCESS = 200; + public static final String SUCCESS_MSG = "操作成功"; + + /** + * 失败标记 + * ================================================================================================================= + */ + public static final Integer ERROR = 500; + public static final String ERROR_MSG = "操作异常"; + +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/controller/LoadBalanceController.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/controller/LoadBalanceController.java new file mode 100644 index 0000000..69d9ba0 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/controller/LoadBalanceController.java @@ -0,0 +1,67 @@ +package com.zhiLian.controller; + +import com.zhiLian.common.Result; +import com.zhiLian.service.LoadBalanceService; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +import java.util.List; + +/** + * @ClassName LoadBalanceController + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/28 9:12 + */ +@RestController +@RequestMapping("loadBalance") +@Log4j2 +public class LoadBalanceController { + + + @Autowired + private LoadBalanceService loadBalanceService; + + /** + * 创建实例 + */ + @GetMapping("/createConnect") + public void createConnect() { + loadBalanceService.createConnect(); + log.info("创建实例成功"); + } + +// /** +// * 停止实例 +// */ +// @GetMapping("/stopConnect") +// public void stopConnect(@RequestParam String instanceId) { +// loadBalanceService.stopConnect(instanceId); +// log.info("停止实例成功"); +// } + + /** + * 销毁实例 + * instanceId 实例id + */ + @GetMapping("/removeConnect") + public void removeConnect(@RequestParam String instanceId) { + loadBalanceService.removeConnect(instanceId); + log.info("销毁实例成功"); + } + + /** + * 获取实例连接 + */ + @GetMapping("/getIpList") + public Result< List > getIpList() { + List ipList = loadBalanceService.getIpList(); +// ipListThread = ipList; + return Result.success(ipList); + } +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/resp/ConnectResp.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/resp/ConnectResp.java new file mode 100644 index 0000000..1657d26 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/resp/ConnectResp.java @@ -0,0 +1,236 @@ +package com.zhiLian.resp; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 连接响应 + * @author YunFei.Du + * @date 9:10 2024/5/27 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ConnectResp { + + /** + * 节点名称 + */ + private String nodeName; + /** + * 节点版本 + */ + private String version; + /** + * 启动时间 + */ + private String startJvmTime; + /** + * 节点ID + */ + private String clusterId; + /** + * HTTP请求地址 + */ + private String httpUrl; + /** + * MQTTS请求地址 + */ + private String mqttUrl; + /** + * websocket请求地址 + */ + private String websocketUrl; + + + private FlowInfo flowInfo; + + + /** + * 节点状态 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + private static class FlowInfo { + /** + * 写入总吞吐量 + */ + private String writeBytesHistory; + /** + * 读取总吞吐量 + */ + private String readBytesHistory; + /** + * 上次读取吞吐量 + */ + private String lastReadThroughput; + /** + * 上次写入吞吐量 + */ + private String lastWriteThroughput; + /** + * 实写字节 + */ + private String realWriteBytes; + } + + public CpuInfo cpuInfo; + + + /** + * cpu使用信息 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class CpuInfo { + /** + * CPU使用信息 + */ + private String cSys; + /** + * 空闲率 + */ + private String idle; + /** + * I/O等待 + */ + private String iowait; + /** + * 用户态使用率 + */ + private String user; + /** + * CPU核数 + */ + private Integer cpuNum; + } + + + public JvmInfo jvmInfo; + + /** + * jvm使用信息 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class JvmInfo { + /** + * JAVA目录 + */ + private String jdkHome; + /** + * 堆内存 + */ + private String heapCommit; + /** + * 堆最大内存 + */ + private String heapMax; + /** + * 线程数量 + */ + private Integer threadCount; + /** + * 文件描述(句柄 + */ + private String fileDescriptors; + /** + * 非堆最大空间 + */ + private String noHeapMax; + /** + * 非堆初始化空间 + */ + private String noHeapInit; + /** + * JDK版本 + */ + private String jdkVersion; + /** + * 堆初始化空间 + */ + private String heapInit; + + /** + * 堆使用空间 + */ + private String heapUsed; + /** + * 非堆空间 + */ + private String noHeapCommit; + /** + * 非堆使用空间 + */ + private String noHeapUsed; + + } + + + public MqttInfo mqttInfo; + + /** + * MQTT事件信息 + */ + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class MqttInfo { + /** + * 连接事件数量 + */ + private Integer connectEventSize; + /** + * 订阅事件数量 + */ + private Integer subscribeEventSize; + /** + * 发布重试事件数量 + */ + private Integer publishRetryEventSize; + /** + * 主题数量 + */ + private Integer topicSize; + /** + * 断开链接数量 + */ + private Integer disconnectEventSize; + /** + * 订阅数量 + */ + private Integer subscribeSize; + /** + * 推送数量 + */ + private Integer publishEventSize; + /** + * 关闭事件数量 + */ + private Integer closeEventSize; + /** + * 链接总数 + */ + private Integer connectSize; + /** + * 保留消息数量 + */ + private Integer retainSize; + /** + * 取消订阅数量 + */ + private Integer unSubscribeEventSize; + } + + +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/LoadBalanceService.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/LoadBalanceService.java new file mode 100644 index 0000000..a1f7461 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/LoadBalanceService.java @@ -0,0 +1,21 @@ +package com.zhiLian.service; + +import java.util.List; + +/** + * @ClassName LoadBalanceService + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/28 9:25 + */ +public interface LoadBalanceService { + void createConnect(); + + void removeConnect(String instanceId); + + void stopConnect(String instanceId); + + List< String> getIpList(); + + +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/impl/LoadBalanceServiceImpl.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/impl/LoadBalanceServiceImpl.java new file mode 100644 index 0000000..ba4eca0 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/service/impl/LoadBalanceServiceImpl.java @@ -0,0 +1,55 @@ +package com.zhiLian.service.impl; + +import com.aliyun.ecs20140526.models.DescribeInstancesResponse; +import com.aliyun.ecs20140526.models.ModifySecurityGroupRuleResponse; +import com.google.gson.Gson; +import com.zhiLian.service.LoadBalanceService; +import lombok.SneakyThrows; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.zhiLian.utils.ECSTool.*; + +/** + * @ClassName LoadBalanceService + * @Description 描述 + * @Author YunFei.Du + * @Date 2024/5/28 9:25 + */ +@Service +@Log4j2 +public class LoadBalanceServiceImpl implements LoadBalanceService { + + @SneakyThrows + @Override + public void createConnect() { + runEcsInstance("cn-zhangjiakou", "lt-8vbepqjihmawbkqcwkcm"); + + } + + @Override + public void removeConnect(String instanceId) { + + try { + runEcsStop (instanceId); + } catch (Exception e) { + log.error ( "getDescribeInstances error:{}", e ); + throw new RuntimeException ( e ); + } + } + + @SneakyThrows + @Override + public void stopConnect(String instanceId) { + runEcsRemove ( instanceId ); + } + + @SneakyThrows + @Override + public List< String > getIpList() { + FindInstance ( "cn-zhangjiakou" ); + return null; + } +} diff --git a/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/utils/ECSTool.java b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/utils/ECSTool.java new file mode 100644 index 0000000..b1e93b2 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/java/com/zhiLian/utils/ECSTool.java @@ -0,0 +1,175 @@ +package com.zhiLian.utils; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.aliyun.ecs20140526.Client; +import com.aliyun.ecs20140526.models.*; +import com.aliyun.tea.TeaException; +import com.aliyun.tea.TeaModel; +import com.aliyun.teaopenapi.models.Config; +import com.aliyun.teautil.Common; +import com.aliyun.teautil.models.RuntimeOptions; +import lombok.extern.log4j.Log4j2; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + + * ECS实例工具类 + * @author YunFei.Du + * @date 9:30 2024/5/28 + */ +@Log4j2 +public class ECSTool { + /** + * 创建ECS客户端 + * @return ECS客户端实例 + * @throws Exception 如果配置信息不正确或网络问题,将抛出异常 + * 注意:此方法用于演示,实际使用时请替换为安全的鉴权方式,如STS + * 更多鉴权访问方式参考:https://help.aliyun.com/document_detail/378657.html + */ + public static Client createClient() throws Exception { + // 配置ECS客户端的基本信息,包括访问密钥和endpoint + Config config = new Config() + .setAccessKeyId("LTAI5tPTk3MFkmCGBbnQgmrM") // 示例Access Key ID,实际使用时应从环境变量获取 + .setAccessKeySecret("q7rLjxrI0SLBXlvNT4VmYcHCNCY2p6"); // 示例Access Key Secret,实际使用时应从环境变量获取 + config.endpoint = "ecs.cn-zhangjiakou.aliyuncs.com"; // 设置ECS服务的访问地址 + // 创建并返回ECS客户端实例 + return new Client(config); + } + + /** + * 创建并运行ECS实例 + * @param regionId 地域ID + * @param launchTemplateId 启动模板ID + * @throws Exception 如果调用API时发生错误,将抛出异常 + */ + public static void runEcsInstance(String regionId, String launchTemplateId) throws Exception { + // 创建ECS客户端 + Client client = ECSTool.createClient(); + // 设置运行实例的请求参数 + RunInstancesRequest runInstancesRequest = new RunInstancesRequest() + .setRegionId(regionId) + .setLaunchTemplateId(launchTemplateId); + // 创建运行选项 + RuntimeOptions runtime = new RuntimeOptions(); + + try { + // 调用API运行实例 + client.runInstancesWithOptions(runInstancesRequest, runtime); + } catch (Exception error) { + // 处理API调用过程中出现的异常 + System.out.println(error.getMessage()); + if (error instanceof TeaException) { + // 处理特定类型的异常,如TeaException + TeaException teaError = (TeaException) error; + System.out.println(teaError.getData().get("Recommend")); // 打印诊断推荐链接 + com.aliyun.teautil.Common.assertAsString(teaError.getMessage()); // 断言错误信息 + } else { + // 处理其他类型的异常 + System.out.println(error.getMessage()); + } + } + } + + + + /** + * 停止实例 + */ + public static void runEcsStop(String instanceId) throws Exception { + // 创建ECS客户端 + Client client = ECSTool.createClient(); + StopInstanceRequest stopInstanceRequest = new StopInstanceRequest () + .setInstanceId(instanceId); + RuntimeOptions runtime = new RuntimeOptions(); + try { + // 复制代码运行请自行打印 API 的返回值 + client.stopInstanceWithOptions(stopInstanceRequest, runtime); + } catch (TeaException error) { + // 处理API调用过程中出现的异常 + System.out.println(error.getMessage()); + if (error instanceof TeaException) { + // 处理特定类型的异常,如TeaException + TeaException teaError = (TeaException) error; + System.out.println(teaError.getData().get("Recommend")); // 打印诊断推荐链接 + com.aliyun.teautil.Common.assertAsString(teaError.getMessage()); // 断言错误信息 + } else { + // 处理其他类型的异常 + System.out.println(error.getMessage()); + } + } + } + /** + * 销毁实例 + */ + public static void runEcsRemove(String instanceId) throws Exception { + // 创建ECS客户端 + Client client = ECSTool.createClient(); + DeleteInstanceRequest deleteInstanceRequest = new DeleteInstanceRequest () + .setInstanceId(instanceId); + RuntimeOptions runtime = new RuntimeOptions(); + try { + // 复制代码运行请自行打印 API 的返回值 + client.deleteInstanceWithOptions(deleteInstanceRequest, runtime); + } catch (TeaException error) { + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } + } + + + + public static void FindInstance( String regionId) throws Exception { + // 创建ECS客户端 + Client client = ECSTool.createClient(); + DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest () + .setRegionId(regionId); + RuntimeOptions runtime = new RuntimeOptions(); + List ipList = new ArrayList<> (); + try { + // 复制代码运行请自行打印 API 的返回值 + DescribeInstancesResponse response = client.describeInstancesWithOptions ( describeInstancesRequest, runtime ); + + List> ipListList = response.getBody().instances.getInstance().stream().map(instance -> instance.publicIpAddress.ipAddress).collect( Collectors.toList()); + for (List strings : ipListList) { + for (String ip : strings) { + ipList.add(ip); + } + System.out.println("------------------------"); + } + log.info ( "ipList: " + ipList ); + } catch (TeaException error) { + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } catch (Exception _error) { + TeaException error = new TeaException(_error.getMessage(), _error); + // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 + // 错误 message + System.out.println(error.getMessage()); + // 诊断地址 + System.out.println(error.getData().get("Recommend")); + com.aliyun.teautil.Common.assertAsString(error.message); + } + } + +} diff --git a/ZhiLian-LoadBalancing/src/main/resources/application.yml b/ZhiLian-LoadBalancing/src/main/resources/application.yml new file mode 100644 index 0000000..52ca826 --- /dev/null +++ b/ZhiLian-LoadBalancing/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 84 diff --git a/pom.xml b/pom.xml index 0559083..76664c6 100644 --- a/pom.xml +++ b/pom.xml @@ -10,11 +10,41 @@ pom VehicleSimulation + ZhiLian-LoadBalancing - - 17 - 17 - UTF-8 - + + spring-boot-starter-parent + org.springframework.boot + 2.6.2 + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + 2021.0.0 + pom + import + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + 2021.1 + pom + import + + + + com.alibaba.nacos + nacos-client + 2.0.4 + + + + diff --git a/src/main/java/com/fei/Main.java b/src/main/java/com/fei/Main.java index 02ffbea..7db3ec5 100644 --- a/src/main/java/com/fei/Main.java +++ b/src/main/java/com/fei/Main.java @@ -1,4 +1,4 @@ -package com.fei; +package com.zhiLian; public class Main { public static void main(String[] args) {