快速,持续,稳定,傻瓜式
支持Mysql,Sqlserver数据同步

mysql和redis的数据一致性问题

在线QQ客服:1922638

专业的SQL Server、MySQL数据库同步软件

在当前的高并发环境中,使用mysql存储数据是不切实际的。需要Redis作为缓存。用户在访问数据时应首先检查是否有缓存。如果存在,请直接读取缓存。如果不存在,请读取数据库并将其值写入高速缓存。

插入图片<">

读取缓存步骤通常是没有问题的,但是在更新数据时,初夏会出现以下问题:

假设数据库中有100个ipad,则需要执行加急服务。最初,数据库中为100,redis中为100:

  • 问题一

    如果先删除Redis缓存,然后又没有来写,则另一个线程访问数据库并发现该缓存为空,然后直接进入数据库进行读取,然后再写入该缓存,则该缓存为脏数据:

用户A杀死一次并发现redis中有记录。高速缓存中的数字减少了1到99,但是尚未将其写入数据库。此时,缓存被删除。此时,另一个用户B也被刺穿。他发现缓存中没有数据,并直接从数据库中读取数据。此时,数据库不是99,而是100。用户B将数据库中的商品数减少了1 =99。但是在正常情况下,此时数据库中的商品数应为98;否则,数据库B中的商品数量应为99。

  • 问题2

    如果首先更新该库,则在删除缓存之前,写入库已关闭;如果未删除该缓存,则数据不一致;

当数据库写入高速缓存时,用户A开始峰值,然后由于停机,高速缓存中的数据为99,而数据库中的数据为100;


读取解决方案的数据(读取缓存):

读取时,首先读取缓存,如果没有缓存,则读取数据库,然后将检索到的数据放回缓存;

为解决方案写数据(写数据库)

首先删除缓存并更新数据库;

这样做有两个问题:

问题1)数据库更新成功,并且缓存删除失败。此时,数据库是新数据,而缓存是旧数据。存在数据不一致的问题

解决方案:首先删除缓存。在更新数据库时,如果成功删除了缓存,如果数据库修改失败,则数据库仍然是旧值,并且缓存为空。这样,尽管数据是错误的,但是不存在数据不一致的问题。最后,读取数据库中的旧数据以更新缓存;如果缓存删除失败,则有两种情况:(1)根本没有这样的产品(缓存删除失败m次,然后停止); (2)缓存本身为空;此时,线程需要等待20毫秒,然后再次继续删除缓存,直到删除成功为止;

问题2)数据库和缓存操作是同时执行的。 A线程尝试修改数据库中的值。在修改完成之前,B线程尝试获取数据库中的商品数量。由于此时缓存为空,因此将获取数据库中的数据,并将旧值写入缓存。答更新后将更新数据库。这时,也会出现数据不一致的问题。

解决方案:数据库和缓存操作的序列化;

在JVM内存中维护n个队列,并更新数据库操作,根据数据的唯一标识符对数据进行哈希处理以获得哈希值,然后将获得的哈希值取模n(hash%n)消息队列。如果在读取数据库时发现高速缓存不存在,则还会根据数据的唯一标识符将操作放入同一消息队列中。保持n个工作线程在消息队列顶部以消耗消息队列。每个工作线程获得相应的操作后,它将开始执行。在这种情况下,对于数据更改操作,首先删除高速缓存,然后更新数据库。如果此时有另一个查询(当缓存为空时),它将继续放置在相同的JVM队列中,并等待缓存被写回。连载;

图片>

这里可以做一个优化过程:消除队列中的重复项;

当查询操作已经存在于队列中时(仅用于上一个修改操作到下一个修改操作),则第二个查询不需要进入队列,您可以直接在(true)旋转的同时设置一个确定到期时间等待队列修改操作完成,并在请求缓存中的数据后直接返回;

如上所述,将redis用作缓存还会有以下问题(坏情况):

A.缓存渗透率

高速缓存渗透是指大量用户访问高速缓存中不存在的密钥。缓存不起作用。该请求将直接渗透到数据库,并且在通信繁忙时数据库将直接关闭;

解决方案:

1.设置拦截器,任何不符合要求的请求都会被拦截;

2.采用布隆过滤器,使用足够大的位图来存储可以访问的密钥,并且将不存在的密钥直接过滤掉;

3.查询键不在数据库中,您可以将空值写入缓存,并设置更短的到期时间;

B.缓存崩溃

高速缓存中的键在发生故障时会被大量请求访问,这些请求将分解到数据库,从而导致数据库压力突然增加。

解决方案:

1.将热点数据设置为永不过期;

2.添加互斥锁;

互斥锁的代码如下:

 

C.缓存雪崩

高速缓存中的多个键同时无效,从而导致数据库压力突然增加;

解决方案:

1.随机分配缓存过期时间,以避免同时失败;

2.如果redis是集群的,则热点数据将平均分布在不同的数据库中;

3.设置热点数据不作废;

相关推荐

咨询软件
 
QQ在线咨询
售前咨询热线
QQ1922638