分布式缓存

本地缓存的问题
缓存数据不一致:每个微服务都要有缓存服务、数据更新时只更新自己的缓存,造成缓存数据不一致

解决方案分布式缓存,微服务共用 缓存中间件

分布式锁
分布式项目时,但本地锁只能锁住当前服务需要分布式锁

redis分布式锁的原理:setnx,同一时刻只能设置成功一个

前提,锁的key是一定的,value可以变

没获取到锁阻塞或者sleep一会

public Map<String, List<Catelog2Vo>> getCatalogJsonDbWithRedisLock() {
    if (lock) { // 获取到锁
    } else { //没获取到锁阻塞或者sleep一会
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 睡眠0.1s后,重新调用 
        //自旋
        return getCatalogJsonDbWithRedisLock();
    }
}

设置好了锁,万一服务出现宕机,没有执行删除锁逻辑,这就造成了死锁

解决:设置过期时间

Boolean lock = ops.setIfAbsent("lock", uuid, 500, TimeUnit.SECONDS);

业务还没执行完锁就过期了,别人拿到锁,自己执行完去删了别人的锁

解决:锁续期(redisson有看门狗),。删锁的时候明确是自己的锁。如uuid

String uuid = UUID.randomUUID().toString();
Boolean lock = ops.setIfAbsent("lock", uuid, 500, TimeUnit.SECONDS);

判断uuid对了,但是将要删除的时候锁过期了,别人设置了新值,那删除了别人的锁

解决:删除锁必须保证原子性(保证判断和删锁是原子的)。使用redis+Lua脚本完成,脚本是原子的

// Lua脚本
String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
        "    return redis.call(\"del\",KEYS[1])\n" +
        "else\n" +
        "    return 0\n" +
        "end";
/**
 * stringRedisTemplate.execute(
 *     new DefaultRedisScript<Long返回值类型>(script脚本, Long.class返回值类型),
 *     Arrays.asList("lock"), // 键key的集合
 *     lockValue); // 锁的值
 */
stringRedisTemplate.execute(
        new DefaultRedisScript<Long>(script, Long.class), // 脚本和返回类型
        Arrays.asList("lock"), // 参数
        lockValue); // 参数值,锁的值
public Map<String, List<Catelog2Vo>> getCatalogJsonDbWithRedisLock() {
    String uuid = UUID.randomUUID().toString();
    ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
    // 设置好了锁,万一服务出现宕机,没有执行删除锁逻辑,这就造成了死锁
    // 解决:设置过期时间
    Boolean lock = ops.setIfAbsent("lock", uuid, 500, TimeUnit.SECONDS);
    if (lock) {
        Map<String, List<Catelog2Vo>> categoriesDb = getCategoryMap();
        String lockValue = ops.get("lock");
        // 业务还没执行完锁就过期了,别人拿到锁,自己执行完去删了别人的锁
        // 解决:锁续期(redisson有看门狗)。删锁的时候明确是自己的锁。如uuid
        // 判断uuid对了,但是将要删除的时候锁过期了,别人设置了新值,那删除了别人的锁
        // 解决:删除锁必须保证原子性(保证判断和删锁是原子的)。使用redis+Lua脚本完成,脚本是原子的
        // get和delete原子操作
        String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        /**
         * stringRedisTemplate.execute(
         *     new DefaultRedisScript<Long返回值类型>(script脚本, Long.class返回值类型),
         *     Arrays.asList("lock"), // 键key的集合
         *     lockValue); // 锁的值
         */
        stringRedisTemplate.execute(
                new DefaultRedisScript<Long>(script, Long.class), // 脚本和返回类型
                Arrays.asList("lock"), // 参数
                lockValue); // 参数值,锁的值
        return categoriesDb;
    } else {
        //没获取到锁阻塞或者sleep一会
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 睡眠0.1s后,重新调用 //自旋
        return getCatalogJsonDbWithRedisLock();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值