MongoDB 分片集群架构中的分片策略

news2025/3/10 11:58:48

一、分片集群架构

1-1、分片简介

分片(shard)是指在将数据进行水平切分之后,将其存储到多个不同的服务器节点上的一种扩展方式。分片在概念上非常类似于应用开发中的“水平分表”。不同的点在于,MongoDB本身就自带了分片管理的能力,对于开发者来说可以做到开箱即用。

1-1-1、为什么要使用分片?

MongoDB复制集实现了数据的多副本复制及高可用,但是一个复制集能承载的容量和负载是有限的。在你遇到下面的场景时,就需要考虑使用分片了:

  • 存储容量需求超出单机的磁盘容量。
  • 活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能。
  • 写IOPS超出单个MongoDB节点的写服务能力。

垂直扩容(Scale Up) VS 水平扩容(Scale Out):

垂直扩容 : 用更好的服务器,提高 CPU 处理核数、内存数、带宽等

水平扩容 : 将任务分配到多台计算机上

1-1-2、MongoDB 分片集群架构

MongoDB 分片集群(Sharded Cluster)是对数据进行水平扩展的一种方式。MongoDB 使用 分片集群来支持大数据集和高吞吐量的业务场景。在分片模式下,存储不同的切片数据的节点被称为分片节点,一个分片集群内包含了多个分片节点。当然,除了分片节点,集群中还需要一些配置节点、路由节点,以保证分片机制的正常运作。

1-1-3、核心概念

  • 数据分片:分片用于存储真正的数据,并提供最终的数据读写访问。分片仅仅是一个逻辑的概念,它可以是一个单独的mongod实例,也可以是一个复制集。图中的Shard1、Shard2都是一个复制集分片。在生产环境中也一般会使用复制集的方式,这是为了防止数据节点出现单点故障。
  • 配置服务器(Config Server):配置服务器包含多个节点,并组成一个复制集结构,对应于图中的ConfigReplSet。配置复制集中保存了整个分片集群中的元数据,其中包含各个集合的分片策略,以及分片的路由表等。
  • 查询路由(mongos)mongos是分片集群的访问入口,其本身并不持久化数据。mongos启动后,会从配置服务器中加载元数据。之后mongos开始提供访问服务,并将用户的请求正确路由到对应的分片。在分片集群中可以部署多个mongos以分担客户端请求的压力。

1-2、分片策略使用分片集群

之前的文章有讲述分片集群搭建过程,# MongoDB分片集群的两种搭建方式及使用

通过分片功能,可以将一个非常大的集合分散存储到不同的分片上,如图:

假设这个集合大小是1TB,那么拆分到4个分片上之后,每个分片存储256GB的数据。这个当然是最理想化的场景,实质上很难做到如此绝对的平衡。一个集合在拆分后如何存储、读写,与该集合的分片策略设定是息息相关的。

1-2-1、使用分片集群

  • 首先连接mongos
mongo mongo03.com:27017
复制代码

  • 为了使集合支持分片,需要先开启database的分片功能(下面给集合shop开启分片功能)--必须要开启
sh.enableSharding("shop")
复制代码

  • 执行shardCollection命令,对集合执行分片初始化()
sh.shardCollection("shop.product",{productId:"hashed"},false,{numInitialChunks:4})
复制代码

shop.product集合将productId作为分片键,并采用了哈希分片策略,除此以外,“numInitialChunks:4”表示将初始化4个chunk。 numInitialChunks必须和哈希分片策略配合使用。而且,这个选项只能用于空的集合,如果已经存在数据则会返回错误。这个值可以为后面数据平衡迁移做计算,(我之前搭建分片集群有两个分片,这样就是每个分片有两个chunk)

  • 向分片集合写入数据(向shop.product集合写入一批数据)
db = db.getSiblingDB("shop");
var count = 0;
for (var i = 0; i < 1000; i++) {
    var p = [];
    for (var j = 0; j < 100; j++) {
        p.push({
            "productId": "P-" + i + "-" + j,
            name: "羊毛衫",
            tags: [{
                tagKey: "size",
                tagValue: ["L", "XL", "XXL"]
            },
            {
                tagKey: "color",
                tagValue: ["蓝色", "杏色"]
            },
            {
                tagKey: "style",
                tagValue: "韩风"
            }]
        });
    }
    count += p.length;
    db.product.insertMany(p);
    print("insert ", count)
}
复制代码
  • 查询数据的分布
db.product.getShardDistribution()
复制代码

可以看到product集合数据存储于shard1和shard2两个分片,同时也可以看到每个分片存储的数据大小、数量以及chunks数量。最后在总统计中可以看到总数据量,以及每个分片数据的占比

1-2-2、什么是chunk

chunk的意思是数据块,一个chunk代表了集合中的“一段数据”,例如,用户集合(db.users)在切分成多个chunk之后如图所示:

chunk所描述的是范围区间,例如,db.users使用了userId作为分片键,那么chunk就是userId的各个值(或哈希值)的连续区间。集群在操作分片集合时,会根据分片键找到对应的chunk,并向该chunk所在的分片发起操作请求,而chunk的分布在一定程度上会影响数据的读写路径,这由以下两点决定:

  • chunk的切分方式,决定如何找到数据所在的chunk
  • chunk的分布状态,决定如何找到chunk所在的分片

1-2-3、分片算法

chunk切分是根据分片策略进行实施的,分片策略的内容包括分片键和分片算法。当前,MongoDB支持两种分片算法:

1-2-3-1、范围分片(range sharding)

假设集合根据x字段来分片,x的完整取值范围为[minKey, maxKey](x为整数,这里的minKey、maxKey为整型的最小值和最大值),其将整个取值范围划分为多个chunk,例如:

  • chunk1包含x的取值在[minKey,-75)的所有文档。

  • chunk2包含x取值在[-75,25)之间的所有文档,依此类推。

范围分片能很好地满足范围查询的需求,比如想查询x的值在[-30,10]之间的所有文档,这时mongos直接将请求定位到chunk2所在的分片服务器,就能查询出所有符合条件的文档。范围分片的缺点在于,如果Shard Key有明显递增(或者递减)趋势,则新插入的文档会分布到同一个chunk,此时写压力会集中到一个节点,从而导致单点的性能瓶颈。一些常见的导致递增的Key如下:

  • 时间值。
  • ObjectId,自动生成的_id由时间、计数器组成。
  • UUID,包含系统时间、时钟序列。
  • 自增整数序列。

1-2-3-2、哈希分片(hash sharding)

哈希分片会先事先根据分片键计算出一个新的哈希值(64位整数),再根据哈希值按照范围分片的策略进行chunk的切分。适用于日志,物联网等高并发场景。

哈希分片与范围分片是互补的,由于哈希算法保证了随机性,所以文档可以更加离散地分布到多个chunk上,这避免了集中写问题。然而,在执行一些范围查询时,哈希分片并不是高效的。因为所有的范围查询都必然导致对所有chunk进行检索,如果集群有10个分片,那么mongos将需要对10个分片分发查询请求。哈希分片与范围分片的另一个区别是,哈希分片只能选择单个字段,而范围分片允许采用组合式的多字段作为分片键。

哈希分片仅支持单个字段的哈希分片:

{ x : "hashed" } 
{x : 1 , y : "hashed"} // 4.4 new
复制代码

4.4 以后的版本,可以将单个字段的哈希分片和一个到多个的范围分片键字段来进行组合,比如指定 x:1,y 是哈希的方式。

1-2-3-3、分片标签

MongoDB允许通过为分片添加标签(tag)的方式来控制数据分发。一个标签可以关联到多个分片区间(TagRange)。均衡器会优先考虑chunk是否正处于某个分片区间上(被完全包含),如果是则会将chunk迁移到分片区间所关联的分片,否则按一般情况处理。

分片标签适用于一些特定的场景。例如,集群中可能同时存在OLTP和OLAP处理,一些系统日志的重要性相对较低,而且主要以少量的统计分析为主。为了便于单独扩展,我们可能希望将日志与实时类的业务数据分开,此时就可以使用标签。

1-2-3-3-1、给分片添加标签

为了让分片拥有指定的标签,需执行addShardTag命令,通过如下指令就可以给shard1设置tag

sh.addShardTag("shard1","oltp")
复制代码

执行指令前使用sh.status()查看状态信息

执行给分片添加标签之后,shard1分片就多了tag属性,如下:

1-2-3-3-2、给集合设置分片标签

  • 首先创建一个集合,并且给集合设置分片的能力
use main
sh.enableSharding("main")
复制代码
  • 给集合设置分片hash的key
sh.shardCollection("main.devices",{i:'hashed'})
复制代码
  • 设置集合属于oltp属性,声明TagRange
# shardKey为分片键(后面进行详细说明)
# sh.addTagRange("main.devices",{shardKey:MinKey},{shardKey:MaxKey},"oltp")

sh.addTagRange("main.devices",{i:MinKey},{i:MaxKey},"oltp")
复制代码
  • 插入数据
for (var i = 0; i < 10000; i++) { 
  db.devices.insert({i: i}); 
}
复制代码
  • 最后在查询数据存储分片结果
db.devices.getShardDistribution()
复制代码

执行结果,可以看到数据都落到shard1上面了,我们就可以通过这种方式来设置让数据只落到某个分片上

1-2-3-4、分片键(ShardKey)的选择

在选择分片键时,需要根据业务的需求及范围分片、哈希分片的不同特点进行权衡。一般来说,在设计分片键时需要考虑的因素包括:

  • 分片键的基数(cardinality),取值基数越大越有利于扩展。
    • 以性别作为分片键 :数据最多被拆分为 2 份
    • 以月份作为分片键 :数据最多被拆分为 12 份
  • 分片键的取值分布应该尽可能均匀。
  • 业务读写模式,尽可能分散写压力,而读操作尽可能来自一个或少量的分片。
  • 分片键应该能适应大部分的业务操作。

分片键如果基数较小,这样会导致chunk的数据量过大的情况发生;每个chunk存储到64MB,就会向下再拆分,拆分为两个32MB的chunk,当这两个32MB的chunk存储到64MB的时候就无法再进行拆分,只能当前chunk进行自己存储。 这样在写入或者后面迁移的时候就有受到影响。

1-2-3-5、分片键(ShardKey)的约束

ShardKey 必须是一个索引。非空集合须在 ShardCollection 前创建索引;空集合 ShardCollection 自动创建索引

上面给main.devices中的i作为分片键(ShardKey)的时候,就会自动在devices中创建一个索引,如下:

4.4 版本之前:

  • ShardKey 大小不能超过 512 Bytes;
  • 仅支持单字段的哈希分片键;
  • Document 中必须包含 ShardKey;
  • ShardKey 包含的 Field 不可以修改。

4.4 版本之后:

  • ShardKey 大小无限制;
  • 支持复合哈希分片键;
  • Document 中可以不包含 ShardKey,插入时被当 做 Null 处理;
  • 为 ShardKey 添加后缀 refineCollectionShardKey 命令,可以修改 ShardKey 包含的 Field;

而在 4.2 版本之前,ShardKey 对应的值不可以修改;4.2 版本之后,如果 ShardKey 为非_ID 字段, 那么可以修改 ShardKey 对应的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】基于单例模式懒汉实现方式的线程池

目录 一、LockGuard.hpp 二、Task.hpp 三、Thread.hpp 四、ThreadPool.hpp 一、LockGuard.hpp #pragma once #include <iostream> #include <pthread.h> class Mutex//锁的对象 { public:Mutex(pthread_mutex_t* lock_pnullptr):_lock_p(lock_p){}~Mutex(){}v…

设计模式-看懂UML类图和时序图

这里不会将UML的各种元素都提到&#xff0c;只讲类图中各个类之间的关系&#xff1b; 能看懂类图中各个类之间的线条、箭头代表什么意思后&#xff0c;也就足够应对 日常的工作和交流&#xff1b; 同时&#xff0c;应该能将类图所表达的含义和最终的代码对应起来&#xff1b;1.…

Qt音视频开发39-海康sdk回调拿到数据GPU绘制的实现

一、前言 采用海康的sdk做开发&#xff0c;最简单最容易的方式就是传入句柄&#xff08;windows和linux都支持/很多人以为只有windows才支持&#xff09;即可&#xff0c;这种方式不用自己处理绘制&#xff0c;全部交给了sdk去处理&#xff0c;所以cpu的占用是最低的&#xff…

ERTEC200P-2 PROFINET设备完全开发手册(8-1)

8.1 IRT通讯实验 这里我们使用APP3 IsoApp&#xff0c;修改源代码usrapp_cfg.h的宏为 #define EXAMPL_DEV_CONFIG_VERSION 3 使能App3&#xff0c;对应的主程序为“usriod_main_isoapp.c” 编译后下载运行。打开4.2建立的TIA项目&#xff0c;添加等时模式组织块&#xff0c…

SAS学习第3章:试验数据处理的心决

sas中数据的输入格式一般分为2种&#xff0c;一种是直接输入&#xff0c;另一种是循环输入。input 后跟几个变量名&#xff0c;数据卡cards就要据此逐次处理&#xff0c;且一定是倍数关系。 1.直接输入在自变量及数据较少的情况下较好使用。 例&#xff1a; 甲、乙、丙三个奶…

代码随想录_二叉树_leetcode105 106

leetcode105. 从前序与中序遍历序列构造二叉树 105. 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 示例 1: 输入…

android sdl编译

SDL&#xff08;Simple DirectMedia Layer&#xff09;是一套开放源代码的跨平台多媒体开发库&#xff0c;使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数&#xff0c;让开发者只要用相同或是相似的代码就可以开发出跨多个平台。 1 下载SDL源码 http://www.libsd…

后缀数组的应用:最长公共子串

题目描述 假设 str1 长度为 N N N&#xff0c;str2 长度为 M M M&#xff0c;求 str1 和 str2 的最长公共子串。 思路分析 示例&#xff1a;str1 “12abcd456”, str2 “7abcd89”&#xff0c;则str1和str2的最长公共子串为 abcd。 注意&#xff0c;子串是连续的。 动…

二叉搜索树专题

二叉搜索树专题 特性篇LeetCode 230. 二叉搜索树中第K小的元素解题思路代码实现LeetCode 538. 把二叉搜索树转换为累加树解题思路代码实现 基操篇LeetCode 98. 验证二叉搜索树解题思路代码实现LeetCode 700. 二叉搜索树中的搜索代码实现LeetCode 701. 二叉搜索树中的插入操作解…

总结826

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 高等数学&#xff1a;复习12讲二元积分&#xff0c;第12讲习题&#xff0c;做了17道题 英语&#xff1a;早上背单词&am…

CAXA 3D 实体设计2020 caxa电子图板2020 64位/32位 详细安装方法

CAXA实体设计2016是国内软件公司根据美国最新的专利技术和多年在CAD/CAM领域积累的经验打造的专业3D模型设计软件&#xff0c;具有国际先进水平&#xff0c;支持创新模式和工程模式。创新模式将可视化自由设计与精准设计相结合&#xff0c;使产品设计跨越了传统参数化CAD软件的…

PHP项目——外卖点餐系统后台管理解析

项目介绍 系统基于总部多门店的连锁模式&#xff0c;拥有门店独立管理后台&#xff0c;支持总部定价和门店定价、LBS定位点餐&#xff0c;可堂食可外卖&#xff0c;适用于茶饮的外卖点餐场景&#xff0c;搭建自己的一点点、奈雪、喜茶点餐系统。 平台后台 1.商品 对门店总商…

取消调休?这个公司好像知道员工要什么...

今年的五一小长假3天变5天&#xff0c;比以往多2天&#xff0c;但是为了多出来的这两天&#xff0c;前一个周末的周日&#xff0c;也就是本周的周日4月23日&#xff0c;要正常上班一天。 五一回来后的5月6日&#xff0c;也就是回来后的那个周六&#xff0c;也要上班&#xff0…

无线蓝牙耳机哪款音质好?目前音质最好的无线蓝牙耳机推荐

现如今&#xff0c;蓝牙耳机已经是一个非常实用且常见的数码产品了&#xff0c;不少人喜欢戴着蓝牙耳机听歌&#xff0c;玩游戏。一款音质好的蓝牙耳机不止能听个响&#xff0c;还能给人极致的听觉享受。在此&#xff0c;我来给大家分享几款目前音质最好的无线蓝牙耳机&#xf…

命令执行漏洞概述

命令执行漏洞概述 命令执行定义命令执行条件命令执行成因命令执行漏洞带来的危害远程命令执行漏洞相关函数assert()preg_replace()call_user_func() a ( a( a(b)可变函数远程命令执行漏洞的利用系统命令执行漏洞相关函数system()exec()shell_exec()passthru&#xff08;&#x…

网络请求实战-实战Fetch和Promise相关的架构

目录 Promise神器&#xff08;承诺&#xff09; PromiseCoding示例 Promise常见用法 简单的promise Fetch的基本用法 fetch Fetch基本用法 FetchPromise场景举例 小结 Promise神器&#xff08;承诺&#xff09; PromiseCoding示例 代表异步求值的过程和结果 promise…

搭建Spark Standalone集群

文章目录 一&#xff0c;Spark Standalone架构&#xff08;一&#xff09;client提交方式&#xff08;二&#xff09;cluster提交方式 二&#xff0c;Spark集群拓扑三&#xff0c;前提条件&#xff1a;安装配置了分布式Hadoop环境四&#xff0c;在master虚拟机上安装配置Spark&…

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈(nacos)

Nacos注册中心 &#xff08;一&#xff09;认识和安装Nacos 1、认识Nacos 2、安装nacos 这里下载1.4.1版本 默认端口是8848 下载解压后&#xff0c;终端进入到nacos/bin下&#xff0c;bash startup.sh -m standalone 然后查看start.out文件得到一个网址就可以查看nacos的服…

《Android 移动应用基础教程(Android Studio)(第2版)》【课本习题】【学习通2023春PDF】【参考答案】

文章目录 超星学习通智能终端软件开发&#xff08;基于Android Studio环境&#xff09;章节作业&#xff08;39&#xff09;第一章第二章 Android常见界面布局第三章 Android常见界面控件第四章第五章第六章&#xff08;略&#xff09;第七章第八章第九章第十章第十一章第十二章…

ChatGPT常见问题,Access denied的解决办法

今天&#xff0c;突然想登录一登录ChatGPT&#xff0c;提示 Access denied, You do not have access to chat.openai.com 怎么办&#xff1f; “Access denied You do not have access to chat.openai.com. The site owner may have set restrictions that prevent you from ac…