自学内容网 自学内容网

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

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

Redis内存淘汰策略

淘汰策略类型

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

  1. noeviction:当内存使用达到阈值时,所有导致内存增加的命令将返回错误。
  2. allkeys-lru:从所有键中优先移除最近最少使用的键。(推荐)
  3. volatile-lru:仅从设置了过期时间的键中优先移除最近最少使用的键。
  4. allkeys-random:从所有键中随机移除键。
  5. volatile-random:仅从设置了过期时间的键中随机移除键。
  6. volatile-ttl:仅从设置了过期时间的键中移除具有更早过期时间的键。

配置方法

要配置Redis的内存淘汰策略,首先需要在redis.conf文件中设置最大内存限制,例如:

maxmemory 300mb

然后,指定内存淘汰策略:

maxmemory-policy allkeys-lru

Redis中的自动过期机制与订单过期自动取消

自动过期机制

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

实现方案
  1. 使用Redis Key自动过期触发事件通知:配置Redis以通知过期事件。
  2. 使用定时任务检查:设定一个定时任务定期检查过期订单。
  3. 按分钟轮询检查:每隔一段时间轮询检查是否有订单过期。

示例:Spring Boot整合Redis键过期监听

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

表结构
CREATE TABLE `order_number` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_name` varchar(255) DEFAULT NULL,
  `order_status` int(11) DEFAULT NULL,
  `order_token` varchar(255) DEFAULT NULL,
  `order_id` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
Redis配置

redis.conf中启用键过期通知:

notify-keyspace-events "Ex"
Spring Boot配置
@Configuration
public class RedisListenerConfig {
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    private static final Integer ORDER_STAYPAY = 0;
    private static final Integer ORDER_INVALID = 2;
    @Autowired
    private OrderMapper orderMapper;
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String expiredKey = message.toString();
        OrderEntity order = orderMapper.getOrderNumber(expiredKey);
        if (order != null && order.getOrderStatus().equals(ORDER_STAYPAY)) {
            orderMapper.updateOrderStatus(expiredKey, ORDER_INVALID);
        }
    }
}
控制器
@RestController
public class OrderController {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RedisUtils redisUtils;

    @RequestMapping("/saveOrder")
    public String saveOrder() {
        String orderToken = UUID.randomUUID().toString();
        String orderId = System.currentTimeMillis() + "";
        redisUtils.setString(orderToken, orderId, 30L); // 30分钟
        OrderEntity orderEntity = new OrderEntity(null, "蚂蚁课堂永久会员", orderId, orderToken);
        int result = orderMapper.insertOrder(orderEntity);
        return result > 0 ? "success" : "fail";
    }
}

Redis事务操作

Redis事务通过MULTIEXECWATCHDISCARD命令来实现。事务确保一系列命令要么全部执行,要么都不执行,但Redis并不支持事务回滚。

事务与回滚的区别

  • 取消事务:不提交事务,事务中的所有操作都不会被执行。
  • 回滚:事务中的所有操作被撤销,恢复到事务开始前的状态。Redis不支持此功能。

Redis实现分布式锁

分布式锁原理

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

核心代码示例

public class RedisUtil {
    private static String IP = "192.168.212.148";
    private static int PORT = 6379;
    private static int MAX_ACTIVE = 100;
    private static int MAX_IDLE = 20;
    private static int MAX_WAIT = 3000;
    private static int TIMEOUT = 3000;
    private static boolean TEST_ON_BORROW = true;
    private static boolean TEST_ON_RETURN = true;
    private static JedisPool jedisPool = null;

    public final static int EXRP_HOUR = 60 * 60;
    public final static int EXRP_DAY = 60 * 60 * 24;
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30;

    private static void initialPool() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);
        jedisPool = new JedisPool(config, IP, PORT, TIMEOUT, "123456");
    }

    private static synchronized void poolInit() {
        if (jedisPool == null) {
            initialPool();
        }
    }

    public synchronized static Jedis getJedis() {
        if (jedisPool == null) {
            poolInit();
        }
        return jedisPool.getResource();
    }

    public static void returnResource(Jedis jedis) {
        if (jedis != null && jedisPool != null) {
            jedisPool.returnResource(jedis);
        }
    }

    public static Long sadd(String key, String... members) {
        Jedis jedis = null;
        Long res = null;
        try {
            jedis = getJedis();
            res = jedis.sadd(key, members);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            returnResource(jedis);
        }
        return res;
    }
}

应用场景

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

原文地址:https://blog.csdn.net/qq_67028830/article/details/143750707

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!