• 小可 置顶
    2019-10-16
    工作中老师说的这几种缓存策略基本都用到了,特别是统计接口响应时间那个例子和我们的场景一样。管理平台统计一百多个节点的上报到队列中的数据,原来是按消费一批统计完直接批量入库,数据量太大(每秒两三千),压力全在数据库,系统也比较卡,并且如果入库不及时就会数据积压,后续都跟不上。现在是消费统计和入库分开,消费统计先放缓存,每分钟再将缓存同步到数据库,同步成功再提交消费offset,目前看还算稳定。

    作者回复: 👍

     8
     6
  • 任鹏斌
    2019-10-16
    读到这里突然想到一个开源项目https://github.com/apache/ignite,内存数据库,结合了关系型数据库和缓存的优点,如果只当缓存使用的话,可以自动加载和写入关系型数据库中的数据。完美解决一致性问题。但是好像国内使用的人不多。

    作者回复: 好滴,我关注一下~

    
     13
  • 岁寒
    2019-10-16
    缓存一定会引入不一致的。。

    作者回复: 是的 所以解决的办法需要权衡一致性和性能

    
     6
  • 七号叽
    2019-10-16
    老师你好,请问一下write back策略为什么读请求时是“如果缓存不是脏的,则由缓存组件将后端存储中的数据加载到缓存中”,而不是直接返回?谢谢

    作者回复: 否则缓存块就可能永远是脏的了

     5
     4
  • 王大伟
    2019-10-16
    Read/Write Through策略与MySQL的Buffer Pool的机制很相似啊
     2
     4
  • 长期规划
    2019-10-24
    老师,我理解WriteBack策略相当于缓存和缓冲区合二为一了,对吧。据我所知,MySQL的buffer pool使用了WriteBack策略,但为了防止系统崩溃后数据丢失,MySQL使用了WAL(Write-Ahead Logging)机制,写先日志。好像WAL在HBase等系统也在用

    作者回复: 是的

    
     3
  • Geek_49305e
    2019-10-18
    老师,1. 一种做法是在更新数据时也更新缓存,只是在更新缓存前先加一个分布式锁,因为这样在同一时间只允许一个线程更新缓存,就不会产生并发问题了。 这个解决方案应该有些不严谨的地方,如有A,B两个线程,A先更新数据库的值为20,而后A获取到更新缓存的分布式的锁,但未释放锁,此时B更新数据库的值为21,更新后尝试获取锁,此时获取锁一定会失败,抛出异常,终止更新缓存。 最后缓存中的数据为A更新的的值20

    作者回复: 这种情况下,在更新数据库之前就要加锁

     1
     3
  • 约书亚
    2019-10-16
    Cache Aside对缓存命中率两种解决方案中的1,可能是我没看懂,感觉没解决问题啊?
    这里说在“更新数据时也更新缓存”,我理解就是先更新DB再更新缓存,这样除非在更新DB之前加分布式锁,否则在更新DB之后加分布式锁,再更新缓存,依然较高可能出现不一致的情况。
    实际中我们确实用在更新缓存时用分布式锁或本地锁,只不过是发现缓存为空而去读DB时,为了解决穿透问题。
    纯个人见解,除了cache aside,另外两种更贴近底层系统开发而不是商业应用开发。因为我们大多数人做的系统,都是低速存储都是数据库,是有复杂的业务逻辑约束的,比如唯一性等,不是那种简单的page/cpu cahce。我们经常的写操作一般都要借助数据库来检验这些约束并且在出错之后返回给用户。而如果直接与缓存打交道,且不论有些缓存的实现并不保证数据可靠性,也不能依靠缓存检验这些约束。
    其实现在很多系统用的一种缓存模式是类似CQRS,写直接修改DB,异步更新到缓存,读只从缓存读数据。适合对数据不一致窗口可以容忍的场景。
    展开

    作者回复: 1. 是在更新数据库前加锁,锁的粒度是大了一些
    2. 确实是更偏重底层开发

    
     3
  • 无形
    2019-11-04
    文中提到的第一个第一个缓存和数据不一致的问题,我认为这个问题的原因是,多个客户端更新缓存和数据库之间是无序的、并发的操作,这样必然导致数据不一致的问题,因此我们采用了监听binlog的方式,把Binlog扔到消息队列中,由一个leader来消费,负责更新缓存,保证了写缓存操作之间的顺序性,保证了缓存的准确性,避免了频繁读库。

    作者回复: 这样确实是一个比较好的方式,只是会稍微复杂

     3
     2
  • fdconan
    2019-10-23
    Cache Aside(旁路缓存)策略,对于读多写少场景,当一个写操作更新db后同时删除缓存。然后多个读就会回源,这不会造成db压力么?

    作者回复: 会的,这就是狗桩效应嘛~

    
     2
  • 程序水果宝
    2019-10-22
    使用写回策略,如果在缓存更新到数据库之前设备掉电了,那这样数据岂不是丢失了,请问这是怎么解决的呢,通过主备机制吗,缓存数据写两份?

    作者回复: 是有这个问题,比如pagecache在机器掉电之后就都是数据了。一个办法是将写入缓存的操作写入log里,类似lsm树的write ahead log

    
     2
  • yc
    2019-10-17
    write back策略读请求时“如果缓存不是脏的,则由缓存组件将后端存储中的数据加载到缓存中”,是不是写错了,如果缓存不是脏的,直接从缓存返回即可,为什么还要从后端记载数据到缓存然后返回?我看留言很多人都有同样的疑问,请老师解释一下,谢谢。

    作者回复: write back策略其实不算数据库和mc之间的策略,而是计算机体系结构中的策略,比如磁盘文件的缓存。它的完整读策略是这样的:如果缓存命中,则直接返回;如果缓存不命中,则重新找一个缓存块儿,如果这个缓存块儿是脏的,那么写入后端存储,并且把后端存储中的数据加载到缓存中;如果不是脏的,那么就把后端存储中的数据加载到缓存,然后标记缓存非脏。
    是我的讲述不太清晰,感谢你的提问

    
     2
  • 饭团
    2019-10-16
    老师问您一个问题!其实如果是使用.Cache Aside方式的话。在写的时候时候因为更新数据后,删除了缓存。在高并发情况下。那么可能会出现以下情况:
    主从同步的情况下,从库没来得及同步。大量的读请求返回的是从库的旧数据。而这个时候读的数据会被动写入缓存。那就存在很大的问题!这种应该怎么处理!如果是这样的话?是不是只能依靠分布式锁来实现了!

    作者回复: 是的 这样只能更新缓存,然后使用分布式锁来控制

     3
     2
  • 长期规划
    2019-12-18
    老师,写穿策略中先写缓存再同步DB,此过程若是多线程,需要加锁吧,如果不加,也存在写覆盖问题

    作者回复: 是的,可以加分布式锁

    
     1
  • 长期规划
    2019-12-17
    Cache Aside在更新频繁时的两种解决策略应该是很经典的CAP问题吧,要保证C就要一定程度上牺牲A,反之亦然。看哪个更重要

    作者回复: 是的

    
     1
  • Fourty Seven
    2019-11-07
    老师,写回策略中,读请求未命中,为啥要找可用缓存块,可用是指什么?有数据?没数据?这块没太理解
     1
     1
  • 你净瞎说~
    2019-10-29
    脏是针对缓存块来说的吧?缓存也有脏不脏吗?

    作者回复: 指的是缓存使用的那块内存有未被刷新到后端存储中的数据,就认为是脏的

     2
     1
  • 小喵喵
    2019-10-20
    Read Through/Write Through...策略的示意图是不是画错了?
    缓存命中?否---------->读缓存-------------->数据库加载数据到缓存
    缓存都没有命中,再去读缓存也无法命中啊。中间步骤(读缓存)是不是多余的呢?

    作者回复: 这个读缓存想表达的意思是由缓存将数据加载到缓存中的

    
     1
  • JackJin
    2019-10-17
    老师你好,请问一下write back策略为什么读请求时是“如果缓存不是脏的,则由缓存组件将后端存储中的数据加载到缓存中”,而不是直接返回?,这里您说: 否则缓存块就可能永远是脏的了。
    对此表示疑惑,既然不是脏数据,难道不是直接返回就好了?

    作者回复: write back策略其实不算数据库和mc之间的策略,而是计算机体系结构中的策略,比如磁盘文件的缓存。它的完整读策略是这样的:如果缓存命中,则直接返回;如果缓存不命中,则重新找一个缓存块儿,如果这个缓存块儿是脏的,那么写入后端存储,并且把后端存储中的数据加载到缓存中;如果不是脏的,那么就把后端存储中的数据加载到缓存,然后标记缓存非脏。
    是我的讲述不太清晰,感谢你的提问

    
     1
  • Keith
    2019-10-17
    你好, 关于Write Back策略:
    1. Write Back只是说明写的策略, 没有说明读的策略吧?
    2. 关于"我们在读到缓存数据后,...,如果缓存不是脏的,则由缓存组件将后端存储中的数据加载到缓存中,最后我们将缓存设置为不是脏的,返回数据就好了。", 如果遇到连续的读操作, 缓存中的数据一直都是"不是脏的", 并且每次读操作都要"由缓存组件将后端存储中的数据加载到缓存中", 这样不是增加了缓存与存储之间的读次数吗?

    作者回复: 1. 后面有写明
    2. 是的 但是读后会将缓存标记为不脏,在读多些少的场景下,不会增加很多

     3
     1
我们在线,来聊聊吧