目录
一 双写一致性
当修改了数据库的同时也要对Redis缓存进行同步更新,保持数据库和缓存要一致。
分两种情况:先删除缓存,再操作数据库。先操作数据库,再删除缓存。
![]() | ![]() |
![]() |
可以看到,这种操作在线程1删除缓存之后,线程2这时刚好插入进来(因为线程是独立进行的),线程2查询缓存未命中之后,然后查库进行了更新操作,又把缓存恢复为10,但是线程1执行完之后数据库变为了20,此时就会出现脏数据的现象。
先修改数据库,再删除缓存
![]() | ![]() |
![]() |
如图:当线程1查询数据库之后得到了数据10,但是还没来得及写回到缓存的时候,线程2进行了数据库的更新,并且删除了缓存,此时线程1将10写入了缓存,又造成了缓存数据库不一致的情况,又出现了脏数据。
为了保证双写一致性,提出了延时双删的逻辑,主要是为了让主从模式的数据库能够进行数据的同步。(但是也有脏数据的风险)
那么如何避免脏数据的风险呢
办法1:分布式锁
分布式锁可以解决该问题,但是看到上图也可以发现,对资源消耗太大了。
办法2:共享锁和排他锁
读锁在读时,其他线程也可以读,但是写数据时不允许其他线程进行操作。
异步保证最终一致性
1.使用MQ中间件,更新数据之后,通知缓存删除
2.利用canal中间件,不需要修改业务代码,伪装成MySQL的从节点,canal通过读取binlog日志数据更新缓存。
二 持久化
RDB持久化和AOF
RDB(Redis Database Backup file)数据备份文件,也是Redis数据快照。简单来说就是把内存中所有数据记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照,恢复数据。
Redis内部有出发RDB的机制,可以在redis.conf中找到
代表的是多少秒内被修改多少次触发RDB机制。
RDB执行原理:
当主进程进行操作时,不会直接在物理内存中进行操作,而是会给主进程分配虚拟内存,而操作系统会维护一个物理内存和虚拟内存之间的一个表——页表,主进程此时就可以通过操作虚拟内存就可以对物理内存进行读写操作了。当我们执行bgsave命令时,会有一个子进程进行这个操作,此时相当于是克隆了一个子进程,这个子进程就只对页表数据进行拷贝,子进程此时就有了和主进程一样的映射关系,此时子进程就可以写新的RDB文件到磁盘中,此时RDB持久化就完成了。但是此时主进程进行写操作的时候,会拷贝一份新数据,在数据副本上进行读写操作,从而避免子进程在写RDB文件时,主进程收到更新数据的命令,从而产生脏数据。
AOF(Append Only File)追加文件
Redis处理的每个命令都会写在AOF之中,AOF会存储之前的命令,因此AOF会比RDB文件要大得多,因此恢复数据的速度也比较慢。
三 数据删除策略
Redis中提供了两种删除策略 惰性删除和定期删除
惰性删除:当key过期了,等下一次访问来了再删除。
定期删除:每隔一段时间,就对key做一些检查,删除里面过期的key(从一定量的数据库中取出一定数量的随机key检查,并删除其中的过期key)
slow模式:默认10hz,每次不超过25ms
fast模式:执行频率不固定,两次间隔不低于2ms,每次耗时不超过1ms