Node.js 猫鼬填充缓存

Node.js 猫鼬填充缓存,node.js,mongoose,Node.js,Mongoose,我有许多不同的mongoose模式,它们通过id字符串相互引用 我正在使用redis缓存mongoose文档 例如,getUserid将返回以前缓存的用户对象(如果存在),否则它将调用mongoosefind 取而代之的是猫鼬的引用和填充,这会让人感觉更加美观 然而,据我所知,它只是find的语法糖,没有任何缓存层 主要问题 与缓存层相比,什么时候应该使用mongoose填充,使用mongoose的稳定高流量应用程序的最佳实践是什么 指导性次级问题 mongoose populate真的适合高流

我有许多不同的mongoose模式,它们通过id字符串相互引用

我正在使用redis缓存mongoose文档

例如,getUserid将返回以前缓存的用户对象(如果存在),否则它将调用mongoosefind

取而代之的是猫鼬的引用和填充,这会让人感觉更加美观

然而,据我所知,它只是find的语法糖,没有任何缓存层

主要问题

与缓存层相比,什么时候应该使用mongoose填充,使用mongoose的稳定高流量应用程序的最佳实践是什么

指导性次级问题

mongoose populate真的适合高流量应用程序吗? 使用“填充”而不是缓存文档有什么好处吗 我自己 缓存模型本身(例如使用redis)的性能是否可以忽略不计? 最佳做法是什么?大型应用程序公司使用什么 猫鼬怎么办? 您会混合填充mongoose引用和缓存层吗 取决于不同的用例,或者您会选择一个,然后 和它一致吗? 示例用例

下面是我的应用程序中的一个普通示例

我有3个集合:用户、应用程序、机构

用户对应用程序有引用 应用程序有一个指向Institute的引用 现在我:

正在从包含应用程序id的缓存层获取用户 正在从缓存层获取应用程序,该层包含institute_id 从缓存层获取数据 给定一个用户,从缓存层获取app和institute实际上是O1

然而,如果我选择纯猫鼬填充,它将需要额外的两个数据库查找调用-为应用程序,然后为研究所

我需要的应用程序和机构的每个认证请求填充到服务器的用户

当然还有更复杂的用例,但这是最常见的用例


我最简单的请求平均需要填充4个引用,而更复杂的请求可以填充更多引用。

以下是我对这两个请求的一些优缺点的理解

猫鼬繁殖的优点

没有针对缓存更简单基础结构的其他设置 它可以在多个级别进行深度填充 它可以从多个数据库中填充。 这是一个简单干净的语法 缓存和数据库之间不需要同步,因为它是唯一的真实来源。 猫鼬繁殖的缺点

数据库用于每个填充和查询,而不是服务器或缓存层。如果在同一实例上有大量写操作,那么如果需要重新计算索引或进行处理器密集型查询,这将影响某些写操作的性能。 依靠mongoose和MongoDB数据库的内部工作。 需要控制,因为深度填充可能无法控制多个级别。 缓存层的优点

可以是多级缓存。每个服务器和一个全局缓存都有一些。 使用缓存引擎的特定力。 将一些工作卸载到缓存,并可能卸载到数据库。 缓存层的缺点

需要在缓存和数据库之间同步状态 更多的基础设施。 如果您想要一个干净的抽象,就需要更多的代码 总的来说,要回答您的子问题, 1.在一些高流量应用程序中,对于无法缓存且需要实时或不经常执行的内容,填充可能很有用

使用“在缓存上填充”更简单、更少的infra、更少的代码、无需同步

根据我的经验,我会选择缓存,因为在大型数据库上缓存会更快。当扩展数据库时,往往需要更多的cpu和成本。另一方面,缓存更便宜,而且可以很好地扩展。此外,还可以对每个实例进行缓存。i、 e.我的服务器在命中远程缓存之前有一个本地缓存。这使得性能非常快,但它可能会影响服务器性能,具体取决于主机

我不在大公司,但我们的产品需要事务性信息和固定状态。“填充”可以用于这种情况,因为数据库是唯一的真相来源,我们不希望状态不正确。由于我们的数据库的复制,它不是一个单一的源,但至少我们会接近数据库。我们在其他任何地方都使用缓存。我们有多个数据库和多个数据库类型,缓存为我们提供了更高的性能。我们的面向微服务的体系结构也从缓存中受益匪浅,并确保数据不都在同一个数据库中,但仍然可以快速访问

是的,混合是一个很好的选择,这取决于用例。一般提示是了解潜在的热点,并尝试分散工作负载,以确保基础架构的一部分不是瓶颈

最后提示:如果有疑问,请确保在数据层和代码层之间保持代码接口。如果需要使用ElasticSearch而不是Redis或任何其他缓存服务,则此抽象非常有用。代码接口将被删除 我们必须做出承诺

示例:不是在代码段中直接使用App.populate,而是在模式中添加一个方法getFullApp,该方法调用this.populate


如果你想摆脱填充,只有一个地方可以改变它或摆脱mongoose getFullApp是你的代码接口的功能。

取决于你如何制作你的模型:根据我的经验,我可以每秒向mongodb插入100000个文档,但我承认服务器有32 Gig的ram和8个线程4个核心。还可以根据业务逻辑定制_id字符串,这有助于按id获取文档,而不是按条件查询。例如:users collection:_id=someusername不在username字段上创建索引如果您想要最佳实践,最好共享您的模型架构和用例。这将有助于会员提供最佳解决方案。听起来很多,但它确实是一台强大的机器。在您的情况下,您是否使用“填充”?在我的业务逻辑中,我实际上对普通的旧的自动生成ID很满意。我在最初的问题中添加了一个简单的用例。这一切都取决于用例。关于您的用例:在任何情况下,您都在请求缓存层,所以问题来了,若缓存层不能保持高负载呢此外,按id获取文档比按某个字段获取文档要快,即使它已编制索引。复杂用例:我认为与其使用缓存层,不如使用弹性搜索,它将对更改做出反应,并准备好使用包含必要数据的搜索索引。我使用消息总线事件总线(message bus event bus)并通过收集和存储将所有关系数据集中在CouchBase中的数据集来对更改做出反应。在任何情况下,对db进行额外查询或对缓存进行第二次查询都不是什么大问题,如果是通过_id获取文档的话。请考虑在某个文件夹中打开一些名称类似于_id的文件。但对于复杂的用例,可以使用ElasticSearch或自己的工作人员来预取数据并将其放置在不同的位置以加快访问速度。另外,不要忘记放置适当的索引以提高查找速度,这可能会占用额外的存储空间

const AppSchema = new mongoose.Schema({...});

AppSchema.static({
   getFullApp(query) {
      return this.find(query).populate()
   }
})

module.exports = mongoose.model("App", AppSchema);