Redis集群下过期key监听的实现代码

 更新时间:2019年09月09日 13:09:54   作者:超人小冰  
这篇文章主要介绍了Redis集群下过期key监听的实现代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

1. 前言

在使用redis集群时,发现过期key始终监听不到。网上也没有现成的解决方案。于是想,既然不能监听集群,那我可以建立多个redis连接,分别对每个redis的key过期进行监听。以上做法可能不尽人意,目前也没找到好的解决方案,如果有好的想法,请留言告知哦!不多说,直接贴我自己的代码!

2. 代码实现

关于Redis集群配置代码此处不贴,直接贴配置监听类代码!

redis.host1: 10.113.56.68
redis.port1: 7030
redis.host2: 10.113.56.68
redis.port2: 7031
redis.host3: 10.113.56.68
redis.port3: 7032
redis.host4: 10.113.56.68
redis.port4: 7033
redis.host5: 10.113.56.68
redis.port5: 7034
redis.host6: 10.113.56.68
redis.port6: 7035
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Arrays;

/**
 * @Author xiabing5
 * @Create 2019/8/6 14:46
 * @Desc  监听redis中Key过期事件
 **/
@Configuration
public class RedisListenerConfig {

  @Value("${redis.host1}")
  private String host1;

  @Value("${redis.host2}")
  private String host2;

  @Value("${redis.host3}")
  private String host3;

  @Value("${redis.host4}")
  private String host4;

  @Value("${redis.host5}")
  private String host5;

  @Value("${redis.host6}")
  private String host6;

  @Value("${redis.port1}")
  private int port1;

  @Value("${redis.port2}")
  private int port2;

  @Value("${redis.port3}")
  private int port3;

  @Value("${redis.port4}")
  private int port4;

  @Value("${redis.port5}")
  private int port5;

  @Value("${redis.port6}")
  private int port6;

  @Bean
  JedisPoolConfig jedisPoolConfig(){
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxIdle(100);
    jedisPoolConfig.setMaxWaitMillis(1000);
    return jedisPoolConfig;
  }

  // redis-cluster不支持key过期监听,建立多个连接,对每个redis节点进行监听
  @Bean
  RedisMessageListenerContainer redisContainer1() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host1);
    jedisConnectionFactory.setPort(port1);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisMessageListenerContainer redisContainer2() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host2);
    jedisConnectionFactory.setPort(port2);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisMessageListenerContainer redisContainer3() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host3);
    jedisConnectionFactory.setPort(port3);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisMessageListenerContainer redisContainer4() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host4);
    jedisConnectionFactory.setPort(port4);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisMessageListenerContainer redisContainer5() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host5);
    jedisConnectionFactory.setPort(port5);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisMessageListenerContainer redisContainer6() {
    final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName(host6);
    jedisConnectionFactory.setPort(port6);
    jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
    jedisConnectionFactory.afterPropertiesSet();
    container.setConnectionFactory(jedisConnectionFactory);
    return container;
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener1() {
    return new RedisKeyExpirationListener(redisContainer1());
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener2() {
    return new RedisKeyExpirationListener(redisContainer2());
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener3() {
    return new RedisKeyExpirationListener(redisContainer3());
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener4() {
    return new RedisKeyExpirationListener(redisContainer4());
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener5() {
    return new RedisKeyExpirationListener(redisContainer5());
  }

  @Bean
  RedisKeyExpirationListener redisKeyExpirationListener6() {
    return new RedisKeyExpirationListener(redisContainer6());
  }

}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import java.util.Date;

/**
 * @Author xiabing5
 * @Create 2019/9/4 9:47
 * @Desc  redis过期监听
 **/
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
  @Autowired
  RedisUtil redisUtil;
  @Autowired
  LoginUserStatisticsMapper loginUserStatisticsMapper;
  public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
    super(listenerContainer);
  }
  @Override
  public void onMessage(Message message, byte[] pattern) {
    // 用户做自己的业务处理即可,message.toString()可以获取失效的key
    String mesg = message.toString();   
  }
}

3. Redis防止过期key重复监听

对于项目集群情况下,部署多个服务后,容易出现redis过期被多个服务同时监听到,从而执行相同的业务逻辑,这不是我们期望的。单机部署下方法的同步可以采用synchronize关键字。但集群下,就得采用分布式锁。在需要加锁的地方,只要加锁和解锁即可。此处正好写到Redis,那就贴一个自己用的redis分布式锁。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Collections;
import java.util.UUID;
/**
 * @Author xiabing5
 * @Create 2019/9/6 15:54
 * @Desc  redis分布式锁
 **/
@Component
public class RedisLock {
  @Autowired
  Jedis jedis;
  private static final String SET_IF_NOT_EXIST = "NX"; // NX表示如果不存在key就设置value
  private static final String SET_WITH_EXPIRE_TIME = "PX"; // PX表示毫秒
  // 加锁
  public String tryLock(String key,Long acquireTimeout) {
    // 生成随机value
    String identifierValue = UUID.randomUUID().toString();
    // 设置超时时间
    Long endTime = System.currentTimeMillis() + acquireTimeout;
    // 循环获取锁
    while (System.currentTimeMillis() < endTime) {
      String result = jedis.set(key,identifierValue, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, acquireTimeout);
      if("OK".equals(result)) {
        return identifierValue;
      }
    }
    return null;
  }
  // 解锁
//  public void delLock(String key,String identifierValue) {
//    // 判断是否是同一把锁
//    try{
//      if(jedis.get(key).equals(identifierValue)){
//        // 此处操作非原子性,容易造成释放非自己的锁
//        jedis.del(key);
//      }
//    }catch(Exception e) {
//      e.printStackTrace();
//    }
//  }
  // 使用Lua代码解锁
  public void delLock(String key,String identifierValue) {
    try{
      String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
      Long result = (Long) jedis.eval(script, Collections.singletonList(key), Collections.singletonList(identifierValue));
      if (1 == result) {
        System.out.println(result+"释放锁成功");
      } if (0 == result) {
        System.out.println(result+"释放锁失败");
      }
    }catch (Exception e) {
      e.printStackTrace();
    }
  }
}

4. 总结

自己实现的一个小demo,废话比较少。小白自己写的配置类,理解有问题请留言!自己实现的方案感觉不妥,只是基本完成需求,还得继续研究。

以上所述是小编给大家介绍的Redis集群下过期key监听的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关文章

  • redis lettuce连接池经常出现连接拒绝(Connection refused)问题解决

    redis lettuce连接池经常出现连接拒绝(Connection refused)问题解决

    本文主要介绍了在Windows 10/11系统中使用Spring Boot和Lettuce连接池访问Redis时,遇到的连接拒绝问题,下面就来介绍一下解决方法,感兴趣的可以了解一下
    2025-03-03
  • 关于Redis库存超卖问题的分析

    关于Redis库存超卖问题的分析

    在高并发场景下进行优惠券秒杀测试时,发现由于并发操作导致了超卖问题,即理论上只能卖出100个优惠券,实际卖出了102个,分析原因,是因为在高并发环境下,多个线程同时操作库存,导致数据不一致,提出了两种解决方案:悲观锁和乐观锁
    2024-11-11
  • Redis底层数据结构之dict、ziplist、quicklist详解

    Redis底层数据结构之dict、ziplist、quicklist详解

    本文给大家详细介绍了Redis的底层数据结构:dict、ziplist、quicklist的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-09-09
  • 浅谈分布式锁的几种使用方式(redis、zookeeper、数据库)

    浅谈分布式锁的几种使用方式(redis、zookeeper、数据库)

    这篇文章主要介绍了浅谈分布式锁的几种使用方式(redis、zookeeper、数据库),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Redis不仅仅是缓存,还是……

    Redis不仅仅是缓存,还是……

    Redis是一个开源的(BSD协议),内存中的数据结构存储,它可以用作数据库,缓存,消息代理。这篇文章主要介绍了Redis不仅仅是缓存,还是……,需要的朋友可以参考下
    2020-12-12
  • Redis设置Hash数据类型的过期时间

    Redis设置Hash数据类型的过期时间

    在Redis中,我们可以使用Hash数据结构来存储一组键值对,而有时候,我们可能需要设置这些键值对的过期时间,本文主要介绍了Redis设置Hash数据类型的过期时间,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • redis的三种启动实现方式(后台运行)

    redis的三种启动实现方式(后台运行)

    文章介绍了Redis的三种启动方式:直接运行、通过配置文件启动及使用启动脚本设置开机自启,启动脚本需复制到/etc/init.d并重命名为redisd,同时添加运行级别注释以解决chkconfig报错问题,确保服务可开机自动启动
    2025-07-07
  • Redis集群的关闭与重启操作

    Redis集群的关闭与重启操作

    这篇文章主要介绍了Redis集群的关闭与重启操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • springboot中操作redis实例分享

    springboot中操作redis实例分享

    本文介绍了如何在Spring Boot应用中整合Redis缓存技术,包括配置Redis连接、定义Redis模板、实现Redis的基本操作以及使用Spring Cache注解。这些内容可帮助开发者快速掌握Spring Boot与Redis的集成,并提高应用性能。
    2023-06-06
  • odoo中使用redis实现缓存的步骤

    odoo中使用redis实现缓存的步骤

    这篇文章主要介绍了odoo中使用redis实现缓存的步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04

最新评论