设计(1):DB/Redis容量监控

1. 监控设计方案

1.1 需求

  • 监控Redis容量
  • 监控数据库容量
  • 可配置监控时间间隔和是否开启监控

1.2 方案设计

  • Redis容量监控:通过RedisTemplate执行Redis命令INFO MEMORY,解析返回结果获取内存信息
  • 数据库容量监控:通过JdbcTemplate执行SQL语句,解析返回结果获取容量信息
  • 监控任务:使用ScheduledExecutorService实现定时任务,定时执行监控操作
  • 配置管理:使用Spring的@ConfigurationProperties注解管理监控配置

1.3 代码实现

  • RedisMemoryMonitor类:封装Redis容量监控逻辑
  • DBMemoryMonitor类:封装数据库容量监控逻辑
  • ScheduledTask类:实现定时任务,根据监控配置决定是否执行监控操作

2. 技术选型与设计

2.1 选型要求

  • 提高应用性能,降低资源消耗
  • 适应高并发场景,支持多线程操作

2.2 连接池选型

  • HikariCP:轻量级、高性能、资源占用小,适合高并发场景
  • Druid:功能丰富,但较重,适合有复杂业务逻辑或需要详细监控的场景
  • C3P0:老牌连接池,稳定性好,但性能不如HikariCP

2.3 连接池设计

  • HikariConfig:使用配置类管理HikariCP连接池配置
  • RedisConnectionUtils:使用ThreadLocal管理Redis连接,避免多线程竞争问题
  • JdbcTemplate和RedisTemplate:在使用连接时,使用连接池获取连接,执行操作后释放连接

2.4 代码实现Demo

(1)HikariConfig类:管理HikariCP连接池配置

@Configuration
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public class HikariConfig {
    
    private String jdbcUrl;
    private String username;
    private String password;
    private String driverClassName;
    private Integer maximumPoolSize;
    
    @Bean
    public HikariDataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(jdbcUrl);
        config.setUsername(username);
        config.setPassword(password);
        config.setDriverClassName(driverClassName);
        config.setMaximumPoolSize(maximumPoolSize);
        return new HikariDataSource(config);
    }
    
    // getter and setter methods
}

(2)RedisConnectionUtils类:封装获取和释放Redis连接的方法,使用ThreadLocal管理连接

public class RedisConnectionUtils {
    
    private static ThreadLocal<RedisConnection> redisConnectionThreadLocal = new ThreadLocal<>();
    
    public static RedisConnection getConnection(RedisConnectionFactory redisConnectionFactory) {
        RedisConnection redisConnection = redisConnectionThreadLocal.get();
        if (redisConnection == null) {
            redisConnection = redisConnectionFactory.getConnection();
            redisConnectionThreadLocal.set(redisConnection);
        }
        return redisConnection;
    }
    
    public static void releaseConnection() {
        RedisConnection redisConnection = redisConnectionThreadLocal.get();
        if (redisConnection != null) {
            redisConnection.close();
            redisConnectionThreadLocal.remove();
        }
    }
}

(3)RedisTemplateUtils类:使用RedisConnectionUtils获取连接池连接,创建RedisTemplate

public class RedisTemplateUtils {
    
    public static RedisTemplate<String, String> createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    
    public static void execute(RedisConnectionFactory redisConnectionFactory, RedisCallback<Void> redisCallback) {
        RedisConnection redisConnection = null;
        try {
            redisConnection = RedisConnectionUtils.getConnection(redisConnectionFactory);
            redisCallback.doInRedis(redisConnection);
        } finally {
            RedisConnectionUtils.releaseConnection();
        }
    }
}

(4)JdbcTemplateUtils类:使用HikariCP连接池获取连接,创建JdbcTemplate

public class JdbcTemplateUtils {
    
    public static JdbcTemplate createJdbcTemplate(HikariDataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    public static void execute(HikariDataSource dataSource, ConnectionCallback<Void> connectionCallback) {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            connectionCallback.doInConnection(connection);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

3. 定时任务

3.1 需求

  • 实现定时任务,每天定时查询并统计数据库和Redis的容量信息,并发送邮件告警
  • 定时任务可配置,可以动态修改任务执行时间和告警开关

3.2 设计

  • 使用Spring的@Scheduled注解实现定时任务
  • 定义ScheduledTask类,封装定时任务的执行逻辑,如查询容量信息和发送邮件告警等
  • 使用动态配置,将任务执行时间和告警开关参数化,使用数据库表或者配置文件存储
  • 使用注解@Value注入动态配置参数,从而实现动态修改任务执行时间和告警开关的功能

3.3 代码实现Demo

@Component
public class ScheduledTask {
    private final Logger logger = LoggerFactory.getLogger(ScheduledTask.class);

    @Autowired
    private DatabaseMemoryMonitor databaseMemoryMonitor;

    @Autowired
    private RedisMemoryMonitor redisMemoryMonitor;

    @Autowired
    private EmailService emailService;

    @Value("${schedule.task.time}")
    private String taskTime;

    @Value("${schedule.task.alarmSwitch}")
    private boolean alarmSwitch;

    // 每天定时执行
    @Scheduled(cron = "${schedule.task.time}")
    public void execute() {
        logger.info("定时任务开始执行");

        // 查询数据库容量信息
        List<DatabaseCapacityInfo> dbCapacityList = databaseMemoryMonitor.getDatabaseCapacityInfo();

        // 查询Redis容量信息
        Map<String, Long> redisCapacityMap = redisMemoryMonitor.getRedisCapacityInfo();

        // 发送邮件告警
        if (alarmSwitch) {
            emailService.sendEmail(dbCapacityList, redisCapacityMap);
        }

        logger.info("定时任务执行完毕");
    }
}

其中,@Scheduled(cron = "${schedule.task.time}")注解表示按照cron表达式执行定时任务,${schedule.task.time}是从配置文件中读取的动态参数,可根据需要修改执行时间。

同时,使用@Value注解将动态配置参数注入到类中,如@Value("${schedule.task.alarmSwitch}")注入告警开关参数,从而实现动态修改告警开关的功能。

另外,需要实现DatabaseMemoryMonitorRedisMemoryMonitor类,分别用于查询数据库容量信息和Redis容量信息,并返回结果给ScheduledTask类使用。同时,需要实现EmailService类,用于发送邮件告警。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值