MongoDB负载均衡集群(第8章节选)

MongoDB自身可组成分片加复制的集群,在这个集群的前端加上负载均衡器(比如HAProxmy + Keepalived),就可组建成一个无单点故障、十分完美的高可用负载均衡集群(如图8-1所示)。

MongoDB负载均衡集群(第8章节选)_第1张图片

 

图8- 1

整个MongDB高可用体系结构中,存在四个应用集群:入口路由集群Mongos、配置集群“Config Server”、分片集群1、分片集群2。

入口路由集群“Mongos”由负载均衡器来实现高可用及负载均衡功能。

配置集群“Config Server”的高可用及负载均衡有MongDB自身功能实现。

分片集群至少有两组及两组以上的集群所组成,每一个分片集群是一个备份集,即每个单独的分片集群的节点所保存的数据是一致的。多个分片集群,由配置服务“Config Server”提供负载分发,分片集群本身的高可用性由MongDB自身功能实现。

一个可用于生产环境的MongDB高可用集群,除了负载均衡外,至少要12个单元运行这些服务。看起来单元数量很多,但对系统的配置要求不高,比如路由集群Mongos和配置集群“Config Server”。虽然可以在一个操作系统上运行多个MongoDB实例(不同的端口区分不同的功能),但还是建议一个系统一个实例,这样便于维护与扩容。将所有运行MongoDB实例的系统,部署在Proxmox VE超融合集群平台,那就更有优势,比容器部署、管理都方便。因为仅需在虚拟机系统安装MongoDB,并做好基础的配置,然后以此做克隆,快速生成所需的运行单元。

8.1 安装MongoDB

MongoDB支持多种Linux 发行版包管理器进行安装,比如Debian之“apt”、Suse之“zypper”、Rocky/Centos之“dnf/yum”等。作者所采用的操作系统版本为Rocky 9.2,包管理器自然就是“dnf/yum”了。

Rocky 9默认情况下,执行指令“dnf install mongodb-org”是得不到期望的结果。用文本编辑器在目录“/etc/yum.repo.d”创建文件“mongodb-org-6.0.repo”,其完整内容如下:

[mongodb-org-6.0]

name=MongoDB Repository

baseurl=https://repo.mongodb.org/yum/redhat/9Server/mongodb-org/6.0/x86_64/

gpgcheck=1

enabled=1

gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc

为保证软件仓库源的正确性,我们需要对文件“mongodb-org.repo”中的“baseurl”与“gpgkey”的设定做检查,比如用浏览器访问“baseurl”设定的地址,应该是真实存在的,如图8-2所示。

MongoDB负载均衡集群(第8章节选)_第2张图片图8- 2

 

同样,用浏览器访问https://www.mongodb.org/static/pgp/server-6.0.asc,也可获得正确的结果。

接下来,系统命令行执行“dnf install mongdb-org”,就应该可以进行MongoDB的安装,如图8-3所示。

MongoDB负载均衡集群(第8章节选)_第3张图片图8- 3

 

安装过程基本不会有错误出现,并且速度很快。安装完成以后,会在系统目录“/etc”生成MongoDB所必须的配置文件“mongod.conf”。我们可直接对其修改进行相应配置,也可单独自建配置文件,在启动“mongod”服务时加选项“-f”进行显式指定。

登录Proxmox VE超融合集群Web管理后台,以安装好MongoDB的虚拟机为基础,克隆出其它所需的运行单元,如图8-4所示。

MongoDB负载均衡集群(第8章节选)_第4张图片图8- 4

 

如果没有作者这样的超融合集群平台,就挨个安装系统和MongoDB。

8.2 分片服务Shard集群

分片集群是实际存储数据的设施,对集群的单个节点而言,存储空间与系统独立,在文件系统层面就是使用独立的分区(如图8-5所示)。分片Shard最少是两组集群,每组三个节点或者更多节点。两组集群本身之间不会产生直接的联系,客户端的读写请求,调度到哪一组集群是由“Config Server”决定的。

MongoDB负载均衡集群(第8章节选)_第5张图片图8- 5

 

我们约定,MongoDB分片的第一个集群的副本集名称为“shard1”,第二个副本集的名称为“shard2”;数据的实际存储路径为“/data/mongodb/data”,日志文件路径为“/data/momgodb/logs”. 为调试和配置集群方便起见,MongoDB暂时不设置管理员密码,集群节点之间的暂不启用认证机制。

分片Shard集群1的配置文件“/etc/mongod.conf”完整内容如下:

# mongod.conf

# for documentation of all options, see:

#   http://docs.mongodb.org/manual/reference/configuration-options/

# where to write logging data.

systemLog:

  destination: file

  logAppend: true

  path: /data/mongodb/logs/mongod.log

# Where and how to store data.

storage:

  dbPath: /data/mongodb/data

  journal:

    enabled: true

engine:

wiredTiger:

# how the process runs

processManagement:

  timeZoneInfo: /usr/share/zoneinfo

# network interfaces

net:

  port: 27017

  bindIp: 0.0.0.0 

#security:

replication:

replSetName: shard1

sharding:

clusterRole: shardsvr

将此配置同步到分片集群“shard1”中的其它节点,然后执行命令“systemctl start mongod”启动所有节点的MongoDB服务。启动过程没有任何错误信息输出,不一定代表正确启动,需要进一步验证。比如作者启动的MongoDB,就存在问题,没有被正确的启动运行,如图8-6所示。

MongoDB负载均衡集群(第8章节选)_第6张图片图8- 6

 

导致MongoDB启动失败的原因是配置文件书写格式的问题,键与值之间需要一个空格站位,比如键“clusterRole:”,冒号后需要输入一个空格,再输入值“shardsvr”。

还有一种情况也能导致“mongod”服务启动失败,那就是数据存储目录“/data/mogodb”的属主与属组需要修改成“mongod:mongod”,因为以包管理器安装的MongoDB启动服务是以普通账号(安装过程会自动生成系统普通账号)“mongod”来执行的。不要养成一看到权限问题,就用“chmod -R 777 dir”胡乱赋权的坏习惯。

确认分片集群“shard1”所有节点的MongoDB服务都正常启动以后,切换到这些节点的任意节点系统命令行,登录到MongoDB交互界面,进行初始化操作,将所有节点组成一个集群,具体的命令如下:

[root@MongoDB-200-149 ~]# mongosh

Current Mongosh Log ID: 6491279f3770cc22c927a6b6

Connecting to:          mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.10.0

Using MongoDB:          6.0.6

Using Mongosh:          1.10.0

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).

You can opt-out by running the disableTelemetry() command.

------

   The server generated these startup warnings when booting

   2023-06-19T17:00:44.278+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted

   2023-06-19T17:00:44.278+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'

   2023-06-19T17:00:44.278+08:00: vm.max_map_count is too low

------

test> use admin

switched to db admin

shard1 [direct: primary] admin> rs.initiate({

...         _id:"shard1",

...         members:[

...         {_id:0,host:"10.122.200.148:27017",priority:1},

...         {_id:1,host:"10.122.200.149:27017",priority:1},

...         {_id:2,host:"10.122.200.150:27017",priority:1}

...     ]

... });

{ ok: 1 }

分片集群“shard1”创建完毕后,继续在此交互界面执行指令“rs.status()”,查看刚创建好的分片集群“shard1”的运行状态,如图8-7所示。

MongoDB负载均衡集群(第8章节选)_第7张图片图8- 7

 

依照此法,将第二个分片集群“shard2”也创建好。

8.3 MongoDB配置服务器“Config Server”集群

MongoDB配置服务器集群“Config Server”节点配置文件,除了副本集名称(replSetName)与集群角色(clusterRole)不同而外,其他的设定与分片集群“shard1”完全相同。在这里,我们约定,集群副本集名字为“configcls”,而集群的角色指定为“configsvr”。注意:副本集的名称可以随意命名,而集群角色是有限定的。一个完整的配置服务器“Config Server”配置文件“/etc/mongodb.conf”的内容如下:

# mongod.conf

systemLog:

  destination: file

  logAppend: true

  path: /data/mongodb/logs/mongod.log

storage:

  dbPath: /data/mongodb/data

  journal:

    enabled: true

engine:

wiredTiger:

# how the process runs

processManagement:

  timeZoneInfo: /usr/share/zoneinfo

# network interfaces

net:

  port: 27017

  bindIp: 0.0.0.0 

#security:

replication:

replSetName: configcls

sharding:

clusterRole: configsvr

启动配置集群“Config Server”所有节点的MongoDB服务“systemctl start mongod”,确认MongoDB服务的监听地址没有绑定到接口“127.0.0.1”上。用MongoDB客户端工具“mongosh”登录,创建集群“configcls”,具体的指令如下:

[root@MongoDB-200-147 ~]# mongosh  10.122.200.147

Current Mongosh Log ID: 64917e4587284270d42be6ec

Connecting to:          mongodb://10.122.200.147:27017/?directConnection=true&appName=mongosh+1.10.0

Using MongoDB:          6.0.6

Using Mongosh:          1.10.0

------省略若干--------------------------------

test> use admin

switched to db admin

admin> rs.initiate({

...         _id:"configcls",

...         members:[

...         {_id:0,host:"10.122.200.154:27017",priority:1},

...         {_id:1,host:"10.122.200.147:27017",priority:1},

...         {_id:2,host:"10.122.200.143:27017",priority:1}

...     ]

... });

{ ok: 1, lastCommittedOpTime: Timestamp({ t: 1687256871, i: 1 }) }

集群建立起后,继续在交互界面执行“rs.status()”验证其正确性。

8.4 Mongos路由集群

Mongos路由本身不需要像分片“Shard”和配置“Config Sever”以副本集方式集群,多个Mongos节点由前端的负载均衡器(例如HAProxy或者Nginx)一起组成高可用集群。Mongos路由集群分三个大的步骤:单节点配置与配置集群的关联、单节点与分片集群的关联以及节点间的集群。

8.4.1 Mongos路由与配置集群(Config server)关联

编辑Mongos所在节点的配置文件“/etc/mongod.conf”,将配置服务集群“Config Server”添加到文件中,一个已经编辑好的“/etc/mongod.conf”文件的完整内容如下:

# mongod.conf

systemLog:

  destination: file

  logAppend: true

  path: /data/mongodb/logs/mongod.log

engine:

wiredTiger:

# how the process runs

processManagement:

  timeZoneInfo: /usr/share/zoneinfo

  fork: true

# network interfaces

net:

  port: 27017

  bindIp: 0.0.0.0 

sharding:

  configDB: configcls/10.122.200.154:27017,10.122.200.147:27017,10.122.200.143:27017

保存文件后,执行命令“mongos -f /etc/mongod.conf &”启动路由服务。注意:执行“systemctl start mongos”将不能成功,除非手动创建一个“systemd”服务。

用命令行指令“mongosh”验证路由服务“mongos”的正确性。客户端“mongosh”连接成功,会输出连接地址、MongDB版本信息等,然后进入交互界面,等待用户输入。

8.4.2 Mongos路由与分片集群相关联

在运行正常的Mongos路由节点,以“mongosh”登录本地“mongos”,执行指令“sh.status()”查看一下路由初始状态,其输出如图8-8所示。

MongoDB负载均衡集群(第8章节选)_第8张图片图8- 8

 

在Mongos客户端交互界面继续输入如下指令,将前边建立起来的两个分片“Shard”集群添加进来:

[direct: mongos] admin> sh.addShard("shard1/10.122.200.148:27017,10.122.200.149:27017,10.122.200.150:27017")

{

  shardAdded: 'shard1',

  ok: 1,

  '$clusterTime': {

    clusterTime: Timestamp({ t: 1687260112, i: 9 }),

    signature: {

      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),

      keyId: Long("0")

    }

  },

  operationTime: Timestamp({ t: 1687260112, i: 9 })

}

[direct: mongos] admin> sh.addShard("shard2/10.122.200.151:27017,10.122.200.152:27017,10.122.200.153:27017")

{

  shardAdded: 'shard2',

  ok: 1,

  '$clusterTime': {

    clusterTime: Timestamp({ t: 1687260132, i: 8 }),

    signature: {

      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),

      keyId: Long("0")

    }

  },

  operationTime: Timestamp({ t: 1687260132, i: 8 })

上述指令执行完毕,就达到将路由与分片相关联的目的。这时,我们输入指令“sh.status()”,查看其状态,应该有分片信息存在,如图8-9所示。

MongoDB负载均衡集群(第8章节选)_第9张图片图8- 9

 

依照此法,将剩余节点的Mongos路由启动并与Shard分片关联。需要注意的是,Mongos路由节点之间,并不存在关联,不像分片Shard集群与配置集群“Config Server”,节点之间是相互感知的(比如主节点故障,剩余节点立即选举新的主节点)。由于存在多个Mongos路由节点,某个路由Mongos-A节点写入的数据,能否被其它路由Mongos-B节点所识别呢?如果不能,或者产生讹误,就不能将这些路由Mongos节点组成集群。

8.4.3 多路由Mongos状态同步验证

以MongoDB客户端工具,连接到路由Mongos节点“10.122.200.143”,创建数据库“sery”,并插入几条数据,具体的指令及输出如下:

[root@MongoDB-200-144 ~]# mongosh 10.122.200.144

Current Mongosh Log ID: 6492a92a52c3eae27b3b24c8

Connecting to:          mongodb://10.122.200.144:27017/?directConnection=true&appName=mongosh+1.10.0

Using MongoDB:          6.0.6

Using Mongosh:          1.10.0

…………………………………………….

[direct: mongos] admin> show dbs

admin   112.00 KiB

config    2.77 MiB

[direct: mongos] admin> use sery

switched to db sery

[direct: mongos] sery> db.sery.insertOne({"one":"001"})

{

  acknowledged: true,

  insertedId: ObjectId("6492cc189467940c5c0dfbb9")

}

[direct: mongos] sery> db.sery.insertOne({"two":"002"})

{

  acknowledged: true,

  insertedId: ObjectId("6492cc3c9467940c5c0dfbbb")

}

上边的插入操作,将在MongoDB中创建数据库“sery”。继续在Mongosh交互界面,输入指令“sh.status()”,可进一步了解数据库“sery”被写入到哪个分片Shard集群,如图8-10所示。

MongoDB负载均衡集群(第8章节选)_第10张图片图8- 10

 

登录到另一个Mongos路由节点“10.122.200.145”,查看在Mongos路由节点“10.122.200.144”创建的数据库“sery”,是否可以被检索到,操作指令及输出结果如图8-11所示。

MongoDB负载均衡集群(第8章节选)_第11张图片图8- 11

 

相应的,在Mongos路由节点“10.122.200.145”创建数据库,然后登录Mongos路由节点“10.122.200.144”,也应该能够看到所有创建好的数据库。

8.4.4 Mongos路由负载均衡集群

在负载均衡器所在的宿主系统,文本编辑器创建文件“/etc/haproxy/mongos.cfg”,并添加如下文本行:

frontend mongos

    mode tcp

    bind *:27017

    option tcplog

    log global

    default_backend mycat_lb

backend mongos_lb

    mode tcp

    balance source

    server mongos144 10.122.200.144:27017 check

server mongos145 10.122.200.145:27017 check

server mongos146 10.122.200.146:27017 check

HAProxy对配置文件执行语法检查无误后,启动或重启“Keepalived”服务,远程客户端仅需用VIP加端口27017来连接MongoDB高可用集群。

8.5 MongoDB数据分片

在本章“8.4”节,我们创建了一个名为“sery”的数据库,并在其中插入了两条数据,并且我们已经定位到“sery”数据的数据被存储到分片集群“shard2”中。而我们可能希望数据库“sery”的一部分数据被存储到分片集群“shard1”,而另一部分被存储于分片集群“shard2”。数据分片以横向方式扩展数据容量,以支持更大规模的数据存储及读写效率。

以Mongosh登录Mongos路由集群(以负载均衡器VIP加TCP27017端口),创建新的数据库“formyz”,开启分片功能并以循环方式向数据库“formyz”的表“mytable”插入50000条记录,然后查验数据库“formyz”的记录是否被分散存储到所有的分片集群。具体的操作及输出如下:

#开启数据库“formyz”分片功能,同时创建空的数据库“formyz”

[direct: mongos] admin> sh.enableSharding("formyz")

{

  ok: 1,

  '$clusterTime': {

    clusterTime: Timestamp({ t: 1687403738, i: 2 }),

    signature: {

      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),

      keyId: Long("0")

    }

  },

  operationTime: Timestamp({ t: 1687403738, i: 1 })

}

#在数据库“formyz”创建表“mytable”,基于键“_id”进行“hash”分片

[direct: mongos] admin> sh.shardCollection("formyz.mytable",{"_id":"hashed"});

{

  collectionsharded: 'formyz.mytable',

  ok: 1,

  '$clusterTime': {

    clusterTime: Timestamp({ t: 1687404504, i: 28 }),

    signature: {

      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),

      keyId: Long("0")

    }

  },

  operationTime: Timestamp({ t: 1687404504, i: 24 })

}

#数据库“formyz”的表“mytable”插入5万条记录

[direct: mongos] admin> use formyz

switched to db formyz

[direct: mongos] formyz> for(i=1;i<=50000;i++){db.usertable.insertOne({"id":i,"name":"nnn"+i})}

{

  acknowledged: true,

  insertedId: ObjectId("6493c13abcd4d10dfc6f054c")

}

数据插入完毕,继续在Mongos路由交互界面输入指令“sh.status()”,查验数据库“formyz”表“mytable”数据的分布情况,如图8-12所示。

MongoDB负载均衡集群(第8章节选)_第12张图片图8- 12

 

从状态输出可知,数据库“formyz”的数据确实分布到分片集群“shard1”和“shard2”,到达预期目标。

8.6 MongoDB集群设置权限和认证

MongoDB高可用集群已经创建完毕,分片功能已经验证通过,基于数据安全层面的考虑,需要给MongoDB数据访问设置账号、各成员节点之间启用安全认证。

8.6.1 设置MongoDB数据库管理账号

你可能感兴趣的:(mongodb,数据库)