MongoDB集群中,在,vivo,评论中台的实践

2021-03-04 08:25:21  来源:互联网  编辑:小狐  阅读人数:926

一、业务背景

MongoDB集群中,在,vivo,评论中台的实践(图1)

涉及到的核心业务概念有:

主题 topic 评论的主题,商城的商品、应用商店的 APP 、社区的帖子

评论 comment 用户针对于主题发表的内容

回复 reply 用户针对于某条评论发表的内容,包括一级回复和二级回复

二、数据库存储的选择

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

MongoDB集群中,在,vivo,评论中台的实践(图2)

由于评论业务的特殊性,它需要如下能力:

字段扩展 业务方不同评论模型存储的字段有一定差异,需要支持动态的自动扩展。

海量数据 作为公司中台服务,数据量随着业务方的增多成倍增长,需要具备快速便捷的水平扩展和迁移能力。

高可用 作为中台产品,需要快速和稳定的读写能力,能够读写分离和自动恢复。

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

三、深入了解 MongoDB

3.1 集群架构

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

MongoDB集群中,在,vivo,评论中台的实践(图3)

主要由以下三个部分组成:

shard: 用于存储集合的分片数据的mongod服务,同样必须以 复制集 方式部署。

3.2 片键

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

MongoDB集群中,在,vivo,评论中台的实践(图4)

分片键只能在分片集合创建时指定,指定后不能修改。分片键主要有两大类型:

hash分片: 通过hash算法进行散列,数据分布的更加平均和分散。支持单列和多列hash。

范围分片: 按照指定片键的值分布,连续的key往往分布在连续的区间,更加适用范围查询场景。单数据散列性由分片键本身保证。

3.3 评论中台的实践

3.3.1 集群的扩展

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

单个集群,不能满足部分业务数据物理隔离的需要。

集群调优(如split迁移时间)很难业务特性差异化设置。

水平扩容带来的单个业务方数据过于分散问题。

因此我们扩展了 MongoDB的集群架构:

MongoDB集群中,在,vivo,评论中台的实践(图5)

扩展后的评论MongoDB集群 增加了 【逻辑集群】和【物理集群】的概念。一个业务方属于一个逻辑集群,一个物理集群包含多个逻辑集群。

增加了路由层设计,由应用负责扩展Spring的MongoTemplate和连接池,实现了业务到MongoDB集群之间的切换选择服务。

不同的MongoDB分片集群,实现了物理隔离和差异调优的可能。

3.3.2 片键的选择

MongoDB集群中,一个集合的数据部署是分散在多个shard分片和chunk中的,而我们希望一个评论列表的查询最好只访问到一个shard分片,因此确定了 范围分片 的方式。

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 迁移和扩容

MongoDB集群中,在,vivo,评论中台的实践(图6)

拆分会导致集合中的数据块分布不均匀,在这种情况下,MongoDB balancer组件会触发集群之间的数据块迁移。balancer组件是一个数据迁移的后台进程,如果各个shard分片之间的chunk数差异超过阈值,balancer会进行自动的数据迁移。

MongoDB集群中,在,vivo,评论中台的实践(图7)

db.settings.update

{ _id: “balancer”}。

{ $set: { activeWindow : { start : stop : } } }。

{ upsert: true}

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

sh.addShard“ < replica_set>/ < hostname>< :port>”

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

四、写在最后

MongoDB集群在评论中台项目中已上线运行了一年多,过程中完成了约10个业务方接入,承载了1亿+评论回复数据的存储,表现较为稳定。BSON非结构化的数据,也支撑了我们多个版本业务的快速升级。而热门数据内存化存储引擎,较大的提高了数据读取的效率。

但对于MongoDB来说,集群化部署是一个不可逆的过程,集群化后也带来了索引,分片策略等较多的限制。因此一般业务在使用MongoDB时,副本集方式就能支撑TB级别的存储和查询,并非一定需要使用集群化方式。

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

参考资料:

点一下,代码无 Bug

本文相关词条概念解析:

集群

集群通信系统是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多。