Redis与数据库的一致性

Redis与数据库的数据一致性

在使用Redis作为应用缓存来提高数据的读性能时,经常会遇到Redis与数据库的数据一致性问题。简单来说,就是同一份数据同时存在于Redis和数据库,如何在数据更新的时候,保证两边数据的一致性。首先,如果期望Redis与数据库保持强一致性,则必须额外引入分布式事务组件,通过一致性协议(如2PC、3PC等)来保证缓存和数据库的一致性。这里讨论的一致性是最终一致性,即Redis中的数据将最终和数据库中的数据保持一致。

Redis缓存模式

Redis缓存模式并没有统一的范式,这里主要是借鉴本地缓存的设计模式,尝试总结出Redis的缓存模式。本地缓存在进行设计时,主要有以下几种常见的模式:cache aside,read through,write through,write around,write back。
在cache aside模式中,对于读请求,客户端应用会优先访问缓存,如果缓存命中,则直接返回数据;如果缓存未命中,则会进一步请求数据库,然后将数据写入缓存。在read through中,缓存负责保持与数据库的一致。当数据未命中时,缓存会主动从数据库中读取该未命中数据,并回写缓存,然后将这部分数据返回给客户端应用。在write through模式中,数据首先写入缓存,然后写入数据库。与read through一样,写入总是通过缓存到达数据库。在write around模式中,数据直接由客户端应用写入数据库,然后让Cache中对应数据无效。在write back模式中,客户端应用将数据写入缓存后,缓存会立即确认,并在延迟一段时间后将数据写回数据库。更多缓存设计模式相关细节可以参考笔者软件系统缓存设计一文。
以上五种缓存设计模式,cache aside模式与read through模式主要针对读请求的场景,且在第一次请求数据时,总是会导致缓存未命中,并额外带来将数据加载到缓存的操作。相比cache aside模式是客户端应用从数据库读取缓存未命中数据并将其写入缓存,read through模式是由缓存从数据库读取未命中数据并将其写入到缓存。对于Redis缓存来说,由于Redis缓存和数据库是两个独立的组件,所以Redis缓存不可能使用read through模式,而只能使用cache aside模式。
而write through模式、write around模式与write back模式主要针对写请求的场景,三种模式均需要将数据写入数据库,只是写入的主体或写入的时机不同。对于Redis缓存来说,同样由于Redis缓存和数据库是两个独立的组件,所以Redis缓存不可能使用write through模式或write back模式,而只能使用write around模式,即数据直接由客户端应用写入数据库。至此,Redis缓存的常用设计模式如下:

请添加图片描述

从上图可知,当客户端应用发起读请求时,客户端应用首先尝试从Redis中读取数据,如果缓存中命中数据,则直接从缓存读取数据。如果缓存未命中,则先从数据库读取数据,并将数据写入缓存。当客户端应用发起写请求时,客户端应用直接将新数据写入数据库。同时为保证Redis与Database的最终一致性,在客户端应用将数据写入缓存时,设置一个TTL,避免脏数据一直保存在Redis中。上述过程的伪代码表示如下:

Object readData(String keyStr) {Object data = readRedis(keyStr);if (data != null) {return data;}data = readDatabase(keyStr);writeRedis(keyStr, data, ttl);return data;
}boolean writeData(String keyStr, Object data) {return writeDatabase(keyStr, data);
}

针对写请求场景(新数据写入、已有数据的更新、已有数据的删除),特别是已有数据的更新和已有数据的删除这种情况,因为对于上述模式来说,只是将数据写入数据库,会带来Redis和数据的不一致。因为向Redis写入数据时,设置了TTL,所以一段时间后,Redis中的数据将最终与数据库一致。

总结

如果期望实现Redis缓存中数据与数据库中数据的强一致性,那么需要额外引入分布式事务组件,通过一致性协议(2PC、3PC)来实现实现Redis缓存中数据与数据库中数据的强一致性。但是,分布式事务组件的引入无疑会降低Redis缓存加速查询的初衷。所以很少看到需要Redis缓存中数据与数据库中数据保持强一致性的情况。
既然不强制要求Redis缓存中数据与数据库中数据的强一致性,那么是否可以加快Redis中数据与数据库中数据一致性的收敛速度呢?网络上针对如何加快Redis中数据与数据库中数据一致性的收敛速度,提出了多种解决方案,如:先更新数据库,再更新Redis;先更新数据库,再删除Redis中数据(直接删除Redis、延迟删除Redis);先删除Redis中数据,再更新数据库;先尝试删除Redis中数据,再更新数据库,再尝试删除Redis中数据(双删策略);先写数据库,然后通过binlog或队列,异步更新Redis中数据。笔者认为,以上方案虽然自成一体,但是不免纸上谈兵、画蛇添足,存在过度设计的问题。以上方案的一个公共特征是为了加快Redis中数据与数据库中数据一致性的收敛速度,需要执行多余的Redis写入步骤或引入额外的功能或组件(如数据库的binlog日志、队列等)。且在提升设计复杂度的同时,并没有真正起到加速一致性收敛的效果或收效甚微。且额外的Redis写入操作会加大Redis主从结点间同步负担,带来更多问题。
笔者认为,使用Redis作为缓存,就是已经接受了Redis缓存中数据可能存在脏数据的情况,且用户对数据不一致性的时间可容忍。与其考虑如何加快一致性收敛的速度,倒不如从业务出发,考虑Redis缓存的使用姿势是否合理,如将一些频繁更新且用户敏感的数据保存到Redis缓存就是一种不合理的使用;将数据长期的存储在Redis缓存中,且设置过长的TTL就是将Redis当做数据库使用,而不是缓存。此外,还应考虑将缓存前置,尝试使用客户端应用的本地缓存来提升性能。

参考

https://mp.weixin.qq.com/s/az1D1lKcoU9hiOIJjmjlJQ 4 种策略让 MySQL 和 Redis 数据保持一致
https://mp.weixin.qq.com/s/RL4Bt_UkNcnsBGL_9w37Zg 如何保障 MySQL 和 Redis 的数据一致性?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/577778.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux课程____selinux模式

一、是什么 它叫做“安全增强型 Linux(Security-Enhanced Linux)”,简称 SELinux,它是 Linux 的一个安全子系统 二、有啥用 就是最大限度地减小系统中服务进程可访问的资源(根据的是最小权限原则)。避免…

实践笔记-harbor搭建(版本:2.9.0)

harbor搭建 1.下载安装包(版本:2.9.0)2.修改配置文件3.安装4.访问harbor5.可能用得上的命令: 环境:centos7 1.下载安装包(版本:2.9.0) 网盘资源:https://pan.baidu.com/s/1fcoJIa4x…

基于springboot+vue实现的校企合作项目管理系统

作者主页:Java码库 主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】:Java 【框架】:spring…

【容器源码篇】Map容器(HashTable,HashMap,TreeMap的特点)

文章目录 ⭐容器继承关系🌹Map容器🗒️HashTable源码解析构造方法put方法remove方法rehash扩容 🗒️HashMap源码解析构造函数get方法put方法详解 扩容方法详解 🗒️TreeMap源码解析 ⭐容器继承关系 🌹Map容器 键值对映…

少量的样本对于深度学习来说,会造成过拟合还是欠拟合呢?

少量样本通常会导致过拟合,而不是欠拟合。过拟合指模型在训练数据上表现良好,但在未见过的测试数据上表现不佳,因为模型过于复杂,试图捕获训练数据中的噪声和细微特征。由于训练数据有限,模型可能会过度适应这些数据的…

基本数据类型

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 数据类型是一种用于描述数据存储格式的结构。 PL/SQL 和其他编程语言一样也有多种数据类型,PL/SQL 语言中的常用数据类型和 Oracle 数据库中内置的数据类型基本…

动手学机器学习K近邻算法+习题

K近邻算法 import matplotlib.pyplot as plt import numpy as np import os# 读入mnist数据集 m_x np.loadtxt(mnist_x, delimiter ) m_y np.loadtxt(mnist_y)# 数据集可视化 data np.reshape(np.array(m_x[0], dtypeint), [28, 28]) plt.figure() plt.imshow(data, cmapgr…

(C++笔试题)选择题+编程题

个人主页:Lei宝啊 愿所有美好如期而遇 选择题 第一道 下面对析构函数的正确描述是() A. 系统不能提供默认的析构函数B. 析构函数必须由用户定义C. 析构函数没有参数D. 析构函数可以设置默认参数 解析: 正确描述析构函数的…

tab切换组件,可横向自适应滑动

示例图&#xff1a; 注&#xff1a;需要引入Jquery <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.tabs-box {width: 100%;height: auto;}.tab-header-box {display: flex;overflow: hidden…

【AI】『Suno』哎呦不错呦,AI界的周董,快来创作你的歌曲吧!

前言 &#x1f34a;缘由 Suno AI的旋风终于还是吹到了音乐圈 &#x1f3c0;事情起因&#xff1a; 朋友说他练习时长两天半&#xff0c;用Suno发布了首张AI音乐专辑。震惊之余&#xff0c;第一反应是音乐圈门槛也这么低了&#xff0c;什么妖魔鬼怪都可以进军了嘛&#xff01;…

unity学习(77)--多玩家信息交互--不同类型的数据包

明白各个数据包的作用&#xff0c;以及是否正确的发挥作用 1.“120包”&#xff0c;客户端登录时发给服务器的&#xff0c;服务器处理后返回“121包”。 2.“121包” &#xff0c;服务器返回给客户端的&#xff0c;包含登录时所有在线玩家的信息。 客户端也通过createPlayer函…

【Android Studio3.5.2安装以及错误错误解决】

前言 下面是博主在安装Android studio时遇到的一些问题&#xff0c;并且花费很长时间寻找解决方法&#xff0c;经过了血和泪的教训下面将自己在安装过程中遇到的查看的资料贴出来&#xff08;感谢各位大佬的文章帮助本闲狗解答疑惑&#xff0c;此处贴出原文链接&#xff0c;如…