master
黄大举 2024-04-19 10:19:01 +08:00
parent 206835eac8
commit 64347438a5
11 changed files with 248 additions and 34 deletions

View File

@ -57,6 +57,12 @@
</distributionManagement>
<dependencies>
<!--MQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- SpringBoot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -6,7 +6,7 @@ import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import com.muyu.loadCenter.config.AliConfig;
import com.muyu.loadCenter.aliyun.utils.UserUtil;
import com.muyu.loadCenter.utils.UserUtil;
import com.muyu.loadCenter.domain.EcsInstanceInfo;
import com.muyu.loadCenter.config.InstanceConfig;
import lombok.extern.log4j.Log4j2;

View File

@ -0,0 +1,86 @@
package com.muyu.loadCenter.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
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;
import org.springframework.context.annotation.Primary;
@Configuration
public class RabbitMqConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback {
public static final Logger logger= LoggerFactory.getLogger(RabbitMqConfig.class);
private RabbitTemplate rabbitTemplate;
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
public static final String QUEUE="queue";
public static final String EXCHANGE="exchange";
public static final String KEY="Key";
@Primary
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
this.rabbitTemplate=rabbitTemplate;
rabbitTemplate.setMessageConverter(messageConverter());
rabbitTemplate();
return rabbitTemplate;
}
public void rabbitTemplate(){
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnsCallback(this);
}
@Bean
public Queue queue(){
return new Queue(QUEUE,true);
}
@Bean
public DirectExchange directExchange(){
return new DirectExchange(EXCHANGE);
}
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(directExchange()).with(KEY);
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
if (ack){
logger.info("{}消息到达交换机",correlationData.getId());
}else{
logger.error("{}消息丢失",correlationData.getId());
}
}
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
logger.error("{}消息未到达队列",returnedMessage.getMessage().getMessageProperties().getMessageId());
}
}

View File

@ -31,6 +31,8 @@ public class GatewayController {
public Result<String> loadNode(){
return Result.success(gatewayLoadService.loadNode());
}
/**
* 30
*

View File

@ -0,0 +1,99 @@
package com.muyu.loadCenter.mq;
import com.muyu.loadCenter.aliyun.service.AliYunEcsService;
import com.muyu.loadCenter.gateway.model.GatewayNodeInfo;
import com.rabbitmq.client.Channel;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* RabbitMQ
* 使Spring AMQP
*/
@RabbitListener(queues = "queue")
@Component
@Log4j2
public class Consumer {
// 注入Spring的StringRedisTemplate以操作Redis
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private AliYunEcsService aliYunEcsService;
/**
*
* 1.
* 2.
* 3. 退
*
* @param gatewayNodeInfo
* @param channel RabbitMQ
* @param message
* @throws IOException RabbitMQ
*/
@RabbitHandler
public void Handler(GatewayNodeInfo gatewayNodeInfo, Channel channel, Message message) throws IOException {
// 消息ID和传递标签
String messageId = message.getMessageProperties().getMessageId();
long deliveryTag = message.getMessageProperties().getDeliveryTag();
// 检查消息是否首次处理
if (!redisTemplate.hasKey("mi"+messageId)){
// 首次处理,存储传递标签
redisTemplate.opsForValue().set("mi"+messageId,deliveryTag+"");
}
try {
// 检查是否重复消费
if (!redisTemplate.hasKey("cf"+messageId)){
// 确认消费并在Redis中做标记
log.info("确认消费");
log.info(gatewayNodeInfo);
// aliYunEcsService.releaseECS(gatewayNodeInfo.getNodeId()); // 释放ECS实例
redisTemplate.opsForValue().set("cf"+messageId,messageId);
channel.basicAck(deliveryTag,false);
}else {
// 重复消费,拒绝处理
log.info("重复消费");
channel.basicReject(deliveryTag,false);
}
} catch (Exception exception) {
// 异常处理逻辑,根据重试次数决定消息处理方式
String s = redisTemplate.opsForValue().get("mi" + messageId);
long old = Long.parseLong(s);
if (deliveryTag==(old+2)){
// 重试三次后,仍然失败,退回消息
log.info("已重试三次,实在消费不了");
channel.basicNack(deliveryTag,false,false);
}else {
// 尝试再次重试
log.info("继续重试");
channel.basicNack(deliveryTag,false,true);
}
}
}
}

View File

@ -3,6 +3,7 @@ package com.muyu.loadCenter.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.loadCenter.aliyun.service.AliYunEcsService;
import com.muyu.loadCenter.config.RabbitMqConfig;
import com.muyu.loadCenter.domain.EcsInstanceInfo;
import com.muyu.loadCenter.domain.WorkGatewayNode;
import com.muyu.loadCenter.gateway.cache.*;
@ -14,12 +15,15 @@ import lombok.extern.log4j.Log4j2;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
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.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* @ProjectName: load_center
@ -53,7 +57,7 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
private final GatewayNodeCache gatewayNodeCache;
@Autowired
private RedisService redisService;
private RabbitTemplate rabbitTemplate;
@ -125,7 +129,6 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
gatewayLoadNodeCache.put(loadNodeList);
Long seriesLoad = gatewayLoadSeriesCache.incrementAndGet();
System.out.println("seriesLoad:" + seriesLoad);
Long seriesLoadIndex = seriesLoad % nodeLength;
@ -178,7 +181,7 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
gatewayZSetNodeCache.put(ip,connectSize);
// 根据连接数判断是否需要进行扩容或缩容
if (connectSize >= 8) {
if (connectSize >= 5) {
aa++;
// 当满足扩容条件时,记录日志并执行扩容操作
if (aa == ipCacheSet.size()) {
@ -199,10 +202,8 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
gatewayNodeInfo.setPublicIdAddress(ecsInstanceInfo.getPublicIpAddress());
gatewayNodeInfo.setPrivateIdAddress(ecsInstanceInfo.getPrivateIpAddress());
gatewayNodeCache.put(ecsInstanceInfo.getPublicIpAddress(), gatewayNodeInfo);
//这里模拟(也可以在别的类里完成) ECS创建成功后服务器发送一条消息服务器正常启动mq可以正常使用存入redis
gatewayZSetNodeCache.put(ecsInstanceInfo.getPublicIpAddress(), 0);
log.info("实例id和公网ip存入redis");
@ -219,18 +220,26 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
//缩容逻辑:删除连接数过低的服务器实例,出现连续两个节点连接数低于5的则执行缩容操作
if (bb >= 2){
log.info("释放实例"+ip);
gatewayZSetNodeCache.remove(ip);
GatewayNodeInfo gatewayNodeInfo = gatewayNodeCache.get(ip);
//这里再来个异步操作 将 GatewayNodeInfo 对象传走,进行异步操作
rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE,RabbitMqConfig.KEY,gatewayNodeInfo, message -> {
message.getMessageProperties().setMessageId(gatewayNodeInfo.getNodeId());
return message;
},new CorrelationData(UUID.randomUUID().toString()));
// 1.分批次解除连接的车辆
// 2.删除各个相关的redis缓存
// aliYunEcsService.releaseECS(gatewayNodeInfo.getNodeId()); // 释放ECS实例
bb = 0;
@ -240,25 +249,6 @@ public class GatewayLoadServiceImpl implements GatewayLoadService {
bb = 0;
}
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -1,7 +1,7 @@
package com.muyu.loadCenter.aliyun.utils;
package com.muyu.loadCenter.utils;
import com.muyu.loadCenter.aliyun.utils.uuid.IdUtils;
import com.muyu.loadCenter.utils.uuid.IdUtils;
import com.muyu.loadCenter.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

View File

@ -1,4 +1,4 @@
package com.muyu.loadCenter.aliyun.utils.uuid;
package com.muyu.loadCenter.utils.uuid;
/**
* ID

View File

@ -1,4 +1,4 @@
package com.muyu.loadCenter.aliyun.utils.uuid;
package com.muyu.loadCenter.utils.uuid;
import java.security.MessageDigest;

View File

@ -10,6 +10,19 @@ Spring:
port: 6379
rabbitmq:
username: guest
password: guest
virtualHost: /
port: 5672
host: 121.89.221.195
listener:
simple:
prefetch: 1 # 每次只能获取一条,处理完成才能获取下一条
publisher-confirm-type: correlated #确认消息已发送到交换机(Exchange)
publisher-returns: true #确认消息已发送到队列(Queue)
config:
ali:
access-key-id: LTAI5tANGefs2gi8nsu4AoSZ

View File

@ -22,8 +22,26 @@ public class LoadTest {
@Test
public void load() {
GatewayNodeInfo gatewayNodeInfo = redisService.getCacheObject("gateway:node:info:39.101.193.188");
System.out.println(gatewayNodeInfo);
redisService.setCacheZSet("gateway:zSet:count","39.103.130.89",0);
redisService.setCacheZSet("gateway:zSet:count","121.89.221.195",0);
// GatewayNodeInfo gatewayNodeInfo = new GatewayNodeInfo();
// gatewayNodeInfo.setPublicIdAddress("39.103.130.89");
// gatewayNodeInfo.setPrivateIdAddress("39.103.130.89");
// gatewayNodeInfo.setNodeId("i-8vbctj4u8ohgaqt9wwre");
//
// redisService.setCacheObject("gateway:node:info:39.103.130.89",gatewayNodeInfo);
// gatewayNodeInfo.setPublicIdAddress("121.89.221.195");
// gatewayNodeInfo.setPrivateIdAddress("121.89.221.195");
// gatewayNodeInfo.setNodeId("i-8vbemtl328dk8er33ylv");
//
// redisService.setCacheObject("gateway:node:info:121.89.221.195",gatewayNodeInfo);
}