💐个人主页:初晴~
📚相关专栏:redis
目录
一、什么是缓存
缓存(Cache)是一种高速存储技术,用于存储数据,以便快速访问。它主要用于减少数据访问的延迟和提高数据访问的速度。
简单来说,缓存是用户和数据库进行数据交互的一个缓冲区。一般会使用redis来作为缓存。像mysql这样的数据库,数据都是存储在硬盘中的,而redis的数据是存储在内存中的,相比之下读写速度会快非常多。
将一些访问频次比较高的数据存储在redis中作为缓存,每次用户读取数据时就可以直接在redis中查询,一方面大幅提高了读写的效率,另一方面也减轻了数据库的访问压力。在一些需求量非常密集的高并发的场景下,就能大大减轻数据层的压力
使用缓存后客户端访问数据的业务流程就会变成下面这样:
客户端会先在redis进行查询,如果查到目标对象就直接进行返回。如果没查到,才会对数据库进行查询,查询到数据后,会将数据写入到缓存中,以便客户端下次查询时能直接在redis中查到数据。然后再将数据返回给客户端
缓存的作用:
- 降低后端负载
- 提高数据读写效率,降低响应时间
凡事都有两面性,缓存的确非常好用,但相应的成本也高了不少:
- 数据一致性成本
- 代码维护成本
- 运维成本
因此实际开发中,没必要无脑冲redis缓存,一些用户量没那么大的小型企业或个人搭建缓存的性价比其实并不高。我们还是应当根据实际开发需求来选择合适的开发根据
二、redis缓存更新策略
什么是数据不一致性
当缓存区缓存了用户信息后,客户端就都会从redis中访问读取数据了。而如果这时候用户更新了数据库中的值,就会导致数据库存储的数据与redis存储数据不一致,在这之后进行读写操作就会发生各种意想不到的错误了
因此,当我们要对数据库数据进行更新时,也要尽可能让edis中的数据也能跟着变化,避免用户读到错误的信息
缓存更新策略
为了缓解数据不一致性问题,就需要及时对redis缓存的数据进行更新。常见的更新策略有以下三种:
为了尽可能提高数据一致性,保证用户数据读取安全。因此实际开发中我们一般都会采用主动更新的策略。这就需要我们程序员自己来编写业务逻辑了。这时候就会面临几个问题:
1、删除缓存还是更新缓存?
- 更新缓存:每次更新数据库都需要更新缓存。无效的写操作过多
- 删除缓存:更新数据库时删除对应缓存,这样在下次读取时就会自动更新缓存数据了
显然在每次读取时再更新数据效率会高的多。因此一般采用删除缓存的操作
2、如何保证数据库与缓存的操作同时成功或失败
单体系统:将数据库与缓存操作放在同一个事物下
分布式系统:利用TCC等分布式事务方案
3、先操作数据库还是先操作缓存?
让我们依次来看看:
(1)先删除缓存,后更新数据库
正常情况:
在第二个用户查完数据库后,就会将此时数据库的数据写入到缓存中,从而实现了缓存的更新。
但就跟线程安全问题一样,删除缓存与更新数据库是两个操作,也没有加锁,并不是原子的,这样在线程1执行完操作1时,就可能被其它线程插入进行操作了:
在线程1并未完成数据库更新操作的时候,就被线程2插入,此时缓存已被删除,线程2进行查询操作时,就会去读取此时还未被更改的数据库的值,并将该数写入到缓存中去。然后线程1才完成了对数据库的更新操作。
这时,缓存里存的是修改前的数据,数据库中存的是修改后的数据,就发生数据一致性问题了。
并且事实上,这种问题出现的概率还是非常高的。
因为线程1删除缓存是一个非常快的操作,然后开始更新数据库信息,而对数据库的修改操作是非常慢的,这期间很容易就会被线程2这样的线程趁虚而入,而相比之下,线程2查询缓存与数据库的速度就快的多了,最后的写入缓存由于是对内存操作,其速度也是非常快的,能达到微秒级别。因此线程2插入的这一系列操作看着复杂,实际执行的时间是非常短的,因此会有很大的可能性在线程1更新数据库的期间完成这一系列操作,最终导致数据不一致
(2)先修改数据库,在删除缓存
正常情况:
同样,在第二个用户读取数据时会顺带将数据写入缓存,也就实现了更新缓存的目的
不过,这种情况下依然有可能会发生数据不一致性问题:
类似于上一种方式,在线程1执行执行完数据库查询,还未写入缓存前,也有可能会插入某个线程2,执行完了更新数据库的操作,并删除了缓存。此时线程1再执行写入缓存的操作,就会将老的数据存入缓存,而数据库内的数据已经被线程2修改过了,从而导致数据库与缓存出现数据不一致问题。
可以看出,这种方法也没办法百分百保证数据一致性。不过相比之下,这种方式出现上述异常情况的概率会小得多。
因为缓存写入的速度回远高于数据库写入的速度,因此线程2很难在线程1写入缓存前那极短的时间内完成更新数据库与删除缓存这一系列操作。也就是说,发生上述这种异常情况的概率是非常小的,并且再与缓存的超时删除机制相结合,即使在低概率情况下真的发生数据不一致了,一段时间后也会自动更新缓存。
总结
显然,第二种方案带来的损失就比较小了。因此在上述这两种方案中,一般会采用第二种“先更新数据库,后删除缓存”的方案。