《Redis内存淘汰策略及分布式锁应用详解》

张春  论坛元老 | 2024-11-14 06:25:33 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1582|帖子 1582|积分 4746

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Redis内存淘汰策略及分布式锁应用详解

Redis内存淘汰策略

淘汰策略类型

Redis提供了多种内存淘汰策略,用于管理当内存使用到达上限时怎样处理数据。以下是六种常见的淘汰策略:

  • noeviction:当内存使用到达阈值时,全部导致内存增长的命令将返回错误。
  • allkeys-lru:从全部键中优先移除最近最少使用的键。(推荐)
  • volatile-lru:仅从设置了逾期时间的键中优先移除最近最少使用的键。
  • allkeys-random:从全部键中随机移除键。
  • volatile-random:仅从设置了逾期时间的键中随机移除键。
  • volatile-ttl:仅从设置了逾期时间的键中移除具有更早逾期时间的键。
设置方法

要设置Redis的内存淘汰策略,起首必要在redis.conf文件中设置最大内存限定,例如:
  1. maxmemory 300mb
复制代码
然后,指定内存淘汰策略:
  1. maxmemory-policy allkeys-lru
复制代码
Redis中的主动逾期机制与订单逾期主动取消

主动逾期机制

Redis允许为键设置一个生存时间(TTL),一旦键逾期,它会被主动删除。这一特性可以用来实现诸如订单逾期主动取消的功能。
实现方案


  • 使用Redis Key主动逾期触发事件通知:设置Redis以通知逾期事件。
  • 使用定时使命检查:设定一个定时使命定期检查逾期订单。
  • 按分钟轮询检查:每隔一段时间轮询检查是否有订单逾期。
示例:Spring Boot整合Redis键逾期监听

假设有一个订单表order_number,当订单30分钟内未付出时,应主动将订单状态更改为已取消。
表结构

  1. CREATE TABLE `order_number` (
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,
  3.   `order_name` varchar(255) DEFAULT NULL,
  4.   `order_status` int(11) DEFAULT NULL,
  5.   `order_token` varchar(255) DEFAULT NULL,
  6.   `order_id` varchar(255) DEFAULT NULL,
  7.   PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
复制代码
Redis设置

在redis.conf中启用键逾期通知:
  1. notify-keyspace-events "Ex"
复制代码
Spring Boot设置

  1. @Configuration
  2. public class RedisListenerConfig {
  3.     @Bean
  4.     RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
  5.         RedisMessageListenerContainer container = new RedisMessageListenerContainer();
  6.         container.setConnectionFactory(connectionFactory);
  7.         return container;
  8.     }
  9. }
  10. @Component
  11. public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
  12.     public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
  13.         super(listenerContainer);
  14.     }
  15.     private static final Integer ORDER_STAYPAY = 0;
  16.     private static final Integer ORDER_INVALID = 2;
  17.     @Autowired
  18.     private OrderMapper orderMapper;
  19.     @Override
  20.     public void onMessage(Message message, byte[] pattern) {
  21.         String expiredKey = message.toString();
  22.         OrderEntity order = orderMapper.getOrderNumber(expiredKey);
  23.         if (order != null && order.getOrderStatus().equals(ORDER_STAYPAY)) {
  24.             orderMapper.updateOrderStatus(expiredKey, ORDER_INVALID);
  25.         }
  26.     }
  27. }
复制代码
控制器

  1. @RestController
  2. public class OrderController {
  3.     @Autowired
  4.     private OrderMapper orderMapper;
  5.     @Autowired
  6.     private RedisUtils redisUtils;
  7.     @RequestMapping("/saveOrder")
  8.     public String saveOrder() {
  9.         String orderToken = UUID.randomUUID().toString();
  10.         String orderId = System.currentTimeMillis() + "";
  11.         redisUtils.setString(orderToken, orderId, 30L); // 30分钟
  12.         OrderEntity orderEntity = new OrderEntity(null, "蚂蚁课堂永久会员", orderId, orderToken);
  13.         int result = orderMapper.insertOrder(orderEntity);
  14.         return result > 0 ? "success" : "fail";
  15.     }
  16. }
复制代码
Redis事件操作

Redis事件通过MULTI、EXEC、WATCH和DISCARD命令来实现。事件确保一系列命令要么全部执行,要么都不执行,但Redis并不支持事件回滚。
事件与回滚的区别



  • 取消事件:不提交事件,事件中的全部操作都不会被执行。
  • 回滚:事件中的全部操作被撤销,恢复到事件开始前的状态。Redis不支持此功能。
Redis实现分布式锁

分布式锁原理

分布式锁是一种在分布式体系中实现互斥访问共享资源的机制。Redis通过SETNX命令实现分布式锁,该命令只有在键不存在时才会设置键。
核心代码示例

  1. public class RedisUtil {
  2.     private static String IP = "192.168.212.148";
  3.     private static int PORT = 6379;
  4.     private static int MAX_ACTIVE = 100;
  5.     private static int MAX_IDLE = 20;
  6.     private static int MAX_WAIT = 3000;
  7.     private static int TIMEOUT = 3000;
  8.     private static boolean TEST_ON_BORROW = true;
  9.     private static boolean TEST_ON_RETURN = true;
  10.     private static JedisPool jedisPool = null;
  11.     public final static int EXRP_HOUR = 60 * 60;
  12.     public final static int EXRP_DAY = 60 * 60 * 24;
  13.     public final static int EXRP_MONTH = 60 * 60 * 24 * 30;
  14.     private static void initialPool() {
  15.         JedisPoolConfig config = new JedisPoolConfig();
  16.         config.setMaxTotal(MAX_ACTIVE);
  17.         config.setMaxIdle(MAX_IDLE);
  18.         config.setMaxWaitMillis(MAX_WAIT);
  19.         config.setTestOnBorrow(TEST_ON_BORROW);
  20.         jedisPool = new JedisPool(config, IP, PORT, TIMEOUT, "123456");
  21.     }
  22.     private static synchronized void poolInit() {
  23.         if (jedisPool == null) {
  24.             initialPool();
  25.         }
  26.     }
  27.     public synchronized static Jedis getJedis() {
  28.         if (jedisPool == null) {
  29.             poolInit();
  30.         }
  31.         return jedisPool.getResource();
  32.     }
  33.     public static void returnResource(Jedis jedis) {
  34.         if (jedis != null && jedisPool != null) {
  35.             jedisPool.returnResource(jedis);
  36.         }
  37.     }
  38.     public static Long sadd(String key, String... members) {
  39.         Jedis jedis = null;
  40.         Long res = null;
  41.         try {
  42.             jedis = getJedis();
  43.             res = jedis.sadd(key, members);
  44.         } catch (Exception e) {
  45.             e.printStackTrace();
  46.         } finally {
  47.             returnResource(jedis);
  48.         }
  49.         return res;
  50.     }
  51. }
复制代码
应用场景



  • 分布式使命调度:确保同一使命不会被重复执行。
  • 分布式全局ID生成:生成唯一标识符。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表