MongoDB如何才能优雅且合理地设计?
Posted 读字节
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB如何才能优雅且合理地设计?相关的知识,希望对你有一定的参考价值。
最近刚入坑MongoDB,感觉比mysql扩展性更强,一张表可以存储特别复杂的字段,这点我非常喜欢,最近需要用MongoDB存储一篇文章的数据,文章的评论和回复的数据存储是个大问题,设计了好久感觉我设计的字段好复杂,还不太合理,请求各位大佬指点一二,希望能参考你们的设计方案。
MongoDB的嵌套与外联设计权衡
1.文章的评论和回复不要与博文文档放到一起嵌套,这样会导致文章集合过大,文档结构过于复杂。最关键是操作文档的各种行为太多,导致严重锁性能。让博文和评论回复通过外键关联。
2.让评论和回复形成独立的一个集合文档,回复作为评论文档的一级数组即可,形成两层结构,不要搞成无限嵌套回复的树形。回复在评论文档内是一个列表文档,回复通过回复者和被回复者,就确定评论内用户的回复关系。
MongoDB的嵌套要慎用,对于频繁变化和数量可能够大的情况,最好独立成集合,通过外键关联。对于更新频率低,数量小,例如字典等比较适合做成文档嵌套。
再举个药品供应商的例子:
例如:设计药品订单,如果业务上几乎所有订单下面都是几个或者二三十个药品,而且这些药品的名称等基本信息也不会轻易去变,那么订单文档的内嵌药品数组就没有问题,可以按照两种模式设计
(1)可以记录所有药品信息。这样应用层更容易查询;
(2)只记录药品ID列表,应用层多费点心做个二次查询。我认为都没有问题,关键是看更细节的设计权衡,例如存储量,极端情况下药品名称修改等等。
再例如说:药品供应商的模型设计,假如一个供应商下面可能有上千种甚至上万种需要供应的药品,这个时候,再让药品供应商的文档去内嵌药品供应清单就不合适了。就需要反范式设计了。在多的那头,也就是药品文档中加入供应商关键信息的内嵌字段。因为往往业务上药品的供应商总是数量有限的,而且供应商基本信息不会频繁变化。应用层就可以从药品文档上直接用供应商作为条件查询了。1.文章的评论和回复不要与博文文档放到一起嵌套,这样会导致文章集合过大,文档结构过于复杂。最关键是操作文档的各种行为太多,导致严重锁性能。让博文和评论回复通过外键关联。
MongoDB设计过程中可能会遇到的坑
虽然MongoDB的易用性已经是分布式数据库里面最舒服的了。但真实情况是,有些问题的存在只不过没有露出真面目而已。
首先从团队数据模型设计上的转变上说说,MongoDB是文档模型数据库,特别强调树形结构的设计,相当一部分的一对多关联关系,基本上在Mongo一个文档结构树就能体现了。但是大多数的工程师,至少当下来看,习惯的设计还是关系表的范式,这就和第一节所说的情况走向了另一个极端。
如果按照这种习惯去设计并发展下去,就会形成大量的琐碎集合,从而由于大量的外联操作,产生大量的锁竞争,开发也会陷入mongodb不擅长的集合间连接操作,极大降低性能。这会让运维陷入到另一个泥潭当中。
其次就是这种数据类型的模式演化了。文档型无论mongodb也好,elasticsearch也好,它们与传统关系型数据库最直接的不同,就是不强制预先定义字段类型,就可以提交数据,由数据库系统自动识别类型。修改类型的过程也非常方便,因为这是有利于应用系统的敏捷迭代开发。
但这一切都有一个前提条件,就是良好的工程管理能力和人员技能素质。若在一个项目混乱,团队更换不断,人员技能不熟的情况下,在数据可靠性压倒一切的情况下,这种模式只会带来更意想不到的坑,甚至问题错在哪里都找不到。若是这种混乱的环境,建议还是老老实实地用传统关系型数据库。
最后再想说的就是分布式CAP理论这个本质问题了,MongoDB比MySQL在主从复制上选项中就更复杂了。
MongoDB副本集下的CAP理解
例如:关系型数据库里面MySQL主从架构复制的异步模式下,满足可靠性,就不管一致性了;复制的半同步模式下,主节点至少还要等到集群中任意一个从节点的复制重放完成才算结束;复制的全同步那就是强一致性了。以前专门讲CAP的文章:CAP 理论常被解释为一种“三选二”定律,这是否是一种误解?说过MySQL的三种不同模式:异步、半同步和全同步,也简单提到了MongoDB的majority选项。
我们再具体看MongoDB的分布式CAP取决的因素:write-concern、read-concern、read-preference三个配置条件:
- write-concern为1,read-concern为local,read-preference为primary的情况下,那么就是读写都在主节点,自然是强一致性。基本属于单机操作,从节点相当于备份。
- write-concern为1,read-concern为local,read-preference为secondary的情况下,写在主节点,读在从节点,这个过程无法保证从节点实时能拿到最新的数据,但能保证可用性高,就和MySQL异步模式下的读写分离一个道理了。
- write-concern为1,read-concern为majority,这个majority的意思就是新数据被大多数的从节点都已经复制确认后才能被读取,这种情况下无论在主节点或在从节点读取数据,都有可能拿的不是最新的数据。这就是所谓的弱一致性。
- write-concern为majority,read-concern为majority,第一个majority的意思就是新数据被大多数的从节点都已经复制确认后写入才算数,第二个majorit的意思同上—新数据被大多数的从节点都已经复制确认后才能被读取。这种情况下read-preference是primary,也就是在主节点读取,一定最新数据,强一致性,可用性差;read-preference若是secondary,也就是在从节点读取,弱一致性,可用性高。
前往读字节创作中心——了解”读字节“更多创作内容
以上是关于MongoDB如何才能优雅且合理地设计?的主要内容,如果未能解决你的问题,请参考以下文章