MongoDB 开发规范
(1)命名原则。数据库、集合命名需要简单易懂,数据库名使用小写字符,集合名称使用统一命名风格,可以统一大小写或使用驼峰式命名。数据库名和集合名称均不能超过 64 个字符。
(2)集合设计。对少量数据的包含关系,使用嵌套模式有利于读性能和保证原子性的写入。对于复杂的关联关系,以及后期可能发生演进变化的情况,建议使用引用模式。
(3)文档设计。避免使用大文档,MongoDB 的文档最大不能超过 16MB。如果使用了内嵌的数组对象或子文档,应该保证内嵌数据不会无限制地增长。在文档结构上,尽可能减少字段名的长度,MongoDB 会保存文档中的字段名,因此字段名称会影响整个集合的大小以及内存的需求。一般建议将字段名称控制在 32 个字符以内。
(4)索引设计。在必要时使用索引加速查询。避免建立过多的索引,单个集合建议不超过10个索引。MongoDB 对集合的写入操作很可能也会触发索引的写入,从而触发更多的 I/O 操作。无效的索引会导致内存空间的浪费,因此有必要对索引进行审视,及时清理不使用或不合理的索引。遵循索引优化原则,如覆盖索引、优先前缀匹配等,使用 explain 命令分析索引性能。
(5)分片设计。对可能出现快速增长或读写压力较大的业务表考虑分片。分片键的设计满足均衡分布的目标,业务上尽量避免广播查询。应尽早确定分片策略,最好在集合达到 256GB 之前就进行分片。如果集合中存在唯一性索引,则应该确保该索引覆盖分片键,避免冲突。为了降低风险,单个分片的数据集合大小建议不超过 2TB。
(6)升级设计。应用上需支持对旧版本数据的兼容性,在添加唯一性约束索引之前,对数据表进行检查并及时清理冗余的数据。新增、修改数据库对象等操作需要经过评审,并保持对数据字典进行更新。
(7)考虑数据老化问题,要及时清理无效、过期的数据,优先考虑为系统日志、历史数据表添加合理的老化策略。
(8)数据一致性方面,非关键业务使用默认的WriteConcern:1
(更高性能写入);对于关键业务类,使用WriteConcern:majority
保证一致性(性能下降)。如果业务上严格不允许脏读,则使用ReadConcern:majority
选项。
(9)使用 update、findAndModify 对数据进行修改时,如果设置了upsert:true
,则必须使用唯一性索引避免产生重复数据。
(10)业务上尽量避免短连接,使用官方最新驱动的连接池实现,控制客户端连接池的大小,最大值建议不超过200。
(11)对大量数据写入使用 Bulk Write 批量化 API,建议使用无序批次更新。
(12)优先使用单文档事务保证原子性,如果需要使用多文档事务,则必须保证事务尽可能小,一个事务的执行时间最长不能超过 60s。
(13)在条件允许的情况下,利用读写分离降低主节点压力。对于一些统计分析类的查询操作,可优先从节点上执行。
(14)考虑业务数据的隔离,例如将配置数据、历史数据存放到不同的数据库中。微服务之间使用单独的数据库,尽量避免跨库访问。
(15)维护数据字典文档并保持更新,提前按不同的业务进行数据容量的规划。
MongoDB 数据建模案例分析
朋友圈评论内容管理
需求
社交类的 APP 需求,一般都会引入“朋友圈”功能,这个产品特性有一个非常重要的功能就是评论体系。
先整理下需求:
这个 APP 希望点赞和评论信息都要包含头像信息:
a. 点赞列表,点赞用户的昵称,头像;
b. 评论列表,评论用户的昵称,头像;
数据查询则相对简单:
a. 根据分享 ID,批量的查询出 10 条分享里的所有评论内容;
建模
不好的设计
跟据上面的内容,先来一个非常非常"朴素"的设计:
{
"_id": 41,
"username": "小白",
"uid": "100000",
"headurl": "http://xxx.yyy.cnd.com/123456ABCDE",
"praise_list": [
"100010",
"100011",
"100012"
],
"praise_ref_obj": {
"100010": {
"username": "小一",
"headurl": "http://xxx.yyy.cnd.com/8087041AAA",
"uid": "100010"
},
"100011": {
"username": "mayun",
"headurl": "http://xxx.yyy.cnd.com/8087041AAB",
"uid"