[我一直在花时间研究缓存(主要是redis和memcached),并且在弄清楚数据不断变化时很难弄清楚到底在哪里使用缓存。
以Twitter为例(只需阅读Making Twitter 10000% faster)。当大量数据库记录不断变化时,您(或他们)将如何缓存其数据?
说Twitter具有以下模型:User
,Tweet
,Follow
,Favorite
。
[某人可能会发布一条推文,一天发送一次,而一天转发一千遍。对于该1000倍的转发,由于一天大约需要24 * 60 == 1440
分钟,这意味着该推文几乎每分钟都会更新一次(例如,它也获得了440个收藏夹)。跟追随某人一样,查理·辛甚至吸引了1 million Twitter followers in 1 day。在这些情况下似乎不值得缓存,但这可能只是因为我尚未达到该级别。
还要说,一般的Twitter关注者每天至少要发一次推文/关注/收藏。这意味着在幼稚的Intro-rails模式情况下,用户表每天至少更新一次(tweet_count
等)。这种情况对于缓存用户配置文件是有意义的。
但是对于上面的1000x Tweets和1M追随者示例,在缓存数据时推荐的做法是什么?
特别(假设使用memcached或redis,并使用纯JSON API(无页面/片段缓存):]
20
的redis列表?]我不了解的是,数据更改量与应缓存数据(并处理缓存过期带来的复杂性)之比。似乎Twitter可能在缓存不同的用户tweet提要,而首页tweets 每个用户,但是每当一个收藏夹/ tweet / reweets都使缓存无效时,意味着更新所有这些缓存项(可能还有缓存列表)记录),这在某些时候似乎意味着使缓存无效会产生相反的效果。
建议对这种变化很大的数据进行缓存的策略是什么?
Event Sourcing。 (http://martinfowler.com/bliki/CQRS.html + http://martinfowler.com/eaaDev/EventSourcing.html)。
[基本上:读写在应用程序上与持久性级别(CQRS)完全分开,并且对系统的每次写入都作为可订阅的事件进行处理(事件源)。还有更多功能(例如能够重播整个事件流,这对于以后实现新功能非常有用),但这是相关的部分。 [在此之后,通常的做法是,每当负责人Read Model
(即,将事件投影到新的读取模型)接收到新的事件时,都重新创建Projector
(认为是内存中的缓存)。订阅的事件类型。 在这种情况下,一个事件可能是TweetHandled,将由所有订户处理,其中RecentTweetsPerUserProjector
,TimelinePerUserProjector
等将更新其各自的ReadModel。
结果是ReadModels的集合,这些集合最终是一致的,不需要任何无效,即:更新的写入和结果事件是更新ReadModels的触发器。
我同意,最后,Charlie Sheen的读取模型将得到大量更新(尽管此更新可能非常有效),因此缓存优势可能非常低。但是,查看普通用户每个时间单位的平均发帖情况,情况就完全不同了。
DDD / CQRS /事件外包领域中的一些有影响力的人:Greg Young,Udi Dahan。
这些概念相当'深刻',所以不要指望在一小时内完全掌握它(至少我没有)。也许最近有关概念的思维导图也很有用:http://www.mindmeister.com/de/181195534/cqrs-ddd-links
是的,如果您还没有注意到的话,我对此非常热情:)
在我的项目中,我定期将50万条记录加载到已排序的集,然后仅通过对它们进行范围查询来运行统计报告,这使报告的执行时间平均不到2秒。