MST
星途 面试题库

面试题:Redis缓存策略如何助力MySQL应对中等规模业务增长

假设一个中等规模电商应用,MySQL数据库存储商品信息,随着业务增长,查询压力增大。请阐述如何运用Redis的缓存策略(如设置合适的过期时间、缓存穿透处理等)来减轻MySQL压力,提高系统性能,并简要说明具体实现步骤。
43.6万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

运用Redis缓存策略减轻MySQL压力及提高性能的方法

  1. 设置合适的过期时间
    • 策略:根据商品的热度和更新频率设置不同的过期时间。对于热门且不常更新的商品,设置较长的过期时间,如一周;对于更新频繁或相对冷门的商品,设置较短的过期时间,如几小时甚至几分钟。这样既保证了缓存命中率,又能及时更新数据。
    • 原因:如果过期时间设置过长,可能导致数据长时间不一致;设置过短,则缓存命中率降低,频繁查询MySQL。
  2. 缓存穿透处理
    • 策略
      • 布隆过滤器:在Redis中使用布隆过滤器。当查询商品时,先通过布隆过滤器判断商品是否存在。如果布隆过滤器判断不存在,则直接返回,不再查询MySQL。布隆过滤器存在一定的误判率,但可以通过调整参数(如哈希函数个数、位数组大小)来降低误判率。
      • 空值缓存:当查询MySQL发现商品不存在时,将空值(如null)缓存到Redis中,并设置较短的过期时间,如几分钟。下次查询同样不存在的商品时,直接从Redis返回空值,避免再次查询MySQL。

具体实现步骤

  1. 设置过期时间实现
    • 代码示例(以Java为例,使用Jedis客户端)
import redis.clients.jedis.Jedis;

public class RedisCacheExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        // 假设商品ID为1,商品信息为JSON字符串
        String productId = "1";
        String productInfo = "{\"name\":\"手机\",\"price\":1999}";
        // 设置较长过期时间,如一周(以秒为单位)
        int expirationLong = 60 * 60 * 24 * 7;
        jedis.setex(productId.getBytes(), expirationLong, productInfo.getBytes());

        // 对于更新频繁的商品,假设商品ID为2
        String productId2 = "2";
        String productInfo2 = "{\"name\":\"耳机\",\"price\":99}";
        // 设置较短过期时间,如1小时
        int expirationShort = 60 * 60;
        jedis.setex(productId2.getBytes(), expirationShort, productInfo2.getBytes());
        jedis.close();
    }
}
  1. 缓存穿透处理实现
    • 布隆过滤器实现(以Java为例,使用Google Guava库)
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import redis.clients.jedis.Jedis;

public class BloomFilterExample {
    private static final int expectedInsertions = 100000;
    private static final double fpp = 0.01;
    private static BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(), expectedInsertions, fpp);

    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        // 初始化布隆过滤器,假设从MySQL加载所有商品ID到布隆过滤器
        // 实际应用中可以在系统启动时加载
        String[] productIds = {"1", "2", "3"};
        for (String id : productIds) {
            bloomFilter.put(id);
        }

        // 查询商品时先通过布隆过滤器判断
        String queryProductId = "4";
        if (!bloomFilter.mightContain(queryProductId)) {
            // 布隆过滤器判断不存在,直接返回
            System.out.println("商品不存在,无需查询MySQL");
        } else {
            // 可能存在,查询Redis或MySQL
            byte[] productInfo = jedis.get(queryProductId.getBytes());
            if (productInfo != null) {
                System.out.println("从Redis获取商品信息: " + new String(productInfo));
            } else {
                // 查询MySQL,假设这里有查询MySQL的逻辑
                // 并将结果缓存到Redis
            }
        }
        jedis.close();
    }
}
  • 空值缓存实现(以Java为例,使用Jedis客户端)
import redis.clients.jedis.Jedis;

public class NullCacheExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        String queryProductId = "5";
        byte[] productInfo = jedis.get(queryProductId.getBytes());
        if (productInfo != null) {
            if (productInfo.length == 0) {
                System.out.println("商品不存在,从空值缓存返回");
            } else {
                System.out.println("从Redis获取商品信息: " + new String(productInfo));
            }
        } else {
            // 查询MySQL
            // 假设查询结果为空
            // 将空值缓存到Redis,设置较短过期时间,如5分钟
            int expiration = 60 * 5;
            jedis.setex(queryProductId.getBytes(), expiration, new byte[0]);
            System.out.println("商品不存在,查询MySQL后缓存空值");
        }
        jedis.close();
    }
}

在实际电商应用中,还需要考虑缓存雪崩(大量缓存同时过期)等问题,可以通过设置随机过期时间等方式来解决。同时,要结合业务场景对缓存策略进行优化。