Redis和数据库同步问题

缓存充当数据库

比如说Session这种访问非常频繁的数据,就适合采用这种方案;当然了,既然没有涉及到数据库,那么也就不会存在一致性问题;

缓存充当数据库热点缓存

读操作

目前的读操作有个固定的套路,如下:

  1. 客户端请求服务器的时候,发现如果服务器的缓存中存在,则直接取服务器的;

  2. 如果缓存中不存在,则去请求数据库,并且将数据库计算出来的数据回填给缓存;

  3. 返回数据给客户端;

写操作

各种情况会导致数据库和缓存出现不一致的情况,这就是缓存和数据库的双写一致性问题;

目前缓存存在三种策略,分别是

  • Cache Aside 更新策略:同时更新缓存和数据库;

  • Read/Write Through 更新策略:先更新缓存,缓存负责同步更新数据库;

  • Write Behind Caching 更新策略:先更新缓存,缓存定时异步更新数据库;

三种策略各有优缺点,可以根据业务场景使用;

Cache Aside 更新策略

该策略大概的流程就是请求过来时先从缓存中取,如果命中缓存的话,则直接返回读取的数据;相反如果没有命中的话,接着会从数据库中成功获取到数据后,再去清除缓存中的数据;具体流程图如下:

但是以上在某些特殊的情况下是存在问题:

问题1:先更新数据库,后更新缓存

两个线程在高并发的情况下就会可能出现数据脏读的情况:

  1. 线程A执行写操作,成功更新数据库;

  2. 线程B同样执行和线程A一样的操作,但是在线程A执行更新缓存的过程中,线程B更新了新的数据库数据到缓存中;

  3. 线程A在线程B全部操作完成以后才将相对老的数据又更新到了缓存中;

问题2:先删除缓存,后更新数据库

同样的,在高并发场景下同样会出现脏读的情况:

  1. 线程A成功删除了缓存,等待更新数据库;

  2. 线程B进行读操作,由于此时缓存已经被删除了,因此线程B重新从数据库中获取老的数据并且更新到了缓存中;

  3. 线程A在线程B完成了整个的读操作以后,才更新数据库,此时缓存中的数据依旧是老的数据;

问题3:先更新数据库,后删除缓存

目前这是比较普遍的操作,即使它还是有可能会出现脏读的情况:

  1. 线程A进行读操作,此时正好没有命中缓存,接着请求数据库;

  2. 线程B进行写操作,在线程A没有从数据库中获取到数据之前,把数据写入到数据库中,并且还成功删除了缓存;

  3. 线程A在线程B完成了整个的写操作以后,才将相对老的数据更新到缓存中;

但是以上的情况比较不会出现,这是因为上述情况需要满足线程A的读操作要慢于线程B的写操作,但是在现实过程中,读操作通常都是要快于写操作得多的,但是为了避免发生以上的情况,通常都是要给缓存加上一个过期的时间

但是设想一下,如果上面的删除缓存失败了怎么办呢,这样显然会导致数据脏读的情况,我觉得方案如下:

  1. 设置缓存的过期时间(必须要做);

  2. 提供一个保障重试机制,将哪些删除失败的key提供给消息队列去消费;

  1. 从消息队列取出这些key再次进行删除,失败再次加入到消息队列中,超过一定次数以上则人工介入;

但是以上情况需要在业务代码中进行操作,显然得需要进行解耦;

目前我们公司就是使用该方案,具体过程为在更新数据库数据的时候,数据库会以binlog日志的形式保存下来,通过canal开源软件将binlog解析成程序语言可以解析的地步,接着订阅程序获取到这些数据以后,尝试删除缓存操作,如果操作失败的话,则将其加入到消息队列中,重复消费,当删除操作的失败次数到达一定的次数以后,还是得人工介入。

Read/Write Through 更新策略

该模式下,程序只需要维护缓存即可,数据库的同步工作交由缓存来同步更新;

该策略具体又分为两种:

  1. Read Through:在查询的过程中更新缓存;

  2. Write Through:在写操作的过程中如果命中缓存,则直接更新缓存,数据库则由缓存自己同步去更新;

Write Behind Caching 更新策略

该策略只更新缓存,不会立马更新数据库,只会在一定的时间异步的批量去操作数据库;这样的好处在于直接操作缓存,效率极高,并且操作数据是异步的,还可以将多次的操作数据库语句合并到一个事务中一起提交,因此效率很客观;

但是,该策略没有办法做到数据强一致性,并且实现逻辑相对是比较复杂的,因为它需要确认哪些是需要更新到数据库的,哪些是仅仅想要存储在缓存中的;

比较

目前通常使用的是第一种策略中的先更新数据库,后更新缓存;其他的相较比起来实现都比较复杂;

最后想说的是,缓存本来就是为了牺牲强一致性来提高性能的,所以肯定会存在一定的延迟时间,我们只需要保证最终的数据一致性即可;

最后

以上是我在学习过程中的总结(其中很多内容都用了其他博客的内容),感恩~

【原创】分布式之数据库和缓存双写一致性方案解析

面试前必须要知道的Redis面试题

使用缓存的正确姿势

Redis和数据库 数据同步问题的更多相关文章

  1. redis如何实现数据同步

    redis如何实现数据同步 两种,1全同步,2部分同步 全备份: 在slave启动时会向master发送sync消息,master收到slave这条消息之后,将启动后台备份进程,备份完成之后,将备份数 ...

  2. 两台Mysql数据库数据同步实现

    两台Mysql数据库数据同步实现 做开发的时候要做Mysql的数据库同步,两台安装一样的系统,都是FreeBSD5.4,安装了Apache 2.0.55和PHP 4.4.0,Mysql的版本是4.1. ...

  3. redis与DB数据同步问题

    Redis 是一个高性能的key-value数据库. redis的出现,很大程度补偿了memcached这类key-value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用.它提供了Pyt ...

  4. Redis和MySQL数据同步及Redis使用场景

    1.同步MySQL数据到Redis (1) 在redis数据库设置缓存时间,当该条数据缓存时间过期之后自动释放,去数据库进行重新查询,但这样的话,我们放在缓存中的数据对数据的一致性要求不是很高才能放入 ...

  5. Oracle数据库数据同步方案

    一.比较原始的方案:触发器/Job/快照+dblink的方式,可实现同步和定时刷新: 二台不同的数据库服务器,从一台数据库服务器A的一个用户读取另一台数据库服务器B下某个用户的数据,可以通过dblin ...

  6. redis 学习笔记——数据同步、事务

    redis主从同步      redis支持简单易用的主从复制(master-slave replication)功能,该功能也是redis高可用性实现的基础.   redis复制原理      re ...

  7. Docker环境下的Mysql8 实现主从数据库数据同步方案

    本文记录下通过MySQL Replication在Docker环境下,通过多个容器 实现数据库主从配置. MySQL Replication就不多解释了,简单说就是MySQL非常出色的一个功能,该功能 ...

  8. solr 简单搭建 数据库数据同步(待续)

    原来在别的公司负责过文档检索模块的维护(意思就是不是俺开发的啦). 所以就略微接触和研究了下文档检索. 文档检索事实上是全文检索.是通过一种技术把N多文档进行一定规律的分割归类,然后创建易于搜索的索引 ...

  9. redis秒杀系统数据同步(保证不多卖)

    东西不多卖 秒杀系统需要保证东西不多卖,关键是在多个客户端对库存进行减操作时,必须加锁.Redis中的Watch刚好可以实现一点.首先我们需要获取当前库存,只有库存中的食物小于购物车的数目才能对库存进 ...

随机推荐

  1. 单字节编码&双字节编码

    单字节编码(WINDOWS-1252.ISO-8859-1.UTF-8) 双字节编码(UTF-16) Windows 记事本默认会将文件保存为单字节的 ANSI(ASCII).如果您选择 " ...

  2. Spring Cloud (十五)Stream 入门、主要概念与自定义消息发送与接收

    前言 不写随笔的日子仿佛就是什么都没有产出一般--上节说到要学Spring Cloud Bus,这里发现按照官方文档的顺序反而会更好些,因为不必去后边的章节去为当前章节去打基础,所以我们先学习Spri ...

  3. 强悍的CSS工具组合:Blueprint, Sass, Compass

    掌握CSS是每个Web开发者的基本要求,虽然CSS本身并不复杂,但怎样写出支持所有主流浏览器(特别是IE)的CSS,以及在大型网站中如何有序地组织好CSS结构却是一个相当棘手的问题.我更多的是一个开发 ...

  4. HTML5 移动开发(CSS3设计移动页面样式)

    1.如何创建CSS样式表 2.CSS3的卓越特性 3.基于设备属性改变样式的媒体查询 4.如何使用属性改变元标签创建更美观移动页面   层叠样式表是移动WEB开发中的一个重要组成部分,本次分享将学到如 ...

  5. Ajax和jsonp区别

    大多数情况下,无论是框架还是自己实现都是通过Ajax的方式来向后端请求数据的,而Ajax之间是通过传输json格式的文件来进行数据的传输的,大家对Ajax也很熟悉了,那么为什么我又要使用jsonp呢? ...

  6. ListView position

    在使用listview的时候,我们经常会在listview的监听事件中,例如OnItemClickListener(onItemClick)中,或listview的adapter中(getView.g ...

  7. mount过程分析之六——挂载关系(图解)【转】

    转自:https://blog.csdn.net/zr_lang/article/details/40343899 引言 写到这里我们已经从mount文件系统调用的入口开始,分析到内核的mount,通 ...

  8. 006_mac osx 应用跨屏幕

    一般情况下 mac osx 中一个应用程序只能在一个屏幕上显示,作为从 windows 转过来的用户有点不太习惯,Goolge 后发现还是有解决方案的(虽然不是很好用). 打开 Mac 的系统偏好设置 ...

  9. jQuery下的onChange事件在某些情况下无效

    onChage无效的原因: 虽然表面上感觉是当内容发生变化时,就会触发onchange事件,但是那只能在页面上操作.而如果通过dom对象去修改它的value则什么事也不会发生. onchange触发原 ...

  10. enum 关键字

    java.lang.Enum.java enum :枚举类型当你需要创建一个整型常量集,但是这些枚举值并不会必然地将其自身的取值限制在这个常量的范围之内,这种情况可以用枚举 package objec ...