redission读写锁解决db和缓存双写不一致

Posted 好大的月亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redission读写锁解决db和缓存双写不一致相关的知识,希望对你有一定的参考价值。

db和缓存双写不一致

多线程访问环境下,在更新完db后再去更新缓存,不加锁显而易见的就会出现缓存被覆盖的问题。

线程1修改完db去更新缓存的时候慢了一拍。
此时线程2线程1之后修改完db更新成功了缓存。
此时线程1更新缓存的操作恢复了,然后去更新了缓存。那么此时的缓存其实是个脏数据。

有什么办法呢?

方案一

直接加redission的普通Rlock分布式锁,比如对一个sku的缓存更新都排着队串行操作。这样也行,但是性能损失大。

方案二

Redisson其实还有读写锁.
操作过db的都知道,写锁是互斥的,读锁是可以大家一起加的。生产中实际80%大多都是读操作,剩下20%才是写。

下面来上demo

redission依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.8.2</version>
</dependency>

配置类

package com.fchan.espractice.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRedissionConfig {

    @Bean
    public RedissonClient redissionClient() {
        Config config = new Config();

        //单机模式
        config.useSingleServer()
                .setAddress("redis://192.168.56.101:36379")
                //.setPassword("111")
                .setDatabase(1);

        //集群模式
        /*config.useClusterServers()
                .addNodeAddress("redis://192.168.56.101:36379")
                .addNodeAddress("redis://192.168.56.102:36379")
                .addNodeAddress("redis://192.168.56.103:36379")
                .setPassword("1111111")
                .setScanInterval(5000);*/

        //哨兵模式
        /*config.useSentinelServers().addSentinelAddress("redis://ip1:port1",
                "redis://ip2:port2",
                "redis://ip3:port3")
                .setMasterName("mymaster")
                .setPassword("password")
                .setDatabase(0);*/

        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }



}

测试读写锁
测试发现同一个key读锁可以重复添加,但是在读锁还没释放的时候,加写锁是会被阻塞的。当这个key的读锁都释放完了写锁才能加上。一旦加上写锁,那么其他的写锁和读锁就会被阻塞了。

比如扣减库存场景,并发读下来,然后并发扣减,可能会有扣减失败的,之前读的时候还有,扣减的时候就没有库存了。

@GetMapping("addReadLock")
public void addReadLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.readLock();
    lock.lock();
}

@GetMapping("releaseReadLock")
public void releaseReadLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.readLock();
    lock.unlock();
}

@GetMapping("addWriteLock")
public void addWriteLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.writeLock();
    lock.lock();
}

@GetMapping("releaseWriteLock")
public void releaseWriteLock(@RequestParam("key") String key){
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(key);
    RLock lock = readWriteLock.writeLock();
    lock.unlock();
}

以上是关于redission读写锁解决db和缓存双写不一致的主要内容,如果未能解决你的问题,请参考以下文章

缓存数据库双写不一致问题处理

缓存数据库双写不一致问题处理

Redis什么是缓存与数据库双写不一致?怎么解决?

面试官:Zookeeper怎么解决读写双写并发不一致问题,以及共享锁的实现原理?

面试官:Zookeeper怎么解决读写双写并发不一致问题,以及共享锁的实现原理?

redis缓存+数据库双写不一致问题分析与解决方案