深入了解MongoDB 分布式集群

在分布式应用系统中,mongodb 已经成为 NoSQL 经典数据库。要想很好的使用 mongodb,仅仅知道如何使用它是不够的。只有对其架构原理等有了充分认识,才能在实际运用中使其更好地服务于应用,遇到问题知道怎么处理,而不是抓瞎抹黑。这篇文章就带你进入 mongodb 集群的大门。

集群概览

mongodb 相关的进程分为三类:

  • mongo 进程 – 该进程是 mongodb 提供的 shell 客户端进程,通过该客户端可以发送命令并操作集群;
  • mongos 进程 – mongodb 的路由进程,负责与客户端连接,转发客户端请求到后端集群,对客户端屏蔽集群内部结构;
  • mongod 进程 – 提供数据读写的 mongodb 实例进程。

类比银行服务,mongo 进程相当于客户,mongos 进程是柜台服务员,mongod 进程是银行后台实际处理业务的人员或者流程。客户只需要和柜台服务员沟通,告知办什么业务,柜台服务员将业务转往后台,后台实际处理。

下图是 mongodb 集群的一般拓扑结构。

如图,mongodb 集群的节点分为三类:

  • mongos 路由节点:处理客户端的连接,扮演存取路由器的角色,将请求分发到正确的数据节点上,对客户端屏蔽分布式的概念;
  • config 配置节点:配置服务,保存数据结构的元数据,比如每个分片上的数据范围,数据块列表等。配置节点也是 mongod 进程,只是它存储的数据是集群相关的元数据;
  • shard 分片节点:数据存储节点,分片节点由若干个副本集组成,每个副本集存储部分全体数据,所有副本集的数据组成全体数据,而副本集内部节点存放相同的数据,做数据备份与高可用。

还是拿银行业务类比,当客户办理保单保存业务时,

  1. 柜台服务员接受客户的保单业务请求(mongos 路由节点接收客户端的操作请求);
  2. 柜台服务员查询文件目录系统查看该保单应该保存到哪个仓库(mongos 节点与 config 配置节点通信,查询相关操作数据在哪个分片节点);
  3. 知道哪个仓库后,柜台服务员将保单给仓库管理员,仓库管理员将保单放到指定仓库中(mongos 节点将请求发送给数据所在分片节点,分片节点进行读写处理)。

mongos 路由服务

mongos 服务类似网关,连接 mongodb 集群与应用程序,对外屏蔽 mongodb 内部结构,应用程序只需要将请求发送给 mongos,而无需关心集群内部副本分片等信息。

mongos 本身不保存数据与索引信息,它通过查询 config 配置服务来获取,所以可以考虑将 mongos 与应用程序部署在同一台服务器上,当服务器宕机时 mongos 也一起失效,防止出现 mongos 闲置。

mongos 节点也可以是单个节点,但为了高可用,一般部署多个节点。就像柜台服务员一样,可以有多个,相互之间没有主备关系,都可以独立处理业务。

需要注意的是,在开启分片的情况下,应用程序应该避免直接连接分片节点进行数据修改,因为这种情况下很可能造成数据不一致等严重后果,而是通过 mongos 节点来操作。

config 配置服务

config 配置节点本质也是一个副本集,副本集中存放集群的元数据,如各个分片上的数据块列表,数据范围,身份验证等信息。如下,可以看到数据库 config,数据库中集合保存了集群的重要元数据。

mongos> use config;
switched to db config
mongos> show collections;
changelog
chunks
collections
databases
lockpings
locks
migrations
mongos
shards
tags
transactions
version

一般情况下,用户不应该直接变更 config 的数据,否则很可能造成严重后果。

shard 分片服务

分布式存储要解决的是两个问题:

随着业务不断发展,数据量越来越大,单机存储受限于物理条件,必然要通过增加服务器来支持不断增大的数据。所以分布式下,不可能全部数据存储在一个节点上,必然是将数据划分,部分数据放到这个节点,另外部分数据放到另外的节点上。也就是数据的伸缩性。
考虑高可用。如果同一份数据只存在一个节点上,当这个节点发生异常时,数据不可用。这就要求分布式下同一份数据需要存储在多个节点上,以达高可用效果。
在 mongodb 集群中,数据的伸缩性通过分片集来实现,高可用通过副本集来实现。

如图,全部数据为1-6,将其划分为3部分,1-2为一个分片,3-4为一个分片,5-6为一个分片。每个分片存储在不同的节点上。而每个分片有3个副本,组成副本集,每个副本都是独立的 mongod 实例。

所以副本集是一个纵向概念,描述的是相同的数据存储在多个节点上;而分片是一个横向概念,描述的是全量数据被切成不同的片段,每个片段独立存储。这个片段就是分片,而分片通过副本集进行存储。

副本集

副本集包含三种角色:

  • 主节点(Primary)
  • 副节点(Secondary)
  • 仲裁节点(Arbiter)

一个副本集由一个主节点,多个副节点,0或多个仲裁节点组成。

主节点与副节点是数据节点。主节点提供数据的写操作,数据写到主节点后,会通过同步机制同步到副节点上。默认读操作也由主节点提供,但是可以手动设置 read preference,优先从副节点读取。

仲裁节点不是数据节点,不存储数据,也不提供读写操作。仲裁节点是作为投票者存在,当主节点异常需要进行切换时,仲裁节点有投票权,但没有被投票权。仲裁节点可以在资源有限的情况下,依然支持故障恢复。比如只有2个节点的硬盘资源,在这种情况下可以增加一个不占存储的仲裁节点,组成“一主一副一仲裁”的副本集架构,当主节点宕掉时,副节点能够自动切换。

节点间通过“心跳”进行沟通,以此知道彼此的状态。当主节点异常不可用时,从其他有被投票权的节点中投票选出一个升级为主节点,继续保持服务高可用。这里投票采取“大多数”原则,即需要多于总节点数一半的节点同意,才能被选举成主节点。也因此不建议采用偶数个节点组成副本集,因为偶数情况下,如果发生半数节点网络隔离,隔离的半数节点达不到“大多数”的要求,无法选举产生新的主节点。

通过 rs.status() 可以查看副本集,参考《教你快速搭建 mongodb 集群》

分片集

分片就是将全部数据根据一定规则划分成没有交集的数据子集,每个子集就是一个分片,不同分片存放在不同节点上。这里有几个问题:

  • 划分规则也就是分片策略是什么?
  • 分片数据是如何存放的?
  • 数据量越来越大,分片如何动态调整?

数据块 Chunk

chunk 由多个文档组成,一个分片中包含多个 chunk。chunk 是分片间数据迁移的最小单位。实际上,文档是通过分片策略计算出应该存储在哪个 chunk,而 chunk 存放在分片上。

如图,假设按照文档的 x 字段值来进行分片,根据不同取值范围存放在不同的数据块,如25-175在 chunk 3上。

把书比作 mongodb 中的文档,书柜比作数据块,房间比作分片。每本书根据一定规则放到某书柜上,房间中有很多书柜。当某个房间的书柜太多,就需要以书柜为单位,迁移到相对比较宽松的房间。

chunk 的大小默认为 64MB,也可以自定义。chunk 的存在有两个意义:

  • 当某个 chunk 超过大小时,会触发 chunk 分裂。
  • 当分片间的 chunk 数不均衡时,会触发 chunk 迁移。

chunk 迁移由 mongodb 的平衡器来操作,默认平衡器是开启的,是运行在后台的一个进程,也可以手动关闭。

可以通过下面命令来查看平衡器状态:

sh.getBalancerState()

chunk 的大小对集群的影响:

  • 比较小时,chunk 数比较多,数据分布比较均匀,但会引起频繁的数据块分裂与迁移;
  • 比较大时,chunk 数比较少,数据容易分散不均匀,迁移时网络传输量大。

所以要自定义数据块大小时,一定要考虑完备,否则将大大影响集群与应用程序的性能。

片键 Shard Key

mongodb 集群不会自动将数据进行分片,需要客户端告知 mongodb 哪些数据需要进行分片,分片的规则是什么。

某个数据库启用分片:

mongos> sh.enableSharding(<database>)

设置集合的分片规则:

mongos> sh.shardCollection(<database.collection>,<key>,<unique>,<options>)
# unique 与 options 为可选参数

例如,将数据库 mustone 开启分片,并设置库中 myuser 集合的文档根据 _id 字段的散列值来进行划分分片。

sh.enableSharding("mustone")
sh.shardCollection("mustone.myuser",{_id: "hashed"})

这里划分规则体现在 上, 定义了分片策略,分片策略由片键 Shard Key 与分片算法组成。片键就是文档的某一个字段,也可以是复合字段。分片算法分为两种:

  • 基于范围。如 设置为 id:1 表示基于字段 id 的升序进行分片,id:-1 表示基于字段 id 的倒序进行分片,字段 id 就是 shard key(片键)。当集合中文档为空时,设置分片后,会初始化单个 chunk,chunk 的范围为(-∞,+∞)。当不断往其中插入数据到达 chunk 大小上限后,会进行 chunk 分裂与必要迁移。
  • 基于hash。如上面的栗子, 设置为 _id:”hashed”,表示根据字段 _id 的哈希来分片,此时片键为 _id。初始化时会根据分片节点数初始化若干个 chunk,如3个分片节点会初始化6个 chunk,每个 shard 2个 chunk。

每个数据库会分配一个 primary shard,初始化的 chunk 或者没有开启分片的集合都默认放在这个 primary shard 上。

分片策略的选择至关重要,等数据量大了再更改分片策略将会很麻烦。分片策略的原则:

  1. 均匀分布原则。分片的目标就是让数据在各个分片上均匀分布,数据的存取压力也分解到各个分片上。比如以自增长的 id 升序为片键,会导致新数据永远都写在最后的 chunk 上,且 chunk 分裂与迁移也会落在该 chunk 所在分片上,造成该分片压力过大。
  2. 大基数原则。集合的片键可能包含的不同值的个数,称为基数。基数越大,数据就能划分得更细。基数越小,chunk 的个数就有限。比如性别,只有男女,如果作为片键,最多两个 chunk,等数据越来越大后,便无法横向扩展。
  3. 就近原则。尽可能让一次查询的数据分布在同一个 chunk 上,这样提升磁盘读取性能。避免毫无意义的随机片键,虽然分布均匀了,但每次查询都要跨多个 chunk 才能完成,效率低下。

需要说明的是,mongodb 分片集群虽然比较完备,但是存在一些限制,如备份相对困难,分片集合无法做关联查询等。所以要根据实际业务来评估,如果副本集已经够用了,不一定要进行分片存取。

以上就是深入了解MongoDB 分布式集群的详细内容,更多关于MongoDB 分布式集群的资料请关注我们其它相关文章!

(0)

相关推荐

  • mongodb3.4集群搭建实战之高可用的分片+副本集

    前言 最近因为工作的原因,在学习使用mongodb数据库,mongodb是最常用的nodql数据库,在数据库排名中已经上升到了前六.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置服务器等. 相关概念 先来看一张图: 从图中可以看到有四个组件:mongos.config server.shard.replica set. mongos,数据库集群请求的入口,

  • 详解MongoDB4.0构建分布式分片群集

    MongoDB分片简述 高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的 CPU 耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘 IO 上. MongoDB 分片是使用多个服务器存储数据的方法,以支持巨大的数据存储和对数据进行操作.分片技术可以满足 MongoDB 数据量大量增长的需求,当一台 MongoDB 服务器不足以存储海量数据或不足以提供可接受的读写吞吐量时,我们就可以通过在多台服务器上分割数据,使得数据库系统能存储和处理更多的数

  • 详解如何使用MongoDB+Springboot实现分布式ID的方法

    一.背景 如何实现分布式id,搜索相关的资料,一般会给出这几种方案: 使用数据库自增Id 使用reids的incr命令 使用UUID Twitter的snowflake算法 利用zookeeper生成唯一ID MongoDB的ObjectId 另外,在我通过爬取知乎用户id发现,知乎的用户id是32位的,初步断定知乎采用的是md5加密,然后全部转换成小写.至于如何爬取知乎用户信息,见我之前分享的文章.本文采取的技术方案采取的是mogoodb的objectId. 二.mongodb如何实现分布式I

  • python连接mongodb集群方法详解

    简单的测试用例 #!/usr/bin/python # -*- coding: UTF-8 -*- import time from pymongo import MongoClient # 连接单机 # single mongo # c = MongoClient(host="192.168.89.151", port=27017) # 连接集群 c = MongoClient('mongodb://192.168.89.151,192.168.89.152,192.168.89.1

  • 详解Java 连接MongoDB集群的几种方式

    先决条件 先运行mongodb肯定是必须的,然后导入以下包: import com.mongodb.MongoClient; import com.mongodb.MongoClientURI; import com.mongodb.ServerAddress; import com.mongodb.MongoCredential; import com.mongodb.MongoClientOptions; MongoClient MongoClient()实例表示到数据库的连接池; 你将只需

  • MongoDB的分片集群基本配置教程

    为何要分片 1.减少单机请求数,降低单机负载,提高总负载 2.减少单机的存储空间,提高总存空间. 常见的mongodb sharding 服务器架构 要构建一个 MongoDB Sharding Cluster,需要三种角色: 1.Shard Server 即存储实际数据的分片,每个Shard可以是一个mongod实例,也可以是一组mongod实例构成的Replication Set.为了实现每个Shard内部的auto-failover(自动故障切换),MongoDB官方建议每个Shard为一

  • mongodb 集群重构和释放磁盘空间实例详解

    MongoDB集群重构,释放磁盘空间 由于mongodb删除了一部分数据后,不会回收相应的磁盘空间,所以这里通过重建数据目录的方式释放磁盘空间. 一 实验环境 配置了一个副本集,该副本集由以下三个节点组成: 10.192.203.201:27017 PRIMARY 10.192.203.202:27017 SECONDARY 10.192.203.202:10001  ARBITER 二 实验步骤 2.1 模拟环境 use dba; for(var i=0;i<1000000;i++)db.c.

  • 深入了解MongoDB 分布式集群

    在分布式应用系统中,mongodb 已经成为 NoSQL 经典数据库.要想很好的使用 mongodb,仅仅知道如何使用它是不够的.只有对其架构原理等有了充分认识,才能在实际运用中使其更好地服务于应用,遇到问题知道怎么处理,而不是抓瞎抹黑.这篇文章就带你进入 mongodb 集群的大门. 集群概览 mongodb 相关的进程分为三类: mongo 进程 – 该进程是 mongodb 提供的 shell 客户端进程,通过该客户端可以发送命令并操作集群: mongos 进程 – mongodb 的路由

  • 分布式文档存储数据库之MongoDB分片集群的问题

    前文我们聊到了mongodb的副本集以及配置副本集,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13953598.html:今天我们来聊下mongodb的分片: 1.什么是分片?为什么要分片? 我们知道数据库服务器一般出现瓶颈是在磁盘io上,或者高并发网络io,又或者单台server的cpu.内存等等一系列原因:于是,为了解决这些瓶颈问题,我们就必须扩展服务器性能:通常扩展服务器有向上扩展和向外扩展:所谓向上扩展就是给服务器加更大的磁盘,使用更大更好的内

  • 详解使用docker搭建hadoop分布式集群

    使用Docker搭建部署Hadoop分布式集群 在网上找了很长时间都没有找到使用docker搭建hadoop分布式集群的文档,没办法,只能自己写一个了. 一:环境准备: 1:首先要有一个Centos7操作系统,可以在虚拟机中安装. 2:在centos7中安装docker,docker的版本为1.8.2 安装步骤如下: <1>安装制定版本的docker yum install -y docker-1.8.2-10.el7.centos <2>安装的时候可能会报错,需要删除这个依赖 r

  • 详解CentOS 6.5搭建Redis3.2.8单机分布式集群

    前言 最近在服务器上搭建了一套Redis3.0伪分布式集群,发现一个问题,就是Shell脚本编写能力和运维工具的重要性亟待提高. 集群环境安装 1.安装Redis $ cd /usr/local #安装目录 $ wget http://download.redis.io/releases/redis-3.2.8.tar.gz $ tar xzf redis-3.2.8.tar.gz $ mv redis-3.2.8/ redis $ cd redis $ make $ make install

  • Linux下Kafka分布式集群安装教程

    Kafka(http://kafka.apache.org/) 是由 LinkedIn 使用 Scala 编写的一个分布式消息系统,用作 LinkedIn 的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础,具有高水平扩展和高吞吐量.Spack.Elasticsearch 都支持与 Kafka 集成.下面看一下几种分布式开源消息队列系统的对比: Kafka 集群架构: 一般不建议直接使用 Kafka 自带的 Zookeeper 建立 zk 集群,这里我们使用独

  • MongoDB分片集群部署详解

     一.环境说明 1.我们prod环境MongoDB的集群架构是做的分片集群的部署,但是目前我们没有分片,即所有数据都在一个分片上,后期如果数量大,需要分配,集群随时可以分片,对业务方透明 2.各个角色的部署情况 角色 IP 端口 复制集名称 mongos 172.21.244.101,172.21.244.102,172.21.244.94 27000 无 config server 172.21.244.101,172.21.244.102,172.21.244.94 27100 repl_c

  • Python搭建Spark分布式集群环境

    前言 Apache Spark 是一个新兴的大数据处理通用引擎,提供了分布式的内存抽象.Spark 最大的特点就是快,可比 Hadoop MapReduce 的处理速度快 100 倍.本文没有使用一台电脑上构建多个虚拟机的方法来模拟集群,而是使用三台电脑来搭建一个小型分布式集群环境安装. 本教程采用Spark2.0以上版本(比如Spark2.0.2.Spark2.1.0等)搭建集群,同样适用于搭建Spark1.6.2集群. 安装Hadoop并搭建好Hadoop集群环境 Spark分布式集群的安装

  • Linux下ZooKeeper分布式集群安装教程

    ZooKeeper 就是动物园管理员的意思,它是用来管理 Hadoop(大象).Hive(蜜蜂).pig(小猪)的管理员,Apache Hbase.Apache Solr.Dubbo 都用到了 ZooKeeper,其实就是一个集群管理工具,是集群的入口.ZooKeeper 是一个分布式的.开源的程序协调服务,是 Hadoop 项目下的一个子项目.ZooKeeper 主要应用场景包括集群管理(主从管理.负载均衡.高可用的管理).配置文件的集中管理.分布式锁.注册中心等.实际项目中,为了保证高可用,

  • Centos7.3 RabbitMQ分布式集群搭建示例

    本文介绍了Centos7.3 RabbitMQ分布式集群搭建示例,分享给大家,具体如下: 注意事项 centos 7.x 关闭firewall 三台机器: 172.17.250.97 rabbiMQ01 172.17.250.98 rabbiMQ03 172.17.250.99 rabbiMQ02 配置 hosts 172.17.250.97 fz-rabbitMQ01 172.17.250.99 fz-rabbitMQ02 172.17.250.98 fz-rabbitMQ03 $ syste

  • ol7.7安装部署4节点hadoop 3.2.1分布式集群学习环境的详细教程

    准备4台虚拟机,安装好ol7.7,分配固定ip192.168.168.11 12 13 14,其中192.168.168.11作为master,其他3个作为slave,主节点也同时作为namenode的同时也是datanode,192.168.168.14作为datanode的同时也作为secondary namenodes 首先修改/etc/hostname将主机名改为master.slave1.slave2.slave3 然后修改/etc/hosts文件添加 192.168.168.11 m

随机推荐