MongoDB分片
创始人
2024-05-23 20:12:37
0

概述

分片,Sharding,将数据拆分至不同数据节点的方式,MongoDB高可用集群的一种形式;需存储海量数据时,一台机器满足不了需求,单台机器读写吞吐性能也会是瓶颈。Sharding技术通过在多台机器上分割数据,使得系统能存储和处理海量数据。

分片的原因

  • 复制所有的写入操作到主节点
  • 延迟的敏感数据会在主节点查询
  • 单个副本集限制在12个节点
  • 当请求量巨大时会出现内存不足
  • 本地磁盘不足
  • 垂直扩展价格昂贵

框架图
在这里插入图片描述
三个主要组件(三类节点):

  • Shard:数据节点,用于存储实际的数据块,分片节点可以是一个普通的数据节点也可以是一个副本集。实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
  • Config Server:配置节点,mongod实例,存储分片的配置信息,包括整个Cluster Metadata、由哪些分片、chunk信息等
  • Query Routers:路由节点,客户端由此接入,由该路由节点路由至不同的数据节点,整个集群看上去像单一数据库,前端应用可以透明使用。

高可用集群

一般来说,MongoDB高可用集群有3种部署形式:

  • Master Slave 模式
  • Replica Set 副本集模式
  • Sharding 模式

Master Slave

分布式系统最常见的部署模式,有一主一从和一主多从形式,常用于热备、读写分离。
Master节点可读可写,通过MongoDB Oplog定时将Master节点接收到的写操作同步到所有Salve节点;所有Slave 从 Master 同步数据,从节点之间不感知。

简单示意图
在这里插入图片描述
搭建 Master-Slave 模式:
启动 Master 节点:mongod --master --dbpath /data/masterdb/
启动 Slave 节点:mongod --slave --source <:> --dbpath /data/slavedb/--source:指定数据的复制来源,也就是 Master 的地址;

这种读写模式有个数据一致性的问题,毕竟同步不是实时的,适用于对数据一致性要求不严格的场景。

MongoDB 3.6 起已不推荐使用主从模式,自 MongoDB 3.2 起,分片群集组件已弃用主从复制。因为 Master-Slave 其中 Master 宕机后不能自动恢复,只能靠人为操作,可靠性也差,操作不当就存在丢数据的风险。

Replica Set

包含三类节点角色:

  • Primary
    主节点,只有 Primary 可读可写,接收所有的写请求,然后把数据同步到所有 Secondary 。一个 Replica Set 只有一个 Primary 节点,Primary 挂掉后,其他 Secondary 及 Arbiter 节点会重新选举出来一个 Primary 节点,继续提供服务。
    读请求默认是发到 Primary 节点处理,客户端可配置读 Secondary 节点。
  • Secondary
    数据副本节点,当主节点挂掉的时候,参与选主。Secondary 相互有心跳,Secondary 可以作为数据源,Replica 可以是一种链式的复制模式。
  • Arbiter
    仲裁者,不存数据,不会被选为主,只进行选主投票。可减轻在减少数据的冗余备份,又能提供高可用的能力。
    在这里插入图片描述
    功能:
  • 读写分离,数据多副本
  • 故障自动恢复
  • 节点之间保持心跳请求应答,可感知集群的整体状态

由于Secondary需要和其他若干个Secondary节点保持心跳信息,即,每两个Secondary节点之间都互有心跳,如何维护这个心跳信息呢?不难猜到,Secondary节点数量不宜过大。

Sharding

MongoDB长于海量存储,而数据量的增长是没有上限。参考关系型数据库在应对海量数据的纵向扩展(升级机器配置)和横向扩展(增加机器数量),其中横向扩展又包括水平和垂直维度的分库分表。

Sharding是横向扩展的思路。基于图1 Sharding架构图,不难发现Sharding模式是架构在前面提到的Replica Set模式基础上,一个Shard就是一个Replica Set集群。理论上,Replica Set 的集群的个数是可以无限增长的。

原理

Sharding模式下,数据如何选择某个Shard进行存储呢?即分片算法。

Chunks

MongoDB将数据分割到Chunks。每个Chunk有一个基于分片键的左闭右开的区间。分片Shard可以含有多个Chunks。

MongoDB 使用分片集群平衡器在分片集群中迁移Chunks,目地是Chunks在分片集群中均匀分布。

不能移动文件数超过 250000 或超过 设置的 chunk 大小 / 平均文件大小 1.3 倍的 chunk。

分片键
MongoDB 根据分片键分割 collection 中的文档。
MongoDB中提供自动分片的方式,会根据数据块(chunk)大小的设定,对片键进行拆分;

分片算法

Chunk切分根据分片策略进行实施,分片策略的内容包括分片键和分片算法。

MongoDB支持的分片算法:

  • 范围分片(range sharding)
    假设集合根据A字段(如订单号)来分片,需提前知道A字段的范围(假如是0~100),然后设置Chunk数量N(假如设置为4),集合存储到具体某个Chunk,如A字段的范围区间为[0-25)的集合会存储到Chunk1。优点:能很好地满足范围查询的需求。缺点:如果Shard Key有明显递增、递减趋势,则新插入的文档会分布到同一个chunk,读写压力会集中到一个节点,从而导致单点的性能瓶颈。
  • 哈希分片(hash sharding)
    事先根据分片键计算出一个新的哈希值(64位整数),再根据哈希值按照范围分片的策略进行chunk的切分。hash算法可保证随机性,文档可以离散地分布到多个Chunk上,能够一定程度上避免范围分片的缺陷。缺点:在执行范围查询时,因为所有的范围查询都必然导致对所有Chunk进行检索,拿到全部Chunk的检索后再聚合返回到客户端。

另一个区别:哈希分片只能选择单个字段,而范围分片允许采用组合式的多字段作为分片键。

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

分片键选择:

  • 分片键基数取值越大越有利于扩展
  • 分片键的取值分布应该尽可能均匀
  • 业务读写模式,尽可能分散写压力,而读操作尽可能来自一个或少量的分片
  • 分片键应该能适应大部分的业务操作

部署实战

在单机环境下,设置分片结构端口分布如下:

Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000

步骤一:启动Shard Server

mkdir -p /www/mongoDB/shard/s0
mkdir -p /www/mongoDB/shard/s1
mkdir -p /www/mongoDB/shard/s2
mkdir -p /www/mongoDB/shard/s3
mkdir -p /www/mongoDB/shard/log
/usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
# 省略

步骤二: 启动Config Server

mkdir -p /www/mongoDB/shard/config
/usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork

像启动普通mongodb服务一样启动,不需要添加—shardsvrconfigsvr参数。因为这两个参数的作用就是改变启动端口

步骤三: 启动Route Process

/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500

mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,默认200MB。

步骤四: 配置Sharding
使用MongoDB Shell登录到mongos,添加Shard节点

/usr/local/mongoDB/bin/mongo admin --port 40000
connecting to: 127.0.0.1:40000/admin
mongos> db.runCommand({ addshard:"localhost:27020" })
{ "shardAdded" : "shard0000", "ok" : 1 }
......
mongos> db.runCommand({ addshard:"localhost:27029" })
{ "shardAdded" : "shard0009", "ok" : 1 }
mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库
{ "ok" : 1 }
mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})
{ "collectionsharded" : "test.log", "ok" : 1 }

步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000

编程

使用Sharding模式后,应用层编码有些注意事项:

  • 要使用 mapReduce 和 aggregrate 代替 group
  • db.eval() 不向下兼容
  • $where 不允许引用 db 对象
  • 不支持 geoSearch
  • 对分片的 collection 进行 update() 或者 remove() 操作必须包含分片键或者 _id,否则会报错

参考

  • sharded-clusters-limit

相关内容

热门资讯

二年级游乐园冲浪作文(优秀6... 二年级游乐园冲浪作文 篇一我最喜欢的游乐园冲浪今天,我和爸爸妈妈去了一个很大很有趣的游乐园。这个游乐...
二年级有趣的游戏作文200字... 二年级有趣的游戏作文200字 篇一:捉迷藏捉迷藏是我们二年级最喜欢的游戏之一。这个游戏的规则很简单:...
我的好朋友二年级作文【实用6... 我的好朋友二年级作文 篇一我的好朋友我有一个非常好的朋友,她叫小芳。她和我在同一个班级,我们从小学一...
我的家【优质6篇】 我的家 篇一我的家是一个温馨而快乐的地方。无论是平日的热闹还是周末的宁静,家里总是充满着欢声笑语和爱...
二年级作文不少于200个字【... 二年级作文不少于600个字 篇一我的暑假生活暑假终于来了,我迫不及待地迎接了这个长假。在这个暑假里,...
二年级暑假趣事作文捉老鼠(推... 二年级暑假趣事作文捉老鼠 篇一暑假快到了,我和弟弟决定在家里玩捉老鼠的游戏。我们找来了一些小道具,准...
小学二年级避暑山庄旅游作文(... 小学二年级避暑山庄旅游作文 篇一我和家人去了一个非常有趣的地方——避暑山庄。这个地方真的很美,有很多...
二年级作文游庐山【精简6篇】 二年级作文游庐山 篇一我和爸爸妈妈一起去了庐山。庐山是中国著名的山岳风景区,被誉为“江南第一山”。我...
二年级下册看图写话春天来了作... 二年级下册看图写话春天来了作文 篇一春天来了春天来了,大地变得生机勃勃。图中的小朋友们正在户外玩耍,...
二年级打雪仗作文指导【通用6... 二年级打雪仗作文指导 篇一打雪仗是冬天最有趣的活动之一,对于二年级的小朋友来说,更是一种享受。下面是...
二年级美丽的早晨作文(实用6... 二年级美丽的早晨作文 篇一美丽的早晨早晨的阳光透过窗户洒进来,房间里弥漫着一股清新的味道。我慢慢睁开...
小学二年级海边旅游作文200... 小学二年级海边旅游作文200字作文 篇一我和家人去海边旅游了,真是一个美好的经历!早上,我们一大早就...
二年级【优秀6篇】 二年级 篇一:我的暑假生活暑假终于来了,我迫不及待地开始了我的暑假生活。在这个悠长的假期里,我过得非...
赏荷花二年级作文【通用6篇】 赏荷花二年级作文 篇一欣赏荷花的美丽今天,我和爸爸妈妈一起去公园赏荷花。公园里有一个大大的荷花池,里...
舞蹈汇演作文二年级【精彩6篇... 舞蹈汇演作文二年级 篇一舞蹈汇演是一场精彩绝伦的表演,让我感受到了舞蹈的魅力和美妙。我在二年级的时候...
二年级作文我家的厨师(优质6... 二年级作文我家的厨师 篇一我家的厨师是我妈妈。她是一个非常厉害的厨师,每天都能给我们做出美味可口的饭...
童年趣事作文:枕头大战【精选... 童年趣事作文:枕头大战 篇一小时候的我总是充满了无尽的精力和好奇心,每天都在探索世界的各个角落。而最...
家乡的菊花作文二年级(经典6... 家乡的菊花作文二年级 篇一家乡的菊花我家乡是一个美丽的小镇,四季如春,花草繁盛。其中,最引人注目的要...
二年级小作文28篇【精简3篇... 二年级小作文28篇 篇一我最喜欢的动物我最喜欢的动物是猫。猫咪有软软的毛,尤其是它们的小脸上,摸起来...
二年级写我的家乡【优选6篇】 二年级写我的家乡 篇一我的家乡是一个美丽的小城镇。它位于一个宽广的山谷之中,四周环绕着青翠欲滴的群山...