MongoDB和Redis作为caching层架构

假设我们有一个社交networking应用(使用NodeJS,Express)和MongoDB作为主数据库引擎。

在大多数来自客户端(移动应用程序,Web应用程序等)的API调用中,我不想为每个请求进行复杂的查询。 例如,这些请求可以从caching层回复,例如Redis。

但我的问题是如何/何时应该更新caching层,因为所有写操作都在MongoDB数据库中执行,而不是caching层(Redis)。 解决这个问题的正确方法/架构是什么?

这真的取决于你的需求,但这是一个相当普遍的:

on_get_request if data_in_redis serve_data_from _redis else get_data_from_mongo set_data_in_redis set_expire_in_redis serve_data_from_memory 

数据有时会有点陈旧,但对大多数使用情况来说都没问题。 在写入重要数据时,它与caching失效结合起来效果很好:

 on_important_data delete_invalid_redis_keys 

但是,这一切都假定低写入,高读取和一组稳定的查询。

你的高负载用例是什么样的?

这已经在MongoDB 开源项目的名为“Socialite”的参考架构中实现,虽然它是Java而不是node.js,所以我的答案是基于我的经验压力和负载testing代码。

正如您从status feed的实现中看到的那样, feed有fanoutOnWritecaching选项 ,它将为活动用户创build一个caching(有限大小的文档) ,限制caching文档中最新条目的数量(该数字是可configuration的)。

实现的关键原则是内容需求实际上与时间线caching要求不同,写入内容数据库首先是所有内容的logging系统,然后更新caching(如果存在)。 如果需要,这部分可以asynchronous完成 。 更新使用“封顶arrays”又名更新$切片function,以primefaces方式将新值/内容推入arrays,同时closures最旧的一个。

如果用户不存在,则不要为用户创buildcaching(如果他们从未login,那么就是在浪费时间)。 或者,您可以根据某个TTL参数使caching过期。

当用户在login时读取caching并且不在那里时,再回到“fanoutOnRead”(查询所有用户的内容),然后从caching中取出caching。

Socialite项目在后台使用了MongoDB,但是在对它进行基准testing时,我们发现时间线caching不需要被复制或保存,因此它的MongoDB服务器只被configuration为“在内存中”(没有日志,没有复制,没有磁盘冲洗),这是类似于你的Redis使用。 如果你失去了caching,它将只是从永久内容数据库“按需”重build。

Idel方法是回写caching方式。 你可以先写mongodb然后写入redis。 这是最常见的方式。

另一个select是,你可以先写redis,然后用redis发送asynchronous消息(比如Q),某些线程可以使用消息并读取,写入mongoDB。

第一个选项更容易实现。 第二个选项可以支持大量的写入事务。 据我所知,mongodblocking问题还没有解决(它已经从全局locking到db级别locking)第二个选项可以相当大的减less这种locking争夺。

由于你的问题是关于build筑,并开始于“假设…”

任何selectmongoDB的理由?

有了Postgres,我得到了比mongoDB更好的性能,以及具有Postgres json / jsonb支持的关系和无模式文档的最好性能,这实际上比mongoDB更快。 有了Postgres,你可以得到一个可靠的战斗强化数据库,它具有出色的性能,可扩展性,最重要的是,你可以在晚上睡觉,享受你的假期。

你也可以使用postgres LISTEN / NOTIFY来处理实时事件,这样你就可以执行rediscaching清除。

这是一个在nodejs中使用postgres LISTEN / NOTIFY的例子: http ://gonzalo123.com/2011/05/23/real-time-notifications-part-ii-now-with-node-js-and-socket-io /

下面是Postgres 9.4作为一个无模式/ noSQL文档存储与mongoDB的综合性能基准:

http://thebuild.com/presentations/pg-as-nosql-pgday-fosdem-2013.pdf

这需要一些严重的数据抽取,以使Redis成为MongoDBcaching层的一个可行选项,同时要记住,MongoDB本身有一个工作集在RAM中; 因为如果你知道自己在做什么并且正确计划你的模式,这两者实际上可以从内存中提供服务

通常转向Redis进行caching是像craigslist( http://www.slideshare.net/jzawodn/living-with-sql-and-nosql-at-craigslist-a-pragmatic-approach )这样的大型网站的目标,正如您可以在幻灯片的幻灯片7中看到的那样使用它:

  • 计数器
  • 斑点
  • 队列

还有更多,但是如果MongoDB是他们的主存储而不是MySQL的话,你可以很容易地看到他们的memcached安装如何也可以和它合并来包含某些post。

因此,演示本身可以让您了解其他人如何在MongoDB中使用Redis。

基本上,它通常用来保存数据的快照,通常来自数据库的速度太慢。

下面是一些相关的信息,我会用它来回答一下: 什么是Redis,我用它做什么? 。 我强烈build议你阅读这个问题,因为它可以让你更清楚地知道Redis的用途以及它可以做什么。

你需要交易和实时写吗? 当有人在mongo上写入更新时,是否需要立即通知客户更改(1秒/分钟/天)?

你的数据真的很重要,任何写不应该丢失? 如果是的话,除了使用AOF(这不是redis的默认模式,速度要慢得多),你不能在redis上写。 mongo和redis之间的交易不会那么容易实现。

如果你先用redis编写,你可以使用发布/订阅来通知订阅了更新mongo值的redis客户端,但是不能保证你的数据是安全的传输的,应该被警告! 但是,这应该是更新所有连接到redis的客户端的最快/最高性能的方式。

另一种方法是,你可以在redis和mongo之间实时地定义一个可接受的轮询时间间隔,用mongo到redis的变化(去耦)来更新caching,而不需要直接从你的代码写入redis。 您可以使用监听器(mongo中的“触发器”)来执行此操作,或使用脏检查。

最后,有些人已经从mongo + redis迁移到了像viber这样的couchbase,也许你应该考虑这个选项? http://www.couchbase.com/viber