继上篇文章开始了Redis场景——缓存的引入之后,后面的文章开始逐渐深入缓存。这篇文章会针对缓存的几个不同策略进行分析。Redis缓存根据读写大致可以分为只读缓存和读写缓存,而读写缓存根据写回的时机不同又可分为同步直写策略和异步写回策略。
一.什么是只读缓存和读写缓存
-
只读缓存就是Redis缓存不接受在缓存里进行写操作,当接收到写操作的时候,如果这个操作对应的数据已经在缓存了,则会先在数据库进行相应的写操作,然后在Redis把对应的缓存数据给删掉(这里需要注意,后面会有比较)。这样的话所有最新的数据都在数据库中,而数据库是提供数据可靠性保障的,这些数据不会有丢失的风险。当我们需要缓存图片、短视频这些用户只读的数据时,就可以使用只读缓存这个类型了。
-
读写缓存就是Redis缓存接受在缓存里进行写操作,比如说在商品大促的场景中,商品的库存信息会一直被修改。如果每次修改都需到数据库中处理,就会拖慢整个应用,此时,我们通常会选择读写缓存的模式。Redis 的高性能访问特性,数据的增删改操作可以在缓存中快速完成,处理结果也会快速返回给业务应用,这就可以提升业务应用的响应速度。但是这样最新的数据就在缓存中了,会面临最新的数据丢失的问题,这样就会对业务带来风险,所以根据可靠性又有了同步直写策略和异步写回策略。
- 同步直写是指,写请求发给缓存的同时,也会发给后端数据库进行处理,等到缓存和数据库都写完数据,才给客户端返回。这样会增加缓存的响应延迟。因为缓存中处理写请求的速度是很快的,而数据库处理写请求的速度较慢。但最新的数据仍然保存在数据库中,这就提供了数据可靠性保证。
- 而异步写回中写请求都先在缓存中处理。等到这些增改的数据要被从缓存中淘汰出来时,缓存将它们写回后端数据库.
二.Redis只读缓存和使用直写策略的读写缓存有什么区别
这两种方式都会把数据同步写入到数据库中,区别在于:
-
使用只读缓存时,是先把修改写到后端数据库中,再把缓存中的数据删除(上面提到注意的点)。当下次访问这个数据时,会以后端数据库中的值为准,重新加载到缓存中。这样做的优点是,数据库和缓存可以保证完全一致,并且缓存中永远保留的是经常访问的热点数据。缺点是每次修改操作都会把缓存中的数据删除,之后访问时都会先触发一次缓存缺失,然后从后端数据库加载数据到缓存中,这个过程访问延迟会变大。
-
使用读写缓存时,是同时修改数据库和缓存中的值。这样做的优点是,被修改后的数据永远在缓存中存在,下次访问时,能够直接命中缓存,不用再从后端数据库中查询,这个过程拥有比较好的性能,比较适合先修改又立即访问的业务场景。但缺点是在高并发场景下,如果存在多个操作同时修改同一个值的情况,可能会导致缓存和数据库的不一致。
当使用只读缓存时,如果修改数据库失败了,那么缓存中的数据也不会被删除,此时数据库和缓存中的数据依旧保持一致。当然如果修改数据库成功,而删除缓存失败也会产生不一致,完全一致性是个比较麻烦的事情。而使用读写缓存时,如果是先修改缓存,后修改数据库,如果缓存修改成功,而数据库修改失败了,那么此时数据库和缓存数据就不一致了。如果先修改数据库,再修改缓存,也会产生上面所说的并发场景下的不一致。
总的来说,只读缓存牺牲了一定的性能,优先保证数据库和缓存的一致性,适合对于一致性要求比较要高的业务场景。而如果对于数据库和缓存一致性要求不高,或者不存在并发修改同一个值的情况,那么使用读写缓存就比较合适,它可以保证更好的访问性能。
三.Redis在用作缓存时,使用只读缓存或读写缓存的哪种模式?
首先,Redis缓存在应对脏数据时,需要在数据修改的同时,也把它写回数据库。为什么呢?
这里就要提到数据淘汰了,Redis是支持数据淘汰的,缓存的空间是有限的,有些“不重要”的数据我们需要淘汰掉来腾空间。一般来说,一旦被淘汰的数据选定后,如果这个数据是干净数据,那么我们就直接删除;如果这个数据是脏数据,我们需要把它写回数据库,如下图所示:
脏数据就是缓存中的最新数据和后端数据库中的数据不一致。
重点来了:而对于Redis,它决定了被淘汰的数据后,会直接把它们删除。即使淘汰的数据是脏数据,Redis 也不会把它们写回数据库。所以缓存在面对脏数据的时候,需要在数据修改的时候,就把它写回数据库。
明确了这个点之后,我们就能知道Redis在用作缓存的时候,用哪种模式了:
1、只读缓存模式:每次修改直接写入后端数据库,如果Redis缓存不命中,则什么都不用操作,如果Redis缓存命中,则删除缓存中的数据,待下次读取时从后端数据库中加载最新值到缓存中。
2、读写缓存模式+同步直写策略:由于Redis在淘汰数据时,直接在内部删除键值对,外部无法介入处理脏数据写回数据库,所以使用Redis作读写缓存时,只能采用同步直写策略,修改缓存的同时也要写入到后端数据库中,从而保证修改操作不被丢失。