Redis是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key-value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。

按照我们一般的使用Redis的场景应该是这样的:

也就是说:我们会先去Redis中判断数据是否存在,如果存在,则直接返回缓存好的数据。而如果不存在的话,就会去数据库中,读取数据,并把数据缓存到redis中。适用场合:如果数据量比较大,但不是经常更新的情况(比如用户排行)

而第二种Redis的使用,跟第一种的情况完成不同,具体的情况请看:

这里我们会先去Redis中判断数据是否存在,如果存在,则直接更新对应的数据(吧对应更新过的key记录下来,比如也保存到redis中,key为save_update_keys),并把更新后的数据返回给页面,而如果不保存的话,就会去先更新数据库中的内容,然后把数据保存一份到Redis。后面的工作,后台会有相关机制把Redis中的save_update_keys存储的key,分别读取出来,找到对应的数据,更新到DB中。优点:主要目的是把Redis当做数据库使用,更新获取数据比DB块,非常适合大数据量的频繁变动(比如微博),缺点,对Redis的依赖很大,要做好宕机时的数据保存。

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与关系型数据库的同步问题相关推荐

  1. Redis 非关系型数据库 安装以及相关命令

    目录 一.缓存简介 1.1 系统缓存 1.2 缓存保存位置及分层结构 1.2.1 DNS缓存 1.2.2 应用层缓存 1.2.3 数据层缓存 分布式缓存服务 数据库 1.2.4 硬件缓存 二. 关系数 ...

  2. Redis非关系型数据库(三)持久化

    目录 一.redis高可用 1.持久化 2.主从复制 3.哨兵 4.集群(cluster) 二.Redis的持久化 1.RDB持久化 2.AOF持久化(append only file) 3.RDB和 ...

  3. 五、redis和关系型数据库如何配合使用

    1.先写缓存,在写数据库(这个需要考虑一下业务的合理性 ) 讲解:先写缓存,再写数据库.应用程序前端直接读写 Redis,后端匀速异步地把数据持久化到 MySQL 或 TiDB.这种做法一般被称之为& ...

  4. 关于Redis与关系型数据的一些区别

    Redis能替代关系型数据库吗? 为什么? 不能替代, 两者侧重点不同, redis是非关系型数据库,以k-v形式存储的内存数据库. 1,基于数据存在于缓存中如果redis服务器出现宕机的情况,会造成 ...

  5. MySQL数据库是非关系_MySQL(数据库)基础知识、关系型数据库yu非关系型数据库、连接认证...

    什么是数据库? 数据库(Database):存储数据的仓库 高效地存储和处理数据的介质(介质主要是两种:磁盘和内存) 数据库系统:DBS(Database System):是一种虚拟系统,将多种内容关 ...

  6. 非关系型数据库-NoSQL(Redis)

    文章目录 一.什么是 NoSQL? 二.NoSQL 的特性? 三.什么是 Redis? 四.Redis 安装部署 4.1 下载安装包 4.2 编译安装 4.3 修改配置文件 4.4 启动服务 4.5 ...

  7. hbase redis mongoddb neo4j 非关系型数据库简介

    Hbase 列式存储以流的方式在列中存储所有的数据.对于任何记录,索引都可以快速地获取列上的数据:列式存储支持行检索,但这需要从每个列获取匹配的列值,并重新组成行.HBase(Hadoop Datab ...

  8. mysql同步大师_数据库大师成长日记:您最需要了解的NoSQL非关系型数据库

    朋友们,我们平时使用的数据库,大多都是关系型数据库,包括MySQL.PostgreSQL.SQLServer等.关系型数据库的特点是数据的存储通过二维表格实现,将数据存储在相互独立的表格中. 近年来, ...

  9. 关系型数据库(Relational Database)与非关系型数据库(NoSQL)的区别:(MySQL,Redis,Memcache,MongoDB)

    Table of Contents 关系型数据库(Relational Database) 什么是关系数据库 什么是SQL? 关系数据库的结构 关系模型 关系数据库的好处 数据一致性 隔离性和原子性 ...

最新文章

  1. 配置中心Apollo的设计原理
  2. wps插件实用插件_6款实用PS插件合集,好用的PS插件都在这里!
  3. Go 语言编程 — 并发 — 同步原语与锁
  4. UA MATH574M 统计学习V Variable Selection: LASSO
  5. python中i+=1不等于++i
  6. Python_面向对象_zipfile和tarfile
  7. 乐乐勇智能教育机器人有多少型号_【头条】协作机器人平台化趋势将会是柔性自动化的破局之道...
  8. UVA - 213 Message Decoding
  9. Linux如何修改环境变量PATH,以及系统登录时读取文件的顺序
  10. jQuery动画之显示隐藏动画
  11. 2020最新版《神经网络与深度学习》中文版更新完毕,pdf开放下载
  12. 小程序 图片显示模式详解
  13. ps软件打不开计算机受限制,win10系统打不开ps软件的处理技巧
  14. 笔记本无线网口共享网络给以太网口
  15. XAMPP下的Tomcat 7运行出现“1% 不是有效的 Win32 应用程序。”
  16. 最新资讯:iPhone 11显示模块更换计划,用于解决触摸问题
  17. 用计算机四舍五入偷银行储户的钱,银行家舍入VS四舍五入(下):.NET发现之旅(四)...
  18. Java高并发编程 (马士兵老师视频)笔记(一)同步器
  19. 高山流水 (余秋雨)
  20. 微软出手,干翻 IDEA?网友:先干翻 Eclipse 吧

热门文章

  1. selenium无法定位到QQ邮箱登录页面的输入框元素和登录按钮元素-解决方法
  2. Xamarin Mono for VS开发窗体标题(Title)乱码解决方案
  3. 细数改善WPF应用程序性能的10大方法
  4. XML Schema ---complexType-----复合元素
  5. 简述用UCenter整合第三方应用程序
  6. sharepoint站点移植方案
  7. cognos10 安装部署
  8. 解不等式之代数和不等式
  9. 德国超级计算机中心,德国:强化人工智能能力建设 加大高性能计算网络投资...
  10. mysql日期格式化季度_mysql按年度、季度、月度、周、日统计查询的sql语句