得物技术教你秒懂mongoDB之分片集群

背景

随着公司直播平台的全面开放,加上直播玩法的多样升级,最明显的感受就是:

① 数据增量明显。

② 并发量明显变大。

应对这两种变化,作为后端开发就需要在技术选型方面做一些选择。当前直播量大的业务都是利用mysql进行了分表处理。但是观察一段时间下来发现以下几个问题:

① 部分业务的分表上存储的数据量不是很均衡,会存在一些大主播对应的分表数据量明显偏大。

② 上新业务或者一些新活动就要建几十张表以提前应对已知的数据量,操作繁琐且后续变更不方便。

所以在做技术选型的时候就联想到了mongoDB的分片集群。下面我们来一探究竟:

一、回忆一下MongoDB的特点

1 灵活的模型

区别于关系数据库最大的一个特点就是字段灵活变更,这就非常适合一些迭代频繁且数据模型多变的业务场景。例如我们直播的活动业务场景,当前直播活动越来越多,玩的花样也是越来越多,其实就很适合用mongoDB来做活动业务的数据存储。

2 json数据格式

mongoDB的数据存储都是json格式,非常适合微服务Restful Api。

3 横向扩展能力

与mysql的分库分表不同,它可以在业务代码不变更的情况下做自动水平扩展。能够很好的解决上文描述的两个场景
① 分表数据不均匀
② 分表数据过大要调整原有数据分布。

二、说一说MongoDB的分片集群的原理和机制

在正式描述分片集群之前,我们先看一下当前MongoDB的架构部署方式如下图:

image.png

从上图我们可以很清晰的看到常用的架构模式氛围三种:
1、单机版:只用于开发和测试环境,没有高可用。
2、复制集:一般是一主二从,当然也可以配置更多从库。大部分用户的生产环境在使用,能够满足绝大多数业务场景,且是高可用。
3、分片集群:满足横向扩展能力且高可用。

分片的组成部分

如下图所示:

image.png

我们把上图分为四个模块来讲:

1. 应用程序+驱动程序

2. 路由节点(mongos)

路由节点主要是用来控制分发到哪一个分区(shard),因为mongos他存储有一个映射表。这个映射表的数据就是config节点存储的映射数据同步过来的。一般是在mongo启动的时候load到mongos的内存。

从上图可以看到mongos有多个,其实这也是为了满足高可用的场景。

3. 配置节点(config)

数据节点主要存储了集群元数据的存储,数据分布映射关系表。

存储的数据表格式如下图展示:

image.png

4. 数据节点(shard)

上图最下面的区域就是分片的数据节点,每一个分片都满足高可用,一般都是一主二从。分片的个数最大可以到1024个。所有分片合到一起就是完整的数据。不存在重复数据。

到此我们对分片集群的组成部分大概描述完了。

你会不会有这样的疑问?

  1. 配置表里存的数据分布范围是怎么定的?
  2. mongoDB的分片集群到底是怎么做数据均衡的?

如果你有其他疑问可以在文末给我留言,在回答上面问题前我先解释几个概念,我们看下图

image.png

如图所示我们可以看到以下几个名词,分表是集群>片>块>文档。

一个集群是由多个分片组成,一个分片存储了多个块(备注:逻辑上的数据分块),一个块包含多个文档。文档不是最小单位,文档里存着一个个字段,一个字段或者多个字段可以组成为一个片键。

片键有什么用?片键决定了你的数据可以分成多少块。

到此基础概念介绍完了,我来回答一下上面的疑问。

关于数据分布,mongoDB提供了三种方式

a. 基于范围

image.png

如图所示,数据在逻辑上被分成了4个块:举个例子你的系统存的是公司用户信息,如果你按年龄来分,假设公司年龄段在18-60,且按一个年龄分一个块,那么最大可以分43个块。再把块分到多个分片上去。这时我们查询某一个年龄段的数据,比如22-25之间的数据,一般很大可能是在同一个片或者两个片上。故而在范围查询性能上表现较好。那么问题来了,这时我们把数据无限放大,公司年龄在22-25之间的占比80以上,这时我们会发现22-25岁的用户数据所在的片和别的片比起来就很显得特别大,这也就是我们说的数据分布不均衡的情况。新增数据都是在22-25岁之间,这时也就导致了热点片的情况。

b. 基于hash

image.png

如上图所示,片键不是连续的而是通过hash散列到不同的片区,这就很好的解决了数据不均匀的情况。但是同时带来的问题就是,范围查询的场景效率特别低,需要遍历全部的分片才能满足业务查询。举个例子用户的订单系统,我们按照下单用户id去做hash,这样不同用户的订单数据就会被均匀的分布到不同的分片。单查某个用户的订单数据是非常高效的,但是如果去根据时间范围去查则要去扫描全部分片。

c. 基于zone

image.png

顾名思义,基于地域去划分。有时候我们服务的可能是全球用户,又因其地域性则可以天然的按地域去划分分片。这样很好的保证,在某固定地域可以访问到最近的数据节点。

到此对于上文中的第一个疑问是否豁然开朗?下面我们再来回答第二个问题:

简单来说,mongo他提供了两个程序:

① 切割器

切割器可以对某个源分片的数据按chunk(数据逻辑块)去做切割。

② 平衡器

当某些分片数据不均匀的情况下,平衡器就发挥作用了,他会发出一个命令让切割器去需要移动的分片上去做数据切割,再把数据移动到数据少的分片上。具体的步骤如下:

  • 平衡器向源分片发送moveChunk的命令
  • 源分片收到命令后,会启动自己内部的一个moveChunk命令,如果在数据移动过程中有客户端发来读写请求的话,都会发送到源分片。(因为配置服务器上的元数据还没有改变)
  • 目标片开始向源分片请求将要移动的数据块的文档,准备拷贝文档数据。
  • 当目标分片接收到据块的最后一个文档后,目标分片会启动一个同步进程来检查,是否已经拷贝完全部的文档。
  • 当同步完成后,目标分片会连接配置服务器,更新元数据列表中数据块的地址。
  • 当目标分片完成元数据更新后,源分片就会删除原来的数据块.如果有新的数据块需要移动的话,可以继续进行移动。
  • 配置服务器会通知monogs进程更新自己的映射表。

到此我们对于上文的第二个问题,也做了较为详尽的描述。下面来归纳一下MongoDB的分片集群的特点:

  • 应用全透明,无特殊处理

对于开发很友好,不需要做改动,mongo架构部署变化不影响业务代码。

  • 数据自动均衡

再也不用担心某个分片过大的情况,但是这里要注意的是你的分块必须要做到不能太大,不然老天也帮不了你。因为太大的话,经常会出现移动失败的情况。

  • 动态扩容,无须下线

如果当前生产环境是mongo复制集的架构,可以在线上环境直接切到分片集群架构。如果你使用阿里云的mongoDb服务,阿里提供了两种方式:1全量切 2增量切(注意增量切是需要另外付费的)对于用户来说操作很方便。

三、说一说分片集群适用的场景

上面我们把分片集群的概念,包括组成,实现机制,特点都描述完了。我相信大家也对分片集群有了一个较为完整的认识。下面我们聊一聊哪些场景我们需要考虑使用分片集群呢?

1.数据容量日益增大,访问性能降低

2.新品上线异常火爆,如何支撑更多的并发用户

直播打榜活动如火如荼的举行,部分业务数据增量和并发也有明显上升,目前来看无需调整部署策略可以轻松应对,假设这个增量无限陡增,那么就可以考虑使用分片集群,以解决数据库性能瓶颈。

3.单库已有海量数据,出了故障如何快速恢复

这时候我们需要提前预判风险问题,不能等出了故障再考虑使用分片集群。海量数据(假设数据已达TB级别)去做数据恢复耗时很长。

4.地理分布

数据来源不同地域,可以考虑使用

四、在使用分片集群前需要考虑的问题

1、合理的架构,需要考虑以下几个问题

问题1:是否需要分片

这个就需要结合自己的业务场景和当前的架构部署情况去做甄别。可以结合上文提到的适用场景去对号入座。

问题2: 需要多少分片

这一般需要考虑三个维度

① 你预估的业务在未来一年或者某一段时间,存储总量来计算,一般经验之谈2TB一个分片

② 根据你业务的最大并发量来计算

③ 根据你的硬件设备条件去衡量

这可能更需要dba去做一个评估来决定。

问题3:数据分布规则

这是非常关键的一点,关于数据分布这个,如果你的数据分布不合理,直接导致你没办法横向扩展、查询效率低等等性能问题

2、使用正确的姿势

① 选择你需要分片的表

mongo的分片都是基于表的,这是一个大前提。只对需要做分片的表做分片。

② 选择正确的片键

上文我们已经说过片键的作用,片键直接决定了你数据的分块。下面我们着重对片键的选择来阐述什么才是正确的片键。

首先我们需要遵守以下几个准则:

基数要大!

为了基数要大?如果你的基础小,例如上文举的例子,按年龄来分段,那么你的数据分块最多分几十块,如果你的数据是10TB,那么你每一块就算平均分布每一块的数据就要几百GB,这么大的块,是很难移动的,直接导致均衡策略失效。

保证分布均匀

为什么要保证分布均匀,如果不均匀我们会出现什么情况?

a、导致热片产生 (可以回忆一下上文讲分片数据分布方式时候提的例子)

b、导致分片数据经常大小差异大,频繁进行数据均衡

要保证定向查询好

好的架构都是服务于业务的,如果你的某些查询业务比较多,你肯定不希望你每次查询都要遍历所有的分片吧。

所以我们需要尽可能让自己查询的数据落在同一个分片上。

3、我们通过两个业务场景来聊聊

① 商家订单系统

业务描述:假设平台每日下单量在百万级,不同商家需要经常统计不同周期的订单数据

针对这一业务场景,我们按照上面思考的步骤考虑一下?

思考步骤一:要不要用分片?

回答:可以使用,因为数据量非常大,而且查询统计很频繁。

思考步骤二:使用什么做片键最合适?

回答:结合选片键的准则,最佳为商家id和下单时间。如果只用商家id做片键,他的确满足基数够大,另外数据均匀也没问题,但是查询某段连续时间内的订单需要遍历所有的分片。所以要选择商家id和下单时间的组合片键,这样才能保证定向查询。

② 直播打赏记录

业务描述:  记录用户给主播打赏数据,,假设打赏记录日增百万,只存在查询近期数据

从业务描述来分析,这个日志的历史数据没有查询的必要其实我们可以对历史数据做归档处理。无需考虑使用分片集群。

四、小结

看完全文,我相信你们对于分片集群都有了一定的认识。在工作中针对某些业务场景希望能给你提供一个多的选择。最后我终结两点:

  1. 分片集群可以有效解决性能瓶颈及系统扩容问题
  2. 分片管理复杂,成本高,能不分片尽量不用

文/荣荣
关注得物技术,带你走向技术的云端

你可能感兴趣的:(集群,mongodb)