1、MongoDB数据库设计规范MongoDB数据库设计规范一、 MongoDB目前核心优势1. 灵活模式+ 高可用性 + 可扩展性2. 通过json文档来实现灵活模式3. 通过复制集来保证高可用4. 通过Sharded cluster来保证可扩展性二、 BSON1.在JSON中,要跳过一个文档进行数据读取,需要对此文档进行扫描才行,需要进行麻烦的数据结构匹配,遍历比较慢BSON针对JSON的一大改进就是将JSON的每一个元素的长度存在元素的头部,这样你只需要读取到元素长度就能直接seek到指定的点上进行读取了。2.MongoDB优化:(1) 由于内存与数据文件的映射(2) 在更新或者获取Docu
2、ment的某一个字段时,如果需要先读取其前面的所有字段,会导致物理内存由于读操作被加载到不必要的字段上,导致资源的不合理分配。(3) 而采用BSON只需要读到相应的位置然后跨过无用内容读取需要内容即可。3. MongoDB=JSON + IndexesMongoDB支持json格式的文档进行bson优化三、 和关系型数据库对比四、 参数参考五、 架构1.复制集和主从强烈建议使用副本集模式(哪怕是单机副本集)启用副本集在参数中添加:sharding: #configsvr or shardsvr clusterRole: shardsvr方便未来使之成为集群环境2. 集群(1) 分片适用场景a.
3、 服务器磁盘不够用b.单个mongod不能满足日益频繁写请求c.将大量数据存放于内存中提高性能比如,如下集合(2) 集群架构六、 Mongodb不适用场景 高度事务性系统,比如银行系统。传统的关系型数据库眼下还是更适用于大量原子性复杂事务的应用程序; 商业智能应用,针对特定问题BI,产生高度优化的查询方式,对于此类应用,数据仓库可能是更合适的选择; 复杂的跨表级联查询(多表join)。七、 MongoDB适用场景 非事务并且关联性集合不强的基本都可以使用 MongoDB4.0+支持了事务 MongoDB4.2版本支持集群事务 GridFS-文件存储:小文件和图片等八、 设计规范重点I.复制集的
4、读写设置 Read Preference 默认情况下,复制集的所有读请求都发到Primary,Driver可通过设置Read Preference来将读请求路由到其他的节点。 primary: 默认规则,所有读请求发到Primary primaryPreferred: Primary优先,如果Primary不可达,请求Secondary secondary: 所有的读请求都发到secondary secondaryPreferred:Secondary优先,当所有Secondary不可达时,请求Primary nearest:读请求发送到最近的可达节点上(通过ping探测得出最近的节点)II.
5、 统计分组函数优化1. 线上正式环境集合: props里有6000多万条数据目表:统计查询了解到他们的业务是昨天上线的,这个查询是处理一些错误的数据统计语句是:db.props.aggregate($group:_id:$extra.uc_event.batchId,count:$sum:1,$match:count:$gt:1)2.分析该语句可能出现的问题做统计分析,查询超过了mongodb限制的16M大小;mongo内存限制。 aggregate函数 使用$group时,数据大小必须小于16945KB该查询是全表扫描,然后进行分组排序操作执行如下查询:shard1:SECONDARY db
6、.props.aggregate($group:_id:$extra.uc_event.batchId,count:$sum:1,$match:count:$gt:1)assert: command failed: ok : 0,errmsg : Exceeded memory limit for $group, but didnt allow external sort.Pass allowDiskUse:true to opt in.,code : 16945 : aggregate failed_getErrorWithCodesrc/mongo/shell/utils.js:23:13
7、3.解决方法添加设置:allowDiskUse:true再次统计:db.props.aggregate($group:_id:$extra.uc_event.batchId,count:$sum:1,$match:count:$gt:1, allowDiskUse: true ) _id : null, count : 34655920 _id : 00028c13-1fce-487f-8c57-753a39dea94e, count : 2 _id : 000d4d9f-943b-47c1-9abd-0d17e9a66395, count : 2 _id : 000df209-8917-49
8、49-948d-296bf0664b19, count : 2 _id : 000e1931-da1a-43e2-92f2-12e813c93058, count : 3 4.优化建议统计batchId大于1的数据数据集合有6300万,总大小6G查询超过了mongodb限制的16M大小执行3分钟左右故可以限制扫描的行数,只扫描昨天到现在的数据即可(从业务上线到目前的错误数据),(1)查询:添加时间限制(2)查询使用allowDiskUse:true方法(3)在secondary库执行统计分析III. Mongodb的创建索引 需要和DBA沟通 在后台创建索引不影响业务正常的DML操作db.wo
9、rks.createIndex(plan:1,trgpoints:1,cOrder:1,sValue:1,background:true)IV. 删除字段、修改字段值等不清楚的和DBA沟通V. 库名全部小写,禁止使用任何_以外的特殊字符,比如我们线上lp-pmm数据库VI.集合名全部小写,禁止使用任何_以外的特殊字符VII.如果评估单集合数据量较大,比如8亿以上的集合,可以将一个大集合拆分为多个小集合,即mongodb的分库分表-sharding;VIII.MongoDB的集合拥有“自动清理过期数据”的功能 需在该集合中文档的时间字段增加一个TTL索引即可实现该功能 但需要注意的是该字段的类型
10、则必须是mongoDate() 一定要结合实际业务设计是否需要IX.文档设计 文档中的key禁止使用任何_以外的特殊字符 禁止使用_id,如:向_id中写入自定义内容X. 查询中的某些 $ 操作符可能会导致性能低下 $exist:因为松散的文档结构导致查询必须遍历每一个文档 $ne:如果当取反的值为大多数,则会扫描整个索引 $not:可能会导致查询优化器不知道应当使用哪个索引,所以会经常退化为全表扫描 $nin:全表扫描 $or:有多少个条件就会查询多少次,最后合并结果集,所以尽可能的使用 $inXI. 不要一次取出太多的数据进行排序 MongoDB 目前支持对32MB以内的结果集进行排序 如
11、果需要排序,那么请尽量限制结果集中的数据量九、 特别注意一十、 案例 mongodb-创建索引引发的血泪案例业务描述 需要在mongodb的集合timeline创建一个TTL索引31.5天后过期ttl索引shard1:PRIMARY db.timeline.count()482594935 业务定于的时间 (1)每天上午没有课,能进行创建和删除 (2)DBA建议在晚上12点后操作(业务没有采纳) (3)最终定于2018/5/19上午10点开始创建TTL索引 10点开始创建索引正在主库执行命令如下:db. timeline.createIndex(created: 1, name: idx_in
12、fos_created,expireAfterSeconds: 2721600,background:true)大约执行50%左右,业务要求停止创建索引,停止后,mongoDB索引会有重建功能,需要特殊处理说明:即使使用这种方式创建索引成功,会没有background : true创建后的索引查看db.infos.getIndexes() 停止创建索引操作(1)在每个secondary节点操作(2个secondary节点操作) mongod -f cumm.conf -shutdown停止 mongod -f cumm.conf noIndexBuildRetry 不重建索引 时间大概30s左
13、右完成 (2)在primary操作 kill创建索引线程 将primary shutdown 然后有一个secondary节点自动接管primary大概两个操作能控制在1分钟内(即影响业务时间)tips: 这样操作能有效避免发生重大业务问题 灾难再现(1)上面几个步骤做完之后,业务会正常DML和查询等操作(2)但是业务的程序有一个特点 a.java回放程序启动判断有没有索引,没有会自动重建 b.并且重建索引在是前台运行,阻塞所有查询和DML操作 建议(1)严格按照DBA给予规定的时间执行DDL(2)应用配置使用副本集模式(3)程序去掉自动检测索引是否存在而后进行重建 DDL操作不能再程序有(4
14、)我们这边会针对性的进行培训,有效避免这样的事情tips: 从这次故障中,梳理出了程序的配置弊端,有利于今后程序配置的良好性和正确性 正确的做法db. timeline.createIndex(created: 1, name: idx_infos_created,expireAfterSeconds: 2721600,background:true) #31.5天后过期rsvk:PRIMARY db.infos.count()31028907数据量少了1千多万MongoDB创建索引,只有两个大括号,否则就会有问题。一十一、 安全设计规范 在参数文件中添加security: keyFile:
15、/data/keyfile/key_file并且key_file是600权限,否则启动失败key_fike是一串字符 建议单库单用户例如: 创建educat数据库,并且创建访问educat数据库的用户educause educatdb.createUser( user: educa, pwd:“Hgq06#eR2wBg7e, roles: role: readWrite,db: educat )一十二、 综述综合上述案例和规范总结如下:o 线上业务一般不使用MapReduce(我们会在隐藏的secondary节点进行操作),使用aggreage进行处理;o 线上业务禁用不带条件的update、
16、remove或者find语句o 其中update语句一定使用$seto aggregate的第一层一定要使用$match,$group的成熟需不大于2层o db.book_rounds.aggregate($match: createdTime: $gte: new Date(2019-01-17), $lt: new Date(2019-01-18),$group:_id:userId:$userId,num_tutorial : $sum : 1, allowDiskUse: true )o 之前该业务没有使用$match,数据量、并发小是可以的,后面直接导致业务接口超时;o 查询只返回的字段o 文档设计-内嵌文档最多内嵌一层o 使用必要的用户验证登录
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1