mongodb分片概念和原理-实战分片集群

一、分片

分片是一种跨多台机器分发数据的方法。MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署。

问题:

具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个服务器的容量。例如,高查询率会耗尽服务器的CPU容量。工作集大小大于系统的RAM会强调磁盘驱动器的I / O容量。

解决系统增长的方法有两种:垂直和水平缩放。

垂直扩展涉及增加单个服务器的容量,例如使用更强大的CPU,添加更多RAM或增加存储空间量。可用技术的局限性可能会限制单个机器对于给定工作负载而言足够强大。此外,基于云的提供商基于可用的硬件配置具有硬性上限。结果,垂直缩放有实际的最大值。

水平扩展涉及划分系统数据集并加载多个服务器,添加其他服务器以根据需要增加容量。虽然单个机器的总体速度或容量可能不高,但每台机器处理整个工作负载的子集,可能提供比单个高速大容量服务器更高的效率。扩展部署容量只需要根据需要添加额外的服务器,这可能比单个机器的高端硬件的总体成本更低。权衡是基础架构和部署维护的复杂性增加。

MongoDB支持通过分片进行水平扩展

二、分片集群概述

MongoDB分片群集包含以下组件:

分片:是一个独立普通的mongod进程,保存数据信息。可以是一个副本集也可以是单独的一台服务器。

mongos:起到一个路由的功能,供程序连接。本身不保存数据,在启动时从配置服务器加载集群信息,开启mongos进程需要知道配置服务器的地址,指定configdb选项。

配置服务器:是一个独立的mongod进程,保存集群和分片的元数据,即各分片包含了哪些数据的信息。最先开始建立,启用日志功能。像启动普通的mongod一样启动配置服务器,指定configsvr选项。不需要太多的空间和资源,配置服务器的1KB空间相当于真是数据的200MB。保存的只是数据的分布表。当服务不可用,则变成只读,无法分块、迁移数据。

交互图如下:

1.png

MongoDB在集合级别对数据进行分片,将集合数据分布在集群中的分片上。

1、锁片键

为了在集合中分发文档,MongoDB 使用分片键对集合进行分区。分片键 由目标集合中每个文档中存在的不可变字段组成。

在分片集合时选择分片键。分片后无法更改分片键的选择。分片集合只能有一个分片 键。要对非空集合进行分片,集合必须具有 以分片键开头的索引。对于空集合,如果集合尚未具有指定分片键的适当索引,MongoDB将创建索引。

分片键的选择会影响分片群集的性能,效率和可伸缩性。具有最佳硬件和基础结构的群集可能会因选择分片键而受到瓶颈。选择分片键及其支持索引也会影响群集可以使用的分片策略。

2、大块

MongoDB将分片数据划分为块。每个块都具有基于分片键的包含较低且独占的较高范围 。

3、平衡器和偶数块分配

为了在群集中的所有分片上实现块的均匀分布,平衡器在后台运行以跨分片迁移块。

4、Sharding的优点

(1)读写

MongoDB的分布在整个的读写工作量 碎片将在分片集群,使每个碎片来处理群集操作的一个子集。通过添加更多分片,可以在群集中水平扩展读取和写入工作负载。

对于包含分片键或复合分片键前缀mongos的查询,可以在特定分片或分片集上定位查询。这些目标操作通常比向群集中的每个分片广播更有效 。

(2)存储容量

拆分分配整个数据碎片集群中,允许每个碎片以包含总簇数据的子集。随着数据集的增长,额外的分片会增加群集的存储容量。

(3)高可用性

分片簇可以继续执行,即使一个或多个碎片是不可用的部分读/写操作。虽然在停机期间无法访问不可用分片上的数据子集,但是针对可用分片的读取或写入仍然可以成功。

备注:

(1)从MongoDB 3.2开始,您可以将配置服务器部署为副本集。只要大多数副本集可用,具有配置服务器副本集(CSRS)的分片群集就可以继续处理读取和写入。

(2)在3.4版本中,MongoDB 删除了对SCCC配置服务器的支持。

(3)在生产环境中,应将各个分片部署为 副本集,从而提供更高的冗余和可用性。

5、分片集群注意事项

(1)分片集群基础架构要求和复杂性需要仔细规划,执行和维护。

(2)选择分片密钥时需要认真考虑,以确保集群性能和效率。分片后不能更改分片键,也不能取消分片分片。

(3)Sharding具有一定的操作要求和限制

(4)如果查询不包括分片键或复合分片键的前缀 ,则mongos执行广播操作,查询分 片群集中的所有分片。这些分散/收集查询可以是长时间运行的操作。

6、分片策略

MongoDB支持两种分片策略,用于跨分片群集分发数据。

(1)散列分片

散列分片涉及计算分片键字段值的散列。然后,基于散列的分片键值为每个块分配一个范围。

(2)远程分片

远程分片涉及基于分片键值将数据划分为范围。然后根据分片键值为每个块分配一个范围

7、 MongoDB Sharding Cluster角色

(1) Shard Server

即存储实际数据的分片每个Shard 可以是一个mongod 实例也可以是一组mongod 实例

构成的Replica Set。为了实现每个Shard 内部的auto-failoverMongoDB 官方建议每个Shard

为一组Replica Set。

(2)Config Server

为了将一个特定的collection 存储在多个shard 中需要为该collection 指定一个shard key

例如{age: 1} shard key 可以决定该条记录属于哪个chunk。Config Servers 就是用来存储

所有shard 节点的配置信息、每个chunk 的shard key 范围、chunk 在各shard 的分布情况、

该集群中所有DB 和collection 的sharding 配置信息。

(3)Route Process

这是一个前端路由客户端由此接入然后询问Config Servers 需要到哪个Shard 上查询或

保存记录再连接相应的Shard 进行操作最后将结果返回给客户端。客户端只需要将原本

发给mongod 的查询或更新请求原封不动地发给Routing Process而不必关心所操作的记录

存储在哪个Shard 上。

三、分配集群搭建

1、环境准备

(1)、数据库环境

主机名

数据库IP地址

数据库版本

用途

系统

SQL_mongdb

172.169.18.128

mongodb4.0.3

配置3,路由1,分片2

cenots7.4

node01

172.169.18.162

mongodb4.0.3

路由1,分片2

centos7.4

node01

172.169.18.180

mongodb4.0.3

分片2

centos7.4

(2)暂时关闭防火墙和seliunx,测试完毕再开启安全规则

(3)yum安装mongdb4.0版本(省略)

同样的,在node01和node02上安装服务

在部署之前先明白片键的意义,一个好的片键对分片至关重要。片键必须是一个索引,数据根据这个片键进行拆分分散。通过sh.shardCollection加会自动创建索引。一个自增的片键对写入和数据均匀分布就不是很好,因为自增的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按照片键查询会非常高效。随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。在所有分片上查询,mongos会对结果进行归并排序。

(4)

框架图

2.png

2、配置服务器的启动。(SQL_mongdb上开启3个,Port:21000、22000、2300)

备注:配置服务器必须开启1个或则3个,开启2个则会报错:

(1)创建目录

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date1

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date2

[root@SQL_mongdb /]# mkdir -p /opt/mongodb/date3

(2)新建配置文件

[root@SQL_mongdb ~]# cat /etc/mongodb_21000.conf

#数据目录

dbpath=/opt/mongodb/date1/

#日志文件

logpath=/opt/mongodb/mongodb_21000.log

#日志追加

logappend=true

#端口

port = 21000

#最大连接数

maxConns = 50

pidfilepath = /opt/mongodb/mongo_21000.pid

#日志,redo log

journal = true

#刷写提交机制

journalCommitInterval = 200

#守护进程模式

fork = true

#刷写数据到日志的频率

syncdelay = 60

#storageEngine = wiredTiger

#操作日志,单位M

oplogSize = 1000

#命名空间的文件大小,默认16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

[root@SQL_mongdb ~]# cat /etc/mongodb_22000.conf

#数据目录

dbpath= /opt/mongodb/date2/

#日志文件

logpath= /opt/mongodb/mongodb_22000.log

#日志追加

logappend=true

#端口

port = 22000

#最大连接数

maxConns = 50

pidfilepath = /opt/mongodb/mongo_22000.pid

#日志,redo log

journal = true

#刷写提交机制

journalCommitInterval = 200

#守护进程模式

fork = true

#刷写数据到日志的频率

syncdelay = 60

#storageEngine = wiredTiger

#操作日志,单位M

oplogSize = 1000

#命名空间的文件大小,默认16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

[root@SQL_mongdb ~]# cat /etc/mongodb_23000.conf

#数据目录

dbpath= /opt/mongodb/date3/

#日志文件

logpath= /opt/mongodb/mongodb_23000.log

#日志追加

logappend=true

#端口

port = 23000

#最大连接数

maxConns = 50

pidfilepath = /opt/mongodb/mongo_23000.pid

#日志,redo log

journal = true

#刷写提交机制

journalCommitInterval = 200

#守护进程模式

fork = true

#刷写数据到日志的频率

syncdelay = 60

#storageEngine = wiredTiger

#操作日志,单位M

oplogSize = 1000

#命名空间的文件大小,默认16M,最大2G。

nssize = 16

noauth = true

unixSocketPrefix = /tmp

configsvr = true

replSet=jiangjj

bind_ip = 172.169.18.128

(3)启动配置文件(实例进程)

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_21000.conf

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_22000.conf

[root@SQL_mongdb ~]# mongod -f /etc/mongodb_23000.conf

3.png

备注:

关闭进程服务

# mongod -f /etc/mongodb_21000.conf --shutdown

如果非正常访问,重新启动会报错,必须要删除mongd.lock后才能启动成功。

(4)将节点配置组成集群(副本集)

在任意节点启动配置,这里使用SQL_jiangjj节点

登录数据库

[root@SQL_mongdb ~]# mongo --host 172.169.18.128:21000

> use admin

> cfg={ _id:"jiangjj",members:[{_id:0,host:'172.169.18.128:21000',priority:3},{_id:1,host:'172.169.18.128:22000',priority:2},{_id:2,host:'172.169.18.128:23000',priority:1}] };

#配置生效命令

> rs.initiate(cfg)

3、路由配置(在SQL_mongodb和node01上各开启1个,port:3000)

路由服务器不保存数据,把日志记录一下即可

(1)在SQL_mongodb上新增配置文件

[root@SQL_mongdb ~]# vim /etc/mongodb_30000.conf

#日志文件

logpath = /opt/mongodb/mongodb_route.log

#日志追加

logappend = true

#端口

port = 30000

#最大连接数

maxConns = 20000

#chunkSize=1

#绑定地址

bind_ip = 0.0.0.0

pidfilepath = /opt/mongodb/mongo_30000.pid

#必须是1个或则3个配置

configdb = jiangjj/172.169.18.128:21000,172.169.18.128:22000,172.169.18.128:23000

#configdb=127.0.0.1:20000  #报错

#守护进程模式

fork = true

(2)开启mongos

[root@SQL_mongdb ~]# mongos -f /etc/mongodb_30000.conf

4.png

(3)配置一个普通分片文件

5.png

查看状态

6.png

按照上面的方法再到node01上开启分片服务和路由服务(配置文件一样),以及在node02上开启分片服务。到此分片的配置服务器、路由服务器、分片服务器都已经部署完成。

备注:分片其中一个配置,其他的类似

[root@node01 etc]# vim mongodb_60000.conf

#mongodb

dbpath=/opt/mongodb/date2/

logpath=/opt/mongodb_60000.log

pidfilepath=/opt/mongodb/mongodb_60000.pid

directoryperdb=true

logappend=true

bind_ip=172.169.18.162

port=60000

oplogSize=100

fork=true

noprealloc=true

4、配置分片:下面的操作都是在mongodb的命令行里执行

(1)登陆路由服务器mongos 操作:

[root@SQL_mongdb ~]# mongo --port=30000

mongos> use admin

mongos> db.runCommand({addshard:'172.169.18.128:60000'})

mongos> db.runCommand({addshard:'172.169.18.162:60000'})

mongos> db.runCommand({addshard:'172.169.18.180:60000'})

7.png

#查看

mongos> sh.status()

8.png

(2)开启分片功能:sh.enableSharding("库名")、sh.shardCollection("库名.集合名",{"key":1})

mongos> sh.enableSharding('jiangjj')

mongos> sh.status()

9.png

mongos> sh.shardCollection("jiangjj.text",{"name":1})

报错如下:

Cannot accept sharding commands if not started with --shardsvr

10.png

在分片配置文件中加入如下参数:

shardsvr = true

重启进程后执行上面的命令

11.png

查看:mongos> sh.status()

12.png

查看详细信息:

mongos> sh.status({"verbose":1})

或则

mongos> db.printShardingStatus("vvvv")

或则

mongos> printShardingStatus(db.getSisterDB("config"),1)

#判断是否是Sharding

13.png

5、测试查看

1、在路由Mongos端添加数据库和数据,如此

14.png

2、添加的数据库分配到不听的分片节点上

15.png

备注:这里我们做的都是单点的,要是一个分片坏了,则数据会丢失,我们可以利用副本集减少灾难

四、高可用:Sharding+Replset

1、在三个节点各自添加一个分片,port:50000,name:user01

其中一个集群分片,根据实际情况修改调整

#mongodb

dbpath=/opt/mongodb/date1/

logpath=/opt/mongodb_50000.log

pidfilepath=/opt/mongodb/mongodb_50000.pid

#keyFile=/opt/mongodb/mongodb.key  //节点间用户验证文件,内容必须一致,权限600,仅副本集模式有效

directoryperdb=true

logappend=true

replSet=user01

bind_ip=172.169.18.162

port=50000

#auth=true

oplogSize=100

fork=true

noprealloc=true

#maxConns=4000

shardsvr = true

2、将分片设置成副本集

登录数据库

[root@SQL ~]# mongo --host 172.169.18.128:50000

> use admin

> user01db={ _id:"user01",members:[{_id:0,host:'172.169.18.128:50000',priority:3},{_id:1,host:'172.169.18.162:50000',priority:2},{_id:2,host:'172.169.18.180:50000',priority:1}] };

#配置生效命令

> rs.initiate(user01db)

21.png

3、配置路由节点

[root@SQL_mongdb ~]# mongo --port=30000

切换到admin库

mongos> use admin

#添加分片节点

mongos> sh.addShard("user01/172.169.18.128:50000")

22.png

备注:

#也可以直接在路由节点添加副本集

mongos>sh.addShard("user01/172.169.18.128:50000,172.169.18.162:50000,172.169.18.180:50000")

#查看集群信息

mongos> sh.status()

23.png

补充说明:均衡器

24.png

均衡器:均衡器负责数据迁移,周期性的检查分片是否存在不均衡,如果不存在则会开始块的迁移,config.locks集合里的state表示均衡器是否找正在运行,0表示非活动状态,2表示正在均衡。均衡迁移数据的过程会增加系统的负载:目标分片必须查询源分片的所有文档,将文档插入目标分片中,再清除源分片的数据。可以关闭均衡器(不建议):关闭会导致各分片数据分布不均衡,磁盘空间得不到有效的利用。 

查看状态:mongos> sh.getBalancerState()

关闭命令:mongos> sh.stopBalancer()

开启命令:mongos> sh.setBalancerState(true)

4、在Mongos添加两个数据库user01和user02,添加数据测试副本集

分配在不同的分片节点上,查看的数据不同26.png

5、分片数据库迁移,删除分片

删除分片时,必须确保该分片上的数据被移动到其他分片中,对于以分片的集合,使用均衡器来迁移数据块,对于非分片的集合,必须修改集合的主分片。

1)将shard0001分片上的数据库jiangjj04迁移到user01集合分片上

mongos> use admin

mongos> db.runCommand({moveprimary:"jiangjj04",to:"user01"})

27.png

如下:

28.png

2、删除分片:

#需要到admin下面删除(需要执行两次)

mongos> db.runCommand({"removeshard":"jiangjj01"})

注意:MongoDB的分片不能删除最后一个,否则报如下错误

31.png

3、删除分片上的数据库

mongos> use jsqdb

mongos> db.dropDatabase()

32.png

三、集群用户验证设置


1、创建验证秘钥文件

keyFile文件的作用: 集群之间的安全认证,增加安全认证机制KeyFile(开启keyfile认证就默认开启了auth认证了,为了保证后面可以登录,我已创建了用户)

# cd /opt/mongodb/

#  touch .keyFile

#  chmod 600 .keyFile

# openssl rand -base64 102 > .keyFile

102:是文件大小

注意:创建keyFile前,需要先停掉副本集中所有主从节点的mongod服务,然后再创建,否则有可能出现服务启动不了的情况。

2、在Mongos节点添加root账号

mongos> use admin

mongos> db.createUser({

... user:'root',

... pwd:'123456',

... roles:[{role:'root',db:'admin'}]

... })

33.png

3、更新所有配置分片节点配置文件,在路由配置文件只配置keyFile参数即可

keyFile=/home/data/.keyFile

auth=true

4、启动副本集,测试

登录验证

root用户

34.png

现在只有两个路由节点端口30000有权访问数据库,其他节点访问如下图报错信息

35.png

在mongos节点给jiangjj01配置用户

添加一个jiangjj用户拥有读写权限

36.png

登录Mongos节点验证成功。

37.png

补充知识点:

权限伸缩

1)如何增加权限

db.grantRolesToUser(

<user_name>,

[{role:<role_name>,db:<db_name>}])

注意:此方法接受2个参数,而不是两个对象, 而且如何权限重复不会覆盖,新的会增加

例如:

db.grantRolesToUser('roleTest,[{role:'readWrite',db:'test'}])\

2)如何收缩权限

db.revokeRolesToUser(

<user_name>,

[{role:<role_name>,db:<db_name>}])

权限配置详细请参考官方


猜你喜欢

转载自blog.51cto.com/13941177/2309939