本系列文章翻译自《50 Tips and Tricks for MongoDB Developers》,暂时没有找到中文版,反正自己最近也在深入学习mongodb,所以正好拿来翻译一下。一方面加强自己学习的效果,另一方面让大家也一起来体验一下需要我们这些mongodb使用者需要注意的地方。
首先声明自己的英文水平不是太高,加之有些英文翻译成中文也找不到合适的词来表达,所以在文章中可能会出现英文原词,或者说有些地方的翻译会有些生硬,也就是说会出现直译的地方。翻译该书的主要目的是为大家学习探讨用的,如果有翻译不精准的地方,或者说有更加精准的翻译,还请大家指出,我会及时的更正的,在此先谢过各位了。
Tip#1.Duplicate data for speed,reference data for integrity
数据冗余是为了性能,引用数据是为了完整性。
被多个文档使用的数据,既可以直接嵌入文档,也可以在文档中引用数据。嵌入不一定就比引用好,反之,引用也不一定就比嵌入好。每一种都有自己的取舍,不论什么,你都应该选择适合你的应用程序的方式。
嵌入式的结构,可能会导致数据的不一致。假设你需要把图1.1中的fruit的值从苹果修改为鸭梨,你刚修改完food集合中的fruit值,这时候你的应用崩溃了,其他地方的fruit的值还是旧的值,这时候你的应用中就同时存在两种不同的fruit值。
图1.1 嵌入式结构,fruit的值既存在于food集合,也存在于meals集合
不一致性也不是什么大问题,但“不是大问题”也是有级别的,这个级别依赖于你的用户需求。对于很多的应用,短时间内的不一致是可以接受的。假设一个用户修改了他的姓名,在几个小时内,他的旧帖子继续显示他的旧姓名,是可以接受的。如果是即使短时间的不一致性也不能接受的话,你就需要考虑使用引用式的结构了。
图1.2 引用式结构,fruit的值只存在于food集合,meals集合存储fruit的id
这需要权衡,你不能同时拥有最好的性能和确保及时的数据一致性。你必须决定哪一个对于你的应用来说更重要。
举个例子来说。
假设我们正在设计一个购物车的应用,设计在mongodb中存在订单信息,订单需要包含哪些信息呢?
引用式结构
a product:
{
"_id":productId,
"name":name,
"price":price
}
a order:
{
"_id":orderId,
"user":userInfo,
"items":[
productId1,
productId2
]
}
在订单的item项中存在每一个productid,当需要显示订单内容的时候,首先查询order集合,然后根据productid查询product集合来获取相应的产品名称,没有办法做到只用一次查询就可以获取完整的订单信息。
如果产品信息被更新,所有引用该产品的地方,都会显示新的产品信息。引用式的结构会拖慢读数据的速度,但是在多个订单会有很好的一致性,多个文档能实现原子的变化(只需要修改引用的文档的信息)。
嵌入式结构
a product:
{
"_id":productId,
"name":name,
"price":price
}
a order:
{
"_id":orderId,
"user":userInfo,
"items":[
{
"_id":productId1,
"name":name,
"price":price
},
{
"_id":productId2,
"name":name,
"price":price
}
]
}
将产品信息嵌入到订单信息中,当需要显示订单的时候,只需要执行一次查询即可。如果产品的信息发生变化,而且我们想要将变化传递给订单的话,我们需要更新多个独立的订单。
嵌入式结构加快了读取的速度,但是一致性会降低,产品信息不能被原子的在多个文档中被修改。
决定使用嵌入式结构还是使用引用式结构,可以参考下面的因素:
为很少发生变化的数据,每次都是再次读取,你是否愿意付出这样的代价?
你是愿意承担1000次读取带来的惩罚?大多数应用,读的压力要大于写的压力。这需要你仔细测试自己的比例。
你正在考虑的引用数据的变化频率如何?改变越少,越是赞成使用嵌入式的结构。引用很少改变的数据,例如名称,出生日期,存货标记和地址,是很不值的。
如果一致性很重要,你就应该使用引用式结构。例如,多个文档需要原子的查看数据的变化。如果我们正在设计一个交易系统,有价证券只能在特定的时间才可以进行交易,到达不可以进行交易的时间,我们需要立即锁定这些有价证券。这种事情在应用级别来操作可能更好,因为应用需要知道在什么时间锁定或者解锁。
在上面的这个订单应用中,一致性可能是有害的。假设我们想要给一个产品打折,20% off。我们不想更新已经存在的订单中的产品信息。这时候,我们需要的可能是一个快照,是下单时候的产品信息。
如果需要尽可能快的读取速度,我们应该使用嵌入式结构。实时系统应该更多的使用嵌入式结构。
上面的这个订单文档是一个很好的嵌入式结构的例子,改变产品信息的时候,我们不想改变订单的信息。在这里,引用式结构不能带给我们任何的好处。
在这个例子中,嵌入式结构是最佳的选择。
最后给大家一个地址,Your Coffee Shop Doesn't Use Two-Phase Commit,,里面的例子讲述了在真实的环境中,如何处理一致性问题,以及相关的系统改如何设计。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com