GPU模块设计
This commit is contained in:
@ -4,17 +4,21 @@ import com.bipt.intelligentapplicationorchestrationservice.gpu.dao.GpuResourceDa
|
||||
import com.bipt.intelligentapplicationorchestrationservice.gpu.exception.CacheInitException;
|
||||
import com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@Transactional // 添加类级别事务管理
|
||||
@Component
|
||||
public class CacheManager {
|
||||
@Autowired
|
||||
@ -34,7 +38,9 @@ public class CacheManager {
|
||||
@Value("${cache.init-batch-size:500}")
|
||||
private int initBatchSize;
|
||||
|
||||
private static final Logger log = org.slf4j.LoggerFactory.getLogger(CacheManager.class);
|
||||
// 全量加载(带分页和分布式锁)
|
||||
@Transactional(propagation = Propagation.REQUIRED) // 方法级别覆盖
|
||||
@PostConstruct
|
||||
public void loadFullCache() {
|
||||
if (tryLock()) {
|
||||
@ -114,22 +120,29 @@ public class CacheManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 带重试机制的缓存刷新
|
||||
private void refreshWithRetry(GpuResource entity) {
|
||||
public void refreshWithRetry(GpuResource entity) {
|
||||
try {
|
||||
setCacheWithTTL(entity);
|
||||
} catch (RedisConnectionFailureException ex) {
|
||||
// 3次重试逻辑
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try {
|
||||
log.info("重试第 {} 次", i + 1); // 添加日志
|
||||
Thread.sleep(1000);
|
||||
setCacheWithTTL(entity);
|
||||
return;
|
||||
} catch (InterruptedException e) {
|
||||
if (i == 2) {
|
||||
throw new CacheInitException("缓存刷新失败: " + entity.getGPUId().toString());
|
||||
}
|
||||
|
||||
log.error("重试失败", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
throw new CacheInitException("缓存刷新失败: " + entity.getGPUId().toString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,6 @@ import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisPassword;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.bipt.intelligentapplicationorchestrationservice.gpu.config;
|
||||
|
||||
import com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource;
|
||||
import io.lettuce.core.ClientOptions;
|
||||
import io.lettuce.core.SocketOptions;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -13,6 +15,8 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
@Value("${spring.data.redis.host}")
|
||||
@ -21,7 +25,7 @@ public class RedisConfig {
|
||||
@Value("${spring.data.redis.port}")
|
||||
private int redisPort;
|
||||
|
||||
@Value("${spring.data.redis.username}") // 若无需用户名可删除
|
||||
@Value("${spring.data.redis.username}")
|
||||
private String redisUsername;
|
||||
|
||||
@Value("${spring.data.redis.password}")
|
||||
@ -32,16 +36,35 @@ public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
// 1. 创建 SocketOptions
|
||||
SocketOptions socketOptions = SocketOptions.builder()
|
||||
.connectTimeout(Duration.ofSeconds(15)) // 连接超时
|
||||
.keepAlive(true) // 启用 TCP Keep-Alive
|
||||
.build();
|
||||
|
||||
// 2. 构建 ClientOptions
|
||||
ClientOptions clientOptions = ClientOptions.builder()
|
||||
.socketOptions(socketOptions)
|
||||
.autoReconnect(true) // 启用自动重连
|
||||
.build();
|
||||
|
||||
// 3. 集成到 Lettuce 配置
|
||||
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
|
||||
.clientOptions(clientOptions) // 注入 ClientOptions
|
||||
.commandTimeout(Duration.ofSeconds(30)) // 全局命令超时
|
||||
.build();
|
||||
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
|
||||
config.setHostName(redisHost);
|
||||
config.setPort(redisPort);
|
||||
config.setUsername(redisUsername); // Redis 6.0+ 支持用户名
|
||||
config.setPassword(RedisPassword.of(redisPassword));
|
||||
|
||||
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
|
||||
.useSsl() // 启用 SSL
|
||||
.disablePeerVerification() // 跳过证书验证(仅测试环境)
|
||||
.build();
|
||||
// LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
|
||||
// .commandTimeout(Duration.ofSeconds(30)) // 增加命令超时
|
||||
// .socketOptions(SocketOptions.builder()
|
||||
// .connectTimeout(Duration.ofSeconds(15)) // TCP连接超时
|
||||
// .build())
|
||||
// .build();
|
||||
|
||||
return new LettuceConnectionFactory(config, clientConfig);
|
||||
}
|
||||
@ -55,8 +78,9 @@ public class RedisConfig {
|
||||
// }
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, GpuResource> redisTemplate(){
|
||||
RedisTemplate<String, GpuResource> template = new RedisTemplate<>();
|
||||
public RedisTemplate<String, Object> redisTemplate(){
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
//RedisTemplate<String, GpuResource> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(redisConnectionFactory());
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
|
@ -41,8 +41,8 @@ public interface GpuResourceDao {
|
||||
* @param offset 起始位置
|
||||
* @param limit 每页数量
|
||||
*/
|
||||
@Select("SELECT * FROM ipz.gpu_resource " +
|
||||
"ORDER BY GPUId ASC LIMIT #{limit} OFFSET #{offset}")
|
||||
// @Select("SELECT * FROM ipz.gpu_resource " +
|
||||
// "ORDER BY GPUId ASC LIMIT #{limit} OFFSET #{offset}")
|
||||
List<GpuResource> findByPage(@Param("offset") int offset,
|
||||
@Param("limit") int limit);
|
||||
|
||||
@ -50,22 +50,22 @@ public interface GpuResourceDao {
|
||||
* 增量数据查询(缓存同步用)
|
||||
* @param since 起始时间
|
||||
*/
|
||||
@Select("SELECT *, is_deleted FROM ipz.gpu_resource " +
|
||||
"WHERE update_time > #{since} " +
|
||||
"ORDER BY update_time ASC")
|
||||
// @Select("SELECT *, is_deleted FROM ipz.gpu_resource " +
|
||||
// "WHERE update_time > #{since} " +
|
||||
// "ORDER BY update_time ASC")
|
||||
List<GpuResource> findModifiedSince(@Param("since") LocalDateTime since);
|
||||
|
||||
/**
|
||||
* 带锁查询(防缓存击穿)
|
||||
*/
|
||||
@Select("SELECT * FROM ipz.gpu_resource " +
|
||||
"WHERE GPUId = #{gpuId} FOR UPDATE NOWAIT")
|
||||
// @Select("SELECT * FROM ipz.gpu_resource " +
|
||||
// "WHERE GPUId = #{gpuId} FOR UPDATE NOWAIT")
|
||||
GpuResource selectByIdWithLock(@Param("gpuId") Long gpuId);
|
||||
|
||||
/**
|
||||
* 动态条件查询(管理界面筛选用)
|
||||
*/
|
||||
@SelectProvider(type = GpuSqlBuilder.class, method = "buildDynamicQuery")
|
||||
// @SelectProvider(type = GpuSqlBuilder.class, method = "buildDynamicQuery")
|
||||
List<GpuResource> selectByFields(@Param("params") Map<String, Object> params);
|
||||
}
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
package com.bipt.intelligentapplicationorchestrationservice.gpu.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.time.Clock;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class CacheUpdateEvent extends ApplicationEvent {
|
||||
public enum OperationType{
|
||||
FULL_SYNC,
|
||||
INCREMENTAL_UPDATE,
|
||||
INVALIDATE
|
||||
}
|
||||
|
||||
|
||||
private OperationType operationType;
|
||||
private final String eventType;
|
||||
private final Long resourceId;
|
||||
private final Long timestamp;
|
||||
|
||||
// 基础构造函数
|
||||
public CacheUpdateEvent(Object source, String eventType, Long resourceId) {
|
||||
super(source); // 必须调用父类构造方法
|
||||
this.eventType = eventType;
|
||||
this.resourceId = resourceId;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public CacheUpdateEvent(Object source, String eventType, Long resourceId, Clock clock) {
|
||||
super(source);
|
||||
this.eventType = eventType;
|
||||
this.resourceId = resourceId;
|
||||
this.timestamp = clock.millis(); // 允许外部控制时间戳
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +1,74 @@
|
||||
package com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity;
|
||||
|
||||
import com.bipt.intelligentapplicationorchestrationservice.gpu.cache.RedisCacheService;
|
||||
import jakarta.persistence.*;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.Data;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "Gpu_Resource")
|
||||
@Data
|
||||
//@Entity
|
||||
//@Table(name = "Gpu_Resource")
|
||||
public class GpuResource {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public void setGPUId(Long GPUId) {
|
||||
this.GPUId = GPUId;
|
||||
}
|
||||
|
||||
public void setGPUModel(String GPUModel) {
|
||||
this.GPUModel = GPUModel;
|
||||
}
|
||||
|
||||
public void setGPUMemorySize(Integer GPUMemorySize) {
|
||||
this.GPUMemorySize = GPUMemorySize;
|
||||
}
|
||||
|
||||
public void setIsDeleted(Integer isDeleted) {
|
||||
this.isDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
Ip = ip;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
CreateTime = createTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
UpdateTime = updateTime;
|
||||
}
|
||||
|
||||
@TableField("GPUId")
|
||||
private Long GPUId;
|
||||
|
||||
@Column(nullable = false, length = 64)
|
||||
@TableField("GPUModel")
|
||||
private String GPUModel;
|
||||
|
||||
@Column(nullable = false)
|
||||
@TableField("GPUMemorySize")
|
||||
private Integer GPUMemorySize;
|
||||
|
||||
@Column(name = "is_deleted", nullable = false)
|
||||
@TableField("is_deleted")
|
||||
private Integer isDeleted = 0;
|
||||
|
||||
public @Pattern(regexp = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$") String getIp() {
|
||||
return Ip;
|
||||
@TableField("Ip")
|
||||
private String Ip;
|
||||
|
||||
@TableField("CreatedTime")
|
||||
private LocalDateTime CreateTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private LocalDateTime UpdateTime;
|
||||
|
||||
public GpuResource(long l, String s, boolean b) {
|
||||
this.GPUId = l;
|
||||
this.GPUModel = s;
|
||||
this.isDeleted = b ? 1 : 0;
|
||||
}
|
||||
// public @Pattern(regexp = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$") String getIp() {
|
||||
// return Ip;
|
||||
// }
|
||||
|
||||
public Long getGPUId() {
|
||||
return GPUId;
|
||||
@ -51,13 +90,7 @@ public class GpuResource {
|
||||
return isDeleted != 0;
|
||||
}
|
||||
|
||||
@Column(nullable = false, length = 15)
|
||||
@Pattern(regexp = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$")
|
||||
private String Ip;
|
||||
|
||||
@Column(updatable = false)
|
||||
@CreationTimestamp
|
||||
private LocalDateTime CreateTime;
|
||||
|
||||
public GpuResource(Long Id, String Model, Integer MemorySize, String ip, LocalDateTime create_time) {
|
||||
this.GPUId = Id;
|
||||
|
@ -53,15 +53,7 @@ public class GpuManageServiceImpl implements GpuManageService {
|
||||
GpuResource entity = gpuMapper.toEntity(dto);
|
||||
gpuDao.updateById(entity);
|
||||
}
|
||||
// private GpuResponseDTO convertToResponseDTO(GpuResource entity) {
|
||||
// return new GpuResponseDTO.Builder()
|
||||
// .id(entity.getGPUId())
|
||||
// .model(entity.getGPUModel())
|
||||
// .memory(entity.getGPUMemorySize())
|
||||
// .ip(entity.getIp())
|
||||
// .createdTime(entity.getCreateTime())
|
||||
// .build();
|
||||
// }
|
||||
|
||||
@Override
|
||||
//模糊匹配查询
|
||||
public List<GpuResponseDTO> searchByCriteria(String model, Integer memorySize, String ip) {
|
||||
|
@ -1,27 +1,33 @@
|
||||
spring.application.name=intelligent-application-orchestration-service
|
||||
|
||||
spring.datasource.url=jdbc:kingbase8://116.205.121.200:54321/Ipz
|
||||
spring.datasource.username=system
|
||||
spring.datasource.password=root
|
||||
spring.datasource.driver-class-name=com.kingbase8.Driver
|
||||
spring.jpa.database-platform=org.hibernate.dialect.Kingbase8Dialect
|
||||
#spring.datasource.url=jdbc:mysql://localhost:3306/Ipz
|
||||
#spring.datasource.username=root
|
||||
#spring.datasource.password=zxc25864
|
||||
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
#spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
|
||||
#spring.datasource.url=jdbc:kingbase8://116.205.121.200:54321/Ipz
|
||||
#spring.datasource.username=system
|
||||
#spring.datasource.password=root
|
||||
#spring.datasource.driver-class-name=com.kingbase8.Driver
|
||||
#spring.jpa.database-platform=org.hibernate.dialect.Kingbase8Dialect
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/Ipz
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=zxc25864
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
|
||||
spring.datasource.hikari.maximum-pool-size=10
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.connection-timeout=30000
|
||||
|
||||
# Redis ????
|
||||
spring.data.redis.host=116.205.121.200
|
||||
spring.data.redis.host=127.0.0.1
|
||||
spring.data.redis.port=6379
|
||||
#spring.data.redis.host=116.205.121.200
|
||||
#spring.data.redis.port=6379
|
||||
spring.data.redis.username=default
|
||||
spring.data.redis.password=your_strong_password
|
||||
spring.data.redis.ssl.enabled=true
|
||||
|
||||
mq.queue.cache-update=cache_update_queue
|
||||
spring.data.redis.password=Jbjhhzstsl97@
|
||||
spring.data.redis.ssl.enabled=false
|
||||
|
||||
#mq.queue.cache-update=cache_update_queue
|
||||
|
||||
mybatis-plus.mapper-locations=classpath:mapper/*.xml
|
||||
mybatis-plus.configuration.map-underscore-to-camel-case=true
|
||||
mybatis-plus.type-aliases-package=com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity
|
||||
|
||||
#mybatis.mapper-locations=classpath:mapper/*.xml
|
||||
#mybatis.type-aliases-package=com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity
|
||||
|
@ -1,19 +1,57 @@
|
||||
<!-- src/main/resources/mapper/GpuResourceMapper.xml -->
|
||||
<select id="selectByCondition" resultType="GpuResource">
|
||||
SELECT * FROM ipz.gpu_resource
|
||||
<where>
|
||||
<if test="gpuId != null">
|
||||
GPUId = #{gpuId}
|
||||
</if>
|
||||
<if test="ipPattern != null and ipPattern != ''">
|
||||
AND Ip LIKE CONCAT('%', #{ipPattern}, '%')
|
||||
</if>
|
||||
<if test="modelKeyword != null and modelKeyword != ''">
|
||||
AND GPUModel LIKE CONCAT('%', #{modelKeyword}, '%')
|
||||
</if>
|
||||
<if test="startTime != null and endTime != null">
|
||||
AND CreatedTime BETWEEN #{startTime} AND #{endTime}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY GPUId DESC
|
||||
</select>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.bipt.intelligentapplicationorchestrationservice.gpu.dao.GpuResourceDao">
|
||||
|
||||
<!-- 动态条件查询 -->
|
||||
<select id="selectByFields"
|
||||
resultType="com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource">
|
||||
SELECT *
|
||||
FROM ipz.gpu_resource
|
||||
<where>
|
||||
is_deleted = 0
|
||||
<if test="params.model != null and params.model != ''">
|
||||
AND GPUModel LIKE CONCAT('%', #{params.model}, '%')
|
||||
</if>
|
||||
<if test="params.memoryMin != null">
|
||||
AND GPUMemorySize >= #{params.memoryMin}
|
||||
</if>
|
||||
<if test="params.ip != null and params.ip != ''">
|
||||
AND Ip = #{params.ip}
|
||||
</if>
|
||||
<if test="params.startTime != null and params.endTime != null">
|
||||
AND update_time BETWEEN #{params.startTime} AND #{params.endTime}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY GPUId DESC
|
||||
</select>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
<select id="findByPage"
|
||||
resultType="com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource">
|
||||
SELECT *
|
||||
FROM ipz.gpu_resource
|
||||
WHERE is_deleted = 0
|
||||
ORDER BY GPUId ASC
|
||||
LIMIT #{limit} OFFSET #{offset}
|
||||
</select>
|
||||
|
||||
<!-- 增量同步查询 -->
|
||||
<select id="findModifiedSince"
|
||||
resultType="com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource">
|
||||
SELECT *, is_deleted
|
||||
FROM ipz.gpu_resource
|
||||
WHERE update_time > #{since}
|
||||
ORDER BY update_time ASC
|
||||
</select>
|
||||
|
||||
<!-- 带锁查询 -->
|
||||
<select id="selectByIdWithLock"
|
||||
resultType="com.bipt.intelligentapplicationorchestrationservice.gpu.model.entity.GpuResource">
|
||||
SELECT *
|
||||
FROM ipz.gpu_resource
|
||||
WHERE GPUId = #{gpuId}
|
||||
FOR UPDATE NOWAIT
|
||||
</select>
|
||||
|
||||
</mapper>
|
Reference in New Issue
Block a user