乐趣区

关于mongodb:MongoDB-在评论中台的实践

本文次要讲述 vivo 评论中台在数据库设计上的技术摸索和实际。

一、业务背景

随着公司业务倒退和用户规模的增多,很多我的项目都在打造本人的评论性能,而评论的业务状态根本相似。过后各我的项目都是各自设计实现,存在较多反复的工作量;并且不同业务之间数据存在孤岛,很难产生分割。因而咱们决定打造一款公司级的评论业务中台,为各业务方提供评论业务的疾速接入能力。在通过对各大支流 APP 评论业务的竞品剖析,咱们发现大部分评论的业务状态都具备评论、回复、二次回复、点赞等性能。

具体如下图所示:

波及到的外围业务概念有:

  • 【主题 topic】评论的主题,商城的商品、利用商店的 APP、社区的帖子
  • 【评论 comment】用户针对于主题发表的内容
  • 【回复 reply】用户针对于某条评论发表的内容,包含一级回复和二级回复

二、数据库存储的抉择

团队在数据库选型设计时,比照了多种支流的数据库,最终在  MySQL  和  MongoDB  两种存储之进行抉择。

因为评论业务的特殊性,它须要如下能力:

  • 【字段扩大】业务方不同评论模型存储的字段有肯定差别,须要反对动静的主动扩大。
  • 【海量数据】作为公司中台服务,数据量随着业务方的增多成倍增长,须要具备疾速便捷的程度扩大和迁徙能力。
  • 【高可用】作为中台产品,须要提供疾速和稳固的读写能力,可能读写拆散和主动复原。

而评论业务不波及用户资产,对事务的要求性不高。因而咱们选用了 MongoDB 集群 作为最底层的数据存储形式。

三、深刻理解 MongoDB

3.1 集群架构

因为单台机器存在磁盘 /IO/CPU 等各方面的瓶颈,因而以 MongoDB 提供集群形式的部署架构,如图所示:

次要由以下三个局部组成:

  • mongos:路由服务器,负责管理利用端的具体链接。利用端申请到 mongos 服务后,mongos 把具体的读写申请转发到对应的 shard 节点上执行。一个集群能够有 1~N 个 mongos 节点。
  • config:配置服务器,用于分存储分片汇合的元数据和配置信息,必须为 复制集(对于复制集概念戳我) 形式部署。mongos 通过 config 配置服务器合的元数据信息。
  • shard:用于存储汇合的分片数据的 mongod 服务,同样必须以 复制集 形式部署。

3.2  片键

MongoDB 数据是存在 collection(对应 MySQL 表)中。集群模式下,collection 依照 片键(shard key)拆分成多个区间,每个区间组成一个 chunk,依照规定散布在不同的 shard 中。并造成元数据注册到 config 服务中治理。

分片键只能在分片汇合创立时指定,指定后不能批改。分片键次要有两大类型:

  • hash 分片:通过 hash 算法进行散列,数据分布的更加均匀和扩散。反对单列和多列 hash。
  • 范畴分片:依照指定片键的值散布,间断的 key 往往散布在间断的区间,更加适用范围查问场景。单数据散列性由分片键自身保障。

3.3 评论中台的实际

3.3.1 集群的扩大

作为中台服务,对于不同的接入业务方,通过表隔离来辨别数据。以 comment 评论表举例,每个接入业务方都独自创立一张表,业务方 A 表为  comment_clientA,业务方 B 表为 comment_clientB,均在接入时创立表和相应索引信息。但只是这样设计存在几个问题:

  • 单个集群,不能满足局部业务数据物理隔离的须要。
  • 集群调优 (如 split 迁徙工夫) 很难业务个性差异化设置。
  • 程度扩容带来的单个业务方数据过于扩散问题。

因而咱们扩大了 MongoDB 的集群架构:

  1. 扩大后的评论 MongoDB 集群 减少了【逻辑集群】和【物理集群】的概念。一个业务方属于一个逻辑集群,一个物理集群蕴含多个逻辑集群。
  2. 减少了路由层设计,由利用负责扩大 Spring 的 MongoTemplate 和连接池治理,实现了业务到 MongoDB 集群之间的切换抉择服务。
  3. 不同的 MongoDB 分片集群,实现了物理隔离和差别调优的可能。

3.3.2 片键的抉择

MongoDB 集群中,一个汇合的数据部署是扩散在多个 shard 分片和 chunk 中的,而咱们心愿一个评论列表的查问最好只拜访到一个 shard 分片,因而确定了 范畴分片 的形式。

起初设置只应用单个 key 作为分片键,以 comment 评论表举例,次要字段有{“_id”: 惟一 id,”topicId”: 主题 id,”text”: 文本内容,”createDate”: 工夫} , 思考到一个主题 id 的评论尽可能间断散布,咱们设置的分片键为   topicId。随着性能测试的染指,咱们发现了有两个十分致命的问题:

  • jumbo chunk 问题
  • 惟一键问题

jumbo chunk:

官网文档中,MongoDB 中的 chunk 大小被限度在了 1M-1024M。分片键的值是 chunk 划分的惟一根据,在数据量继续写入超过 chunk size 设定值时,MongoDB 集群就会主动的进行决裂或迁徙。而对于同一个片键的写入是属于一个 chunk,无奈被决裂,就会造成  jumbo chunk 问题。

举例,若咱们设置 1024M 为一个 chunk 的大小,单个 document 5KB 计算,那么单个 chunk 可能存储 21W 左右 document。思考热点的主题评论(如微信评论),评论数可能达到 40W+,因而单个 chunk 很容易超过 1024M。超过最大 size 的 chunk 仍然可能提供读写服务,只是不会再进行决裂和迁徙,短暂以往会造成集群之间数据的不均衡.

惟一键问题:

MongoDB 集群的惟一键设置减少了限度,必须是蕴含分片键的;如果_id 不是分片键,_id 索引只能保障单个 shard 上的唯一性。

  • You cannot specify a unique constraint on a hashed index
  • For a to-be-sharded collection, you cannot shard the collection if the collection has other unique indexes
  • For an already-sharded collection, you cannot create unique indexes on other fields

因而咱们删除了数据和汇合,调整    topicId 和 _id 为联结分片键 从新创立了汇合。这样即突破了 chunk size 的限度,也解决了唯一性问题。

3.4 迁徙和扩容

随着数据的写入,当单个 chunk 中数据大小超过指定大小时(或 chunk 中的文件数量超过指定值)。MongoDB 集群会在插入或更新时,主动触发 chunk 的拆分。

拆分会导致汇合中的数据块散布不平均,在这种状况下,MongoDB balancer 组件会触发集群之间的数据块迁徙。balancer 组件是一个治理数据迁徙的后盾过程,如果各个 shard 分片之间的 chunk 数差别超过阈值,balancer 会进行主动的数据迁徙。

balancer 是能够在线对数据迁徙的,然而迁徙的过程中对于集群的负载会有较大影响。个别倡议能够通过如下设置,在业务低峰时进行(更多见官网)

db.settings.update({ _id: "balancer"},
{$set: { activeWindow : { start : "<start-time>", stop : "<stop-time>"} } },
{upsert: true}
)

MongoDB 的扩容也非常简单,只须要筹备好新的 shard 复制集后,在 Mongos 节点中执行:

sh.addShard("<replica_set>/<hostname><:port>")

扩容期间因为 chunk 的迁徙,同样会导致集群可用性升高,因而只能在业务低峰进行

四、写在最初

MongoDB 集群在评论中台我的项目中已上线运行了一年多,过程中实现了约 10 个业务方接入,承载了 1 亿 + 评论回复数据的存储,体现较为稳固。BSON 非结构化的数据,也撑持了咱们多个版本业务的疾速降级。而热门数据内存化存储引擎,较大的进步了数据读取的效率。

但对于 MongoDB 来说,集群化部署是一个不可逆的过程,集群化后也带来了索引,分片策略等较多的限度。因而个别业务在应用 MongoDB 时,正本集形式就能撑持 TB 级别的存储和查问,并非肯定须要应用集群化形式。

以上内容基于 MongoDB 4.0.9 版本个性,和最新版本的 MongoDB 细节上略有差别。

参考资料:https://docs.mongodb.com/manual/introduction/

作者:vivo 官网商城开发团队

退出移动版