本文正在参与「技术专题19期 漫谈数据库技术」活动

前语

当咱们运用Redis做缓存时,数据不一致问题是绕不过的问题。如果咱们没有很好的处理数据一致性问题,就有可能影响用户体验,最严峻的会形成事务丢失。数据一致性的场景和解决方法都有哪些呢?让咱们一探究竟。

缓存和数据库的数据不一致产生原因

数据一致性总结便是2种状况:

  • 缓存中有数据,这时缓存的数据和数据库的相同;
  • 缓存中没有数据,这时数据库的值是最新值。

因此,不符合这2种状况的便是数据不一致了。而缓存又包括读写缓存和只读缓存。 产生数据不一致的状况有各自的区别。

读写缓存

对数据增修正操作时,需要在缓存中进行。一起呢还得依据写回战略,看是否要同步写回到数据库。

  • 同步直写战略:写缓存时,并同步写数据库。缓存和数据库的数据一致。
  • 异步写回战略:写缓存时不同步写数据库,而是等数据筛选触发时,再将数据写回数据库。此状况下,若未触发数据筛选就呈现故障,数据库就没有最新数据,形成数据不一致的问题。

总结一下,采用读写缓存时,要确保数据一致性问题,就要采用同步直写战略。若数据一致性要求不是很高,可采用异步写回战略。

只读缓存

当要新增数据,就直接写到数据库;当数据删去或修正时,修正数据库的值,并将缓存的数据铲除。

redis数据一致性问题还稀里糊涂?看这篇就够了

剖析一下数据一致性的问题:

  • 新增数据:数据直接写到数据库,不对缓存操作。此刻不存在一致性的问题。
  • 删去和修正数据:这种状况下,既要更新数据库,也要删去缓存。若两个操作确保不了原子性,就会呈现数据不一致问题。

只读缓存修正数据的不一致问题

  • 先删去缓存,再更新数据库:若缓存删去成功,数据库更新失败。后面拜访就会缓存缺失,然后拜访数据库就会查到旧值。(但数据库更新失败,这种状况此操作就失败了,不能叫旧值)
  • 先更新数据库,再删去缓存:若更新数据库成功,删去缓存失败。后续拜访的便是缓存中的旧值。

redis数据一致性问题还稀里糊涂?看这篇就够了

看上图很好了解这个数据不一致的产生进程:

  1. a旧值=1,客户端要更新a的值为2;
  2. 先更新数据库成功,此刻数据库a = 2;
  3. 再删去缓存,但失败了。缓存还在。此刻缓存中a = 1, 数据库中a = 2;
  4. 再去查询a的值。因缓存射中,回来a = 1,和数据库不一致。

数据不一致的解决方案

处理方法一:先删去缓存,再更新数据库。(不引荐)

产生数据不一致的场景:

  1. 线程1删去缓存中的a数据后,还没来得及更新数据库。
  2. 此刻线程2读取数据a,会发现缓存缺失,然后会去读数据库。

线程2去数据库读取这个动作会带来2个问题:

  • 线程2读取的a是旧值(因为线程1已经改了a的值,只是还没更新到数据库)
  • 线程2在缓存缺失时读了数据库的旧值,这也就算了,它还会将这个旧值回写到缓存中。后续读取a可能都会读到旧值。

这种处理方法很简单形成数据不一致的问题,并且可能会影响后续多个查询操作。许多教程有提供推迟双删的解决方案(线程1更新完数据库后,先sleep一段时刻,再进行一次缓存删去操作),这种sleep的方法无法准确预估其他多个线程开端和完毕的时刻。还是可能会产生数据不一致问题。个人建议别运用这种处理方法。

处理方法二:先更新数据库,再删去缓存。(引荐)

产生数据不一致的场景:

  • 若线程1删去了数据库的值a,但还没来得及删去缓存。
  • 此刻线程2读取a数据,就会射中缓存中a的值,这便是读到了旧值。

但此状况若并发读a的线程不多,影响就不大。因为线程1马上就会将缓存中的a删去。后续读取a时就会呈现缓存缺失,然后去数据库读a的最新值。对事务的影响较小。

总结

在Redis的缓存和数据库的数据不一致问题上,可分为读写缓存只读缓存来剖析。

读写缓存有同步写回战略异步写回战略。采用同步写回能确保数据一致性,若数据一致性要求不是很高,可采用异步写回战略。

只读缓存有2种处理方法:

  • 先删去缓存,再更新数据库(不引荐):并发恳求多的时分,简单产生缓存和数据库值不一致的状况。
  • 先更新数据库,再删去缓存(引荐):并发恳求多的时分,会存在短暂的数据不一致问题。