架构师-怎样保证redis和数据库的同等性

打印 上一主题 下一主题

主题 830|帖子 830|积分 2490

 
概述

在分布式体系中,保证Redis和MySQL之间的数据同等性是一个复杂且告急的题目。由于Redis是内存数据库,而MySQL是磁盘数据库,它们的特性和持久化方式不同,因此必要特别的注意和处置惩罚来确保数据的同等性。
以下是一些常见的方法来保证Redis和MySQL之间的数据同等性:

  • 双写模式:在进行写操作时,先将数据写入MySQL,然后再将数据写入Redis。这种方式可以保证MySQL中的数据一定会被同步到Redis中,但是对于读操作来说效率较低。
  • 异步更新:在进行写操作时,只将数据写入MySQL,然后异步地将数据写入Redis。这种方式可以提高写入操作的效率,但是大概会导致Redis中的数据与MySQL中的数据存在一定的耽误。
  • 通过消息队列实现数据同步:可以利用消息队列(如Kafka、RabbitMQ等)来实现MySQL和Redis之间的数据同步。当MySQL中的数据发生变革时,将变革的数据写入消息队列,然后Redis订阅消息队列,根据消息内容更新自己的数据。这种方式可以实现异步更新,而且解耦了MySQL和Redis之间的直接依赖。
  • 定期全量同步:定期从MySQL中读取全量数据,然后覆盖Redis中的数据。这种方式可以保证Redis中的数据与MySQL中的数据完全同等,但是对于大数据量的环境下大概会影响性能。
  • 利用分布式事务:在一些场景下,可以利用分布式事务来保证Redis和MySQL之间的数据同等性。例如,可以利用基于XA协议的分布式事务管理器(如Seata)来和谐Redis和MySQL之间的数据更新操作。 必要根据具体的业务场景和需求选择合适的数据同等性方案,并进行相应的计划和实现。同时,还必要考虑各种非常环境下的处置惩罚,如网络故障、节点宕机等,以确保体系在非常环境下依然能够保持数据同等性。


  •  

    解决方案
    1.基于 MQ 异步同步更新,消息队列+异步重试-比如基于 RocketMQ 的可靠性消息通讯,来实现终极同等
    2.还可以直接通过 Canal (阿里的一款开源框架)组件,监控 Mysql 中 binlog 的日记,把更新后的数据同步到 Redis 里面。
    3.延时双删
    缓存延时双删
    删除缓存重试机制
    读取biglog异步删除缓存
    一样平常环境下,Redis 用来实现应用和数据库之间读操作的缓存层,主要目的是减少数据库 IO,还可以提升数据的 IO 性能。这是它的团体架构
    当应用程序必要去读取某个数据的时候,起首会先尝试去 Redis 里面加载,如果掷中就直接返回。如果没有掷中,就从数据库查询,查询到数据后再把这个数据缓存到 Redis 里面。
    在如许一个架构中,会出现一个题目,就是一份数据,同时保存在数据库和 Redis里面,当数据发生变革的时候,必要同时更新 Redis 和 Mysql,由于更新是有先后次序的,而且它不像 Mysql 中的多表事务操作,可以满意 ACID 特性。以是就会出现数据同等性题目。
    在这种环境下,能够选择的方法只有几种
    先更新数据库,再更新缓存
    先删除缓存,再更新数据库
    如果先更新数据库,再更新缓存,如果缓存更新失败,就会导致数据库和 Redis中的数据不同等。
    如果是先删除缓存,更新数据库,理想环境是应用下次访问 Redis 的时候,发现 Redis 里面的数据是空的,就从数据库加载保存到 Redis 里面,那么数据是同等的。但是在极度环境下,由于删除 Redis 和更新数据库这两个操作并不是原子的,以是这个过程如果有其他线程来访问,还是会存在数据不同等题目
    如果必要在极度环境下仍然保证 Redis 和 Mysql 的数据同等性,就只能接纳终极同等性方案。
    消息队列+异步重试 基于 RocketMQ 的可靠性消息通讯,来实现终极同等

    因为延时双删大概会存在第二步的删除缓存失败,导致的数据不同等题目。可以利用这个方案优化:删除失败就多删除几次呀,保证删除缓存乐成绩可以了呀~ 以是可以引入删除缓存重试机制

    删除缓存重试流程
    Canal 组件,监控 Mysql 中 binlog 的日记,把更新后的数据同步到 Redis 里面

    因为这里是基于终极同等性来实现的,如果业务场景不能担当数据的短期不同等性,那就不能利用这个方案来做
    异步更新缓存(基于订阅binlog的同步机制)
    MySQL binlog增量订阅消耗+消息队列+增量数据更新到redis读Redis
    热数据基本都在Redis写MySQL:增删改都是操作MySQL更新Redis数据:MySQ的数据操作binlog,来更新到Redis:
    1)数据操作主要分为两大块:一个是全量(将全部数据一次写入到redis)一个是增量(实时更新)。
    这里说的是增量,指的是mysql的update、insert、delate变更数据。
    2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
    如许一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,Redis再根据binlog中的记录,对Redis进行更新。
    其实这种机制,很类似MySQL的主从备份机制,因为MySQL的主备也是通过binlog来实现的数据同等性。
    这里可以结合利用canal(阿里的一款开源框架),通过该框架可以对MySQL的binlog进行订阅,而canal正是模拟了mysql的slave数据库的备份请求,使得Redis的数据更新达到了雷同的效果。
    当然,这里的消息推送工具你也可以接纳别的第三方:kafka、rabbitMQ等来实现推送更新Redis
    重试删除缓存机制还可以吧,就是会造成好多业务代码入侵。其实,还可以如许优化:通过数据库的binlog来异步镌汰key。

    以mysql为例吧
    ● 可以利用阿里的canal将binlog日记采集发送到MQ队列里面
    ● 然后通过ACK机制确认处置惩罚这条更新消息,删除缓存,保证数据缓存同等性
    延时双删

    1. redis.delKey(X)
    2. db.update(X)
    3. Thread.sleep(N)
    4. redis.delKey(X)
    5. 
    复制代码
    先删除缓存,再更新数据库,当更新数据后休眠一段时间再删除一次缓存。
    这个休眠时间 = 读业务逻辑数据的耗时 + 几百毫秒。为了确保读请求竣事,写请求可以删除读请求大概带来的缓存脏数据。
    这种方案还算可以,只有休眠那一会(比如就那1秒),大概有脏数据,一样平常业务也会担当的。但是如果第二次删除缓存失败呢?缓存和数据库的数据还是大概不同等,对吧?给Key设置一个自然的expire过期时间,让它自动过期怎样?那业务要担当过期时间内,数据的不同等咯?还是有其他更佳方案呢?
  • 延时双删策略在高并发环境下,通过在第一次删除缓存后延时一段时间进行第二次删除缓存,确保缓存和数据库中的数据同等,避免并发操作带来的数据不同等题目。步骤是:先删除Redis缓存数据,再更新Mysql,耽误几百毫秒再删除Redis缓存数据,如许就算在更新Mysql时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删撤除, 从而把数据保持⼀致
  • 弱同等性和强同等性

    数据同步过程中,会存在短暂的耽误,这属于正常的现象。
    在分布式架构中很难实现数据强同等性
    弱同等性: 主从之间数据答应不同等性;
    强同等性: 主从之间数据必须同等性; 如果实现 本钱黑白常高,管帐划到 一些锁的技术,
    终极同等性:短暂的数据耽误是答应的,但是终极数据是必要同等; —在分布式中做数据同步必要经过网络传输的,网络传输数据必要一定的时间, 以是数据短暂的耽误是答应的,但是终极数据一定告竣同等。
    耽误是很难避免的,优化 减少耽误的时间。 公司中数据 同步耽误 优化在 10-30 毫秒。
    Canal详解

    Canal 是阿里巴巴开源的数据库变更捕获(CDC)解决方案,主要用于监控数据库的变更,并将这些变更推送到其他数据存储、消息队列等目标端。以下是对 Canal 的详细表明:
    方案二:还可以直接通过 Canal 组件,监控 Mysql 中 binlog 的日记,把更新后的数据同步到 Redis 里面。
  • 延时双删有啥作用?

    • 为了使得缓存和数据库数据终极同等。

  • 为什么要删除缓存数据,而不是修改?

    • 如果是修改,并发修改数据场景,先改缓存的有大概后改库,先改库的也大概后改缓存。

  • 为什么要睡眠延时一段时间?

    • 读写分离是解决高并发比力有效的方案,但是缓存/库的主从是异步更新数据的。
    • 睡眠一段时间,就是为了库和缓存能实现数据主从同步。

  • 延时双删能确保缓存和数据库终极同等吗?

    • 不能确保。
    • 只能通过延时最大程度上提高数据的终极同等的概率。
    • 如果缓存和数据库负载很高,主从同步很慢,很有大概不能在延时的时间内实现同步。

  • 脏读怎么办?

    • 确实有这题目,要知道这是终极同等,并不是强同等,末了一次删除就是为了终极同等^_^!
    • 以是要确保你的业务场景能忍受数据终极同等的缺陷,着实不行你读主库呗。
    • 优化业务逻辑的计划,具体请参考下文的:通过业务计划加强数据同等性 章节。

  • 为什么要有第一次删除缓存?
    1> 删除脏读。
    2> 提前实现别的操作的数据终极同等。

    • 延时双删有 4 个步骤,全部实行完才华实现数据终极同等,大概会比力慢!
    • 延时双删第三个步骤延时期待是比力漫长的,有大概在期待时间超时前,数据就已经完成同步了。在并发环境中,如果别的并发环节增长第一次删除,大概会提前实现前面操作的数据终极同等,不用等延时双删四个步骤都完成。


接纳缓存耽误双删策略最多在X毫秒内读取的数据是老数据,在X毫秒之后读取的数据都是最新的数据。X的具体值怎样确定那就必要根据自身的业务了来确定。
耽误双删策略只能保证终极的同等性,不能保证强同等性
怎样实现耽误双删

耽误双删策略主要是为了维护数据同等性,特别是在高并发的环境下。它确保了在写入数据库之前,缓存数据被删除,然后在耽误一段时间后再次删除缓存,以应对以下环境:

  • 数据修改并发题目:如果多个请求同时尝试修改数据库中的数据,而缓存中的数据没有被删除,就有大概导致数据不同等。某个请求大概会在缓存中获取旧数据并写入数据库,然后其他请求又读取了旧数据,从而导致数据不同等。
  • 缓存与数据库同步题目:纵然写入数据库是同步的,缓存的删除大概是异步的,这意味着缓存中的数据大概在数据库写入之后仍然存在,导致不同等性。
耽误双删策略通过以下步骤解决了这些题目:

  • 删除缓存:起首,缓存中的数据被删除,确保了缓存中不再有旧数据。
  • 写入数据库:然后,数据被写入数据库,以确保数据的持久性。
  • 休眠一段时间:在写入数据库后,应用程序期待一段时间。这个期待时间是为了确保在这段时间内,所有大概的读取操作都能够访问数据库中的最新数据,而不再访问缓存。
  • 再次删除缓存:末了,在休眠时间竣事后,再次删除缓存。这可以确保纵然有一些读取操作仍然从缓存中获取数据,它们也会得到最新的数据。
以下是一个利用Java代码实现耽误双删策略的示例:
  1. import java.util.concurrent.TimeUnit;
  2. public class CacheManager {
  3.     public void deleteCache(String key) {
  4.         // 删除缓存的实现
  5.         // 请根据您的缓存库的具体方法来删除缓存数据
  6.     }
  7.     public void writeToDatabase(String data) {
  8.         // 写入数据库的实现
  9.         // 请根据您的数据库访问库来执行写入操作
  10.     }
  11.     public void delayDoubleDelete(String key, String data, long delayTimeInSeconds) {
  12.         // 先删除缓存
  13.         deleteCache(key);
  14.         // 写入数据库
  15.         writeToDatabase(data);
  16.         // 休眠一段时间(根据业务需求设置的延迟时间)
  17.         try {
  18.             TimeUnit.SECONDS.sleep(delayTimeInSeconds);
  19.         } catch (InterruptedException e) {
  20.             Thread.currentThread().interrupt();
  21.         }
  22.         // 再次删除缓存
  23.         deleteCache(key);
  24.     }
  25.     public static void main(String[] args) {
  26.         CacheManager cacheManager = new CacheManager();
  27.         String key = "example_key";
  28.         String data = "example_data";
  29.         long delayTimeInSeconds = 5; // 延迟时间为5秒
  30.         cacheManager.delayDoubleDelete(key, data, delayTimeInSeconds);
  31.     }
  32. }
复制代码
上述代码示例中,我们创建了一个CacheManager类,其中包罗了删除缓存和写入数据库的方法,以及delayDoubleDelete方法来实行耽误双删策略。在main方法中演示了怎样利用它来实行耽误双删操作。确保根据您的现实需求和缓存库、数据库库的具体方法来实现deleteCache和writeToDatabase方法。请注意,这只是一个简单的示例,现实实现大概必要考虑错误处置惩罚、并发控制和合适的耽误时间。耽误时间的选择应根据应用的需求来确定,以确保充足的时间供所有大概的读取操作从数据库中获取最新数据。
Redis耽误双删是为了解决网络耽误导致指令没有正常实行的题目。当通过Redis发送一个删除指令时,由于网络耽误的存在,Redis服务器大概无法立刻实行该指令。为了避免出现误删的环境,耽误双删就被用来保证删除操作的可靠性。
耽误双删的原理是在实行删除指令之前,先将要删除的键值对设置一个过期时间。为了确保过期时间能够充足长,一样平常会设置为比力长的时间,例如1秒。然后再实行第二次删除操作,确保键值对被删除。
为什么要删第一次呢?这是因为在Redis中,删除操作是立刻返回的,纵然现实上删除操作并没有立刻实行。以是,通过第一次删除来触发过期时间的设置,并立刻返回。然后在网络耽误竣事后,再实行第二次删除操作来真正删除键值对。
耽误双删的利益在于能够保证删除操作的可靠性。纵然在网络耽误的环境下,也能够有效地删除键值对,避免出现误删的环境。在现实应用中,耽误双删可以用于解决分布式锁的题目,保证锁的正常开释。
总之,耽误双删是为了解决网络耽误导致指令没有正常实行的题目,并保证删除操作的可靠性。通过设置过期时间和实行两次删除操作,可以有效地避免误删和确保删除的可靠性。这是Redis在处置惩罚删除操作时的一种常用策略。
 
 
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表