专栏首页只为你下javascript正则表达式入门先了解这些
原创

javascript正则表达式入门先了解这些

  当执行写操作后,需要保证从缓存读取到的数据与数据库中持久化的数据是一致的,因此需要对缓存进行更新。

  

  因为涉及到数据库和缓存两步操作,难以保证更新的原子性。

  

  在设计更新策略时,我们需要考虑多个方面的问题:

  

  对系统吞吐量的影响:比如更新缓存策略产生的数据库负载小于删除缓存策略的负载

  

  并发安全性:并发读写时某些异常操作顺序可能造成数据不一致,如缓存中长期保存过时数据

  

  更新失败的影响:若某个操作失败,如何对业务影响降到最小

  

  检测和修复故障的难度: 操作失败导致的错误会在日志留下详细的记录容易检测和修复。并发问题导致的数据错误没有明显的痕迹难以发现,且在流量高峰期更容易产生并发错误产生的业务风险较大。

  

  更新缓存有两种方式:

  

  删除失效缓存: 读取时会因为未命中缓存而从数据库中读取新的数据并更新到缓存中

  

  更新缓存: 直接将新的数据写入缓存覆盖过期数据

  

  更新缓存和更新数据库有两种顺序:

  

  先数据库后缓存

  

  先缓存后数据库

  

  两两组合共有四种更新策略,现在我们逐一进行分析。

  

  并发问题通常由于后开始的线程却先完成操作导致,我们把这种现象称为“抢跑”。 下面我们逐一分析四种策略中“抢跑”带来的错误。

  

  先更新数据库,再删除缓存

  

  若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。

  

  可能发生的并发错误:

  

  时间 线程A 线程B 数据库 缓存

  

  1 缓存失效 v1 null

  

  2 从数据库读取v1 v1 null

  

  3 更新数据库 v2 null

  

  4 删除缓存 v2 null

  

  5 写入缓存 v2 v1

  

  先更新数据库,再更新缓存

  

  同删除缓存策略一样,若数据库更新成功缓存更新失败则会造成数据不一致问题。

  

  可能发生的并发错误:

  

  时间 线程A 线程B 数据库 缓存

  

  0 v0 v0

  

  1 更新数据库为 v1 v1 v0

  

  2 更新数据库为 v2 v2 v0

  

  3 更新缓存为 v2 v2 v2

  

  4 更新缓存为 v1 v2 v1

  

  当两个写线程发生冲突时,可以通过比较数据版本方式避免线程A写入旧的数据。

  

  先删除缓存,再更新数据库

  

  可能发生的并发错误:

  

  时间 线程A 线程B 数据库 缓存

  

  1 删除缓存 v1 null

  

  2 缓存失效 v1 null

  

  3 从数据库读取v1 v1 null

  

  4 更新数据库为v2 v2 null

  

  5 将v1写入缓存 v2 v1

  

  先更新缓存,再更新数据库

  

  若缓存更新成功数据库更新失败, 则此后读到的都是未持久化的数据。因为缓存中的数据是易失的,这种状态非常危险。

  

  因为数据库因为键约束导致写入失败的可能性较高,所以这种策略风险较大。

  

  可能发生的并发错误:

  

  时间 线程A 线程B 数据库 缓存

  

  0 v0 v0

  

  1 更新缓存为 v1 v0 v1

  

  2 更新缓存为 v2 v0 v2

  

  3 更新数据库为 v2 v2 v2

  

  4 更新数据库为 v1 v1 v2

  

  异步更新

  

  双写更新的逻辑复杂,一致性问题较多。现在我们可以采用订阅数据库更新的方式来更新缓存。

  

  阿里巴巴开源了mysql数据库binlog的增量订阅和消费组件 - canal。

  

  我们可以采用API服务器只写入数据库,而另一个线程订阅数据库 binlog 增量进行缓存更新的策略。

  

  这种策略存在和先更新数据库后删除缓存类似的并发问题:

  

  时间 读线程 写线程 异步线程 数据库 缓存

  

  1 缓存失效 v1 null

  

  2 从数据库读取v1 v1 null

  

  3 更新数据库为v2 v2 null

  

  4 删除缓存/更新缓存 v2 null

  

  5 写入缓存 v2 v1

  

  这个问题同样可以采用异步线程更新缓存,且写入缓存时比较数据版本的方法来解决。

  

  var array1 = [. www.motianydl.cn ..str1.matchAll(regexp1)www.lecaixuanzc.cn];

  

  console.log(array1)

  

  //['test1','e','st1','1',index: www.51baishizc.cn,input: 'test1test2',groups: undefined]

  

  //['test2','e','st2','2',index: 5,input: 'test1test2',groups: undefined]

  

  var array2 = [...str2.matchAll(regexp2)];

  

  console.log(array2)

  

  //['test1','www.zhuyngyule.cn','st1','1',index: www.51feiyuzc.cn,input: www.shentuylgw.cn'test1test2',groups: undefined]

  

  Keep working, www.javachenglei.com will find a way out. This is Finley, welcome to join us.

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 面试中很值得聊的二叉树遍历方法——Morris遍历

    通过利用空闲指针的方式,来节省空间。时间复杂度O(N),额外空间复杂度O(1)。普通的非递归和递归方法的额外空间和树的高度有关,递归的过程涉及到系统压栈,非递归...

    不会飞的小鸟
  • Python 3.9 新特性:任意表达式可作为装饰器!

    一个月前(2月20日),一则新的 PEP 没有受到任何阻碍就被官方采纳了,这么快的速度,似乎并不多见。

    不会飞的小鸟
  • 使用python实现数组、链表、队列、栈

      数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。

    不会飞的小鸟
  • 究竟先操作缓存,还是数据库?

    但是,一旦没有命中缓存,或者一旦涉及写操作,流程会比没有缓存更加复杂,这些是今天要分享的话题。

    架构师之路
  • 【每周三面】Redis 面试常见问答

    通常,我们会使用缓存用于缓冲对 DB 的冲击,如果缓存宕机,所有请求将直接打在 DB,造成 DB 宕机——从而导致整个系统宕机。

    趣学程序
  • 缓存一致性

      系统程序处理时,缓存作为DB的一道屏障,可以防止大量请求达到数据库,造成压力过大,还可以提高查询效率。

    OPice
  • redis缓存介绍与常见问题(精心准备)

    对于web来说,是用户量和访问量支持项目技术的更迭和前进。随着服务用户提升。可能会出现一下的一些状况:

    bigsai
  • 谈谈缓存更新

    看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作...

    Java架构
  • 搞懂分布式技术15:缓存更新的套路

    本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

    Java技术江湖
  • 缓存更新的套路

    看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作...

    wangxl

扫码关注云+社区

领取腾讯云代金券