Redis 双写一致性

问题:redis 作为缓存,mysql 的数据如何与 redis 进行同步呢?(双写一致性)

双写一致性是指当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致。
Redis 双写一致性_第1张图片

  • 读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时时间。
  • 写操作:延迟双删

什么是延迟双删?

  1. 先删除缓存,还是先修改数据库?

无论怎么操作都会存在数据不一致的问题。

  1. 为什么要删除缓存呢?

先删除缓存再删除数据库肯定是存在脏数据的,所以要删除两次缓存。

  1. 为什么要延时双删?

因为数据库是主从分离的,主从同步需要时间,所以需要延时删除。但是因为延时的时间不好控制,所以延时的过程中也可能出现脏数据

到底怎么才能保证数据的强一致性呢?

通过加锁的方式,但是性能比较低。
如何优化呢?
首先,存入缓存的数据一般都是读多写少,所以我们可以用读写锁控制。
共享锁:读锁 readLock,加锁之后,其他线程可以共享读操作。
排他锁:独占锁 writeLock 也叫,加锁之后,阻塞其他线程读写操作。
所以我们在读操作的时候可以加共享锁,其他线程就可以读,但是不可以写。

public item getById(Integer id){
	RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ITEM_READ_WRITE_LOCK");
	// 读之前加读锁,读锁的作用就是等待该lockkey释放写锁以后再读
	RLock readLock = readWriteLock.readLock();
	try{
        // 开锁
        readLock.lock();
        System.out.println("readLock");
        Item item =(Item) redisTemplate.opsForValue().get("item:"+id);
        if(item != null){
            return item;
        }
        // 查询业务数据
        item = new Item(id,"华为手机","华为手机",5299.00);
        // 写入缓存
        redisTemplate.opsForValue().set("item:"+id,item);
        // 返回数据
        return item;
    }finally{
        readLock.unlock();
    }
}

在写操作的时候,加排他锁,其他线程都不能读写操作。

public void updateById(Integer id){
	RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ITEM_READ_WRITE_LOCK");
	// 写之前加写锁,写锁加锁成功,读锁只能等待
	RLock writeLock = readWriteLock.writeLock();
	try{
        // 开锁
        writeLock.lock();
        System.out.println("writeLock");
        // 更新业务数据
        Item item = new Item(id,"华为手机","华为手机",5322.00);
        try{
            Thread.sleep(10000);
        }catch(InterruptedEXception e){
            e.printStackTrace();
        }
        // 删除缓存
        redisTemplate.delete("item:"+id);
    }finally{
        writeLock.unlock();
    }
}

使用读写锁肯定可以保证数据的强一致性,但是性能肯定低。所以需要保证数据强一致性的业务场景才会使用。

允许短暂的不一致性

  1. 异步通知保证数据的最终一致性

Redis 双写一致性_第2张图片

  1. 基于 Canal 的异步通知

Redis 双写一致性_第3张图片

你可能感兴趣的:(redis,数据库,缓存)