我有许多通过id字符串互相引用的猫鼬模式。
我正在使用Redis缓存猫鼬文档。
例如,getUser(id)将返回先前缓存的用户对象(如果存在),否则将调用猫鼬查找。
取而代之的是猫鼬引用并使用填充。
但是,据我了解,它只是用于查找的语法糖,并且没有任何缓存层。
主要问题
何时应该使用猫鼬填充而不是缓存层?使用猫鼬在稳定的高流量应用程序中的最佳做法是什么?
指导性子问题
用例示例
这是我应用中的一个普通示例。
我有3个收藏集:用户,应用,研究所。
现在我是:
给用户一个信息,从缓存层获取应用程序并进行初始化实际上是O(1)。
但是,如果我选择填充纯猫鼬,则会对数据库进行2次额外的查找调用-对于应用程序,然后对于研究所。
我需要具有应用程序的用户,并在对服务器的每个经过身份验证的请求上填充研究所。
当然还有更复杂的用例,但这是最常见的用例。
我最简单的请求平均需要填充4个引用,而更复杂的请求可以填充更多引用。
答案 0 :(得分:1)
这是我对两者的利弊的理解。
猫鼬的优点
猫鼬的缺点
用于缓存图层的优点
缓存层的缺点
总体回答您的子问题, 1.对于某些流量较高的应用程序,“填充”可能有用,因为它们不能被缓存并且需要实时运行,或者不经常执行。
在缓存中使用填充更简单,更少的基础设施,更少的代码,没有同步。
根据我的经验,我会去缓存,因为在大型数据库上它会更快。扩展数据库时,往往需要更多的cpu并花费更多的钱。另一方面,缓存更便宜并且可以扩展。同样,可以按实例缓存。即,我的服务器在访问远程缓存之前具有本地缓存。这样可以使性能非常快,但是根据托管情况,可能会影响服务器性能。
我不是大公司,但是我们的产品需要交易信息和固定状态。在这种情况下可以使用填充,因为数据库是唯一的事实来源,而且我们不希望状态不正确。由于我们数据库的复制,它不是单一来源,但至少我们将接近数据库。我们在其他任何地方都使用缓存。我们有多个数据库和多个数据库类型,缓存使我们拥有更高的性能。我们的面向微服务的体系结构还从缓存中受益匪浅,并确保数据不是全部都在同一个数据库中,而是仍然可以快速访问。
是的,根据使用情况,混合是一个不错的选择。一个一般性的技巧是了解潜在的热点,并尝试分散工作量,以确保基础结构的一部分不会成为瓶颈。
最后的提示:毫无疑问,请确保在数据层和代码层之间保留代码接口。如果需要使用ElasticSearch代替Redis或任何其他缓存服务,则此抽象非常有用。代码界面将推迟作出承诺的需要。
示例:不是在一段代码中直接使用App.populate
,而是在您的模式中添加调用getFullApp()
的方法this.populate()
const AppSchema = new mongoose.Schema({...});
AppSchema.static({
getFullApp(query) {
return this.find(query).populate()
}
})
module.exports = mongoose.model("App", AppSchema);
如果要摆脱填充,只有一个地方可以更改它或摆脱猫鼬getFullApp
是您的代码接口的功能。