说明

突然发现更需要的是副本集群,而不是分片式集群。

分片式集群将数据切分成了一块块,集群的每台机器上理论都不应该有完整的数据;而为了保证机器坏掉时还能够正常访问所有数据,就要做冗余:每个分片要有副本(或/和仲裁)。这样原始数据至少膨胀了3倍,而且还要协调好分片的分布(例如至少可以容忍任意两台物理机挂掉而数据不受影响)。

所以,分片集群应该面对的是海量的数据,至少10台以上的物理机部署。

目前我的业务目标是:

  • 1 机器(节点)的动态迁移
  • 2 并发查询(考虑大量查数的情况)
  • 3 分布式计算

我觉得在10个T以内的数据都不必称为大数据,用高性能台式机集群就可以处理。Mongo会对数据进行压缩,10个T的数据存储空间估计4个T左右就够了,普通的计算机,机上pci扩展卡,单机的固态很容易上10T容量。如果数据到了PB级,那么可能就要考虑分片集群了。

内容

踩了不少坑,算是还了账(之前搭建分片的过程过于顺利了)

以下是本次的架构目标图:在局域网的三台机器上启动副本集,当我们在主节点上写入时,副本集会自动进行同步。对于用户的使用来说,不必去管当前的主节点是谁,直接去读写,这时候我要观察一下读的速度是否有提升(是否会balance)。

一台宿主机可以启动多少个docker docker集群要几台机器_副本集

1 背景

Mongo的集群结构有主从、副本和分片三种形式。由于副本和主从非常相似,但是更健壮,我好像有看到文章说以后就没有主从了,使用副本。

上面已经提过,分片集群目前并不适合我用,而且构建起来更为麻烦一些。所以我打算先专心搞好副本集。

关于副本集群的介绍
好文章还是比较有帮助的:这篇不错关于Mongo副本集的介绍

里面和我相关的一些要点记录一下:

  • 1 MongoDB 的副本集是自带故障转移功能的主从复制
  • 2 一个副本集最多可以有50 个成员,但只有7 个投票成员。如果副本集已经有 7 个投票成员,则额外的成员必须是非投票成员
  • 3 Oplog的配置至少1个G(WiredTiger Storage Engine)
  • 4 参与选举的节点数量必须大于副本集总节点数量的一半,如果已经小于一半了所有节点保持只读状态(所以主节点+副本+仲裁必须为奇数)

副本成员的类型(从参考文章中截过来的),这个参考信息还是很有用的。例如:

  • 1 Secondary是最常用的副本
  • 2 Arbiter来确保可以选举
  • 3 Priority0 来确保不担任主节点
  • 4 Vote0 看起来像旁观者
  • 5 Hidden平时不会启用
  • 6 Delayed 用来做时间镜像恢复

一台宿主机可以启动多少个docker docker集群要几台机器_一台宿主机可以启动多少个docker_02

2 搭建

  • 1 程序/配置文件保存在opt目录下
  • 2 数据文件夹保存在data目录下

2.1 配置文件

本次实验集群的搭建我省去了用户的授权认证、集群成员的秘钥这些设置。
主要的配置文件如下(放在opt下面):

mongod.conf

storage:
  dbPath: /home/mongod/db #分片数据库路径
  journal:
    enabled: true
  directoryPerDB: true
 
#  engine:
#  mmapv1:
#  wiredTiger:
# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /home/mongod/log/mongod.log # 副本日志
 
# network interfaces
net:
  bindIpAll: true

 
# how the process runs
processManagement:
 fork: false 
# security:
#   keyFile: /etc/mongo.key
#  authorization: enabled

# set auth?
# setParameter:
#   enableLocalhostAuthBypass: false
 
#operationProfiling:
replication:
  oplogSizeMB: 500
  replSetName: myrs #副本集名称

2.2 数据文件

切到data路径,执行这个脚本快速创建文件夹并设置权限

create_shard_folder.sh 脚本内容

#!bin/bash
mkdir -p $1

mkdir $1/db

mkdir $1/log 

touch $1/log/mongod.log 

chmod -R 777 $1

执行(假设要创建名为replica的文件夹)

proc_path=/opt/aprojects/Mongo_Replica_24831/
data_path=/data/aprojects/Mongo_Replica_24831/

sh ${proc_path}/create_shard_folder.sh ${data_path}/replica

2.3 分别启动mongo

在m1和m7上分别启动(我使用 -it 启动,方便看他们打印出来的信息)

proc_path=/opt/aprojects/Mongo_Replica_24831/
data_path=/data/aprojects/Mongo_Replica_24831/
image_name="Mongo镜像"
port=25001

docker run -it \
 --name='mongo_rs_data' \
 --rm \
 -v ${data_path}/replica:/home/mongod \
 -v ${proc_path}replica/mongod.conf:/etc/mongod.conf \
 -p ${port}:27017 \
 ${image_name} \
 -f /etc/mongod.conf

2.4 设置集群

然后这里踩了一个坑,坑了我一天。

首先切进任意一个副本的mongo shell

docker exec -it mongo_rs_data mongo

> rs.status()
{
	"ok" : 0,
	"errmsg" : "no replset config has been received",
	"code" : 94,
	"codeName" : "NotYetInitialized"
}

此时是全新的数据库,所以不会有任何信息,然后进行初始化。这里踩的坑就是:一开始我认为可以使用add方式直接开始添加新的集群节点,但结果是我发现节点之间开始通信,但是新的节点始终处于START状态,不会进入正常状态(例如 Secondary)。

节点的流转状态如下:

- STARTUP :刚加入到复制集中,配置还未加载
- STARTUP2 :配置已加载完,初始化状态
- RECOVERING :正在恢复,不适用读
- ARBITER: 仲裁者
- DOWN :节点不可到达
- UNKNOWN :未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂
- REMOVED :移除复制集
- ROLLBACK :数据回滚,在回滚结束时,转移到 RECOVERING 或 SECONDARY 状态
- FATAL :出错。查看日志 grep “replSet FATAL” 找出错原因,重新做同步
- PRIMARY :主节点
- SECONDARY :备份节点

此时在新的节点上查看,会和之前刚进入primary的mongo shell一样,告诉你没有配置文件。然后,…, 我翻了很多很多文章也没搞明白为什么。

我的猜想是:主节点初始化的时候需要一个配置文件,我使用add语句认为mongo会自动创建一个默认的配置文件(用于分发),但实际上没有。而使用下面的语句,则会产生这样的配置文件。(并且后续再单个add节点的时候也是没问题的)。

也怪我自己没有详细了解mongo的使用吧,但我确实没那么多时间。

rs.initiate(
    {
        _id : "myrs",
        members: [
            { _id : 0, host : "192.168.0.187:25001",priority:5 },
            { _id : 1, host : "192.168.0.4:25001",priority:3 },
        ]
    })

一开始节点可能会认为自己是Secondary,但是不一会就会变成Primary

myrs:SECONDARY> rs.status()

...
	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.0.187:25001",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
...

然后我插入数据

myrs:PRIMARY> db.test.insert( { item : "card", qty : 15 })
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB

再加入一个节点

rs.add('192.168.0.4:25002')

从节点很快就转变状态了(无语),然后也能看到集群信息

myrs:SECONDARY> rs.status()

	"members" : [
		{
			"_id" : 0,
			"name" : "192.168.0.187:25001",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
...
			"_id" : 1,
			"name" : "192.168.0.4:25001",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 248,

使用命令将节点转为可读状态

myrs:SECONDARY> rs.secondaryOk()
myrs:SECONDARY> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
myrs:SECONDARY> use test;
switched to db test
myrs:SECONDARY> show collections;
test
myrs:SECONDARY> db.test.find({})
{ "_id" : ObjectId("62c64602fa53ce157f16019a"), "item" : "card", "qty" : 15 }

然后在主节点继续加了一条数据,从节点可以读到

myrs:SECONDARY> db.test.find({})
{ "_id" : ObjectId("62c64602fa53ce157f16019a"), "item" : "card", "qty" : 15 }
{ "_id" : ObjectId("62c64671fa53ce157f16019b"), "item" : "card", "qty" : 16 }

后来又用pymongo往里写了两条

myrs:SECONDARY> db.test.find({})
{ "_id" : ObjectId("62c64602fa53ce157f16019a"), "item" : "card", "qty" : 15 }
{ "_id" : ObjectId("62c64671fa53ce157f16019b"), "item" : "card", "qty" : 16 }
{ "_id" : ObjectId("62c67e1d0b1aab0341399456"), "yoyo" : "lets go" }
{ "_id" : ObjectId("62c67e1d0b1aab0341399457"), "aa" : 123 }

后来我又加入了一个节点,并且断开,查询集群信息会显示该节点不可达。

3 python操作

一开始我是这么写的,这两条数据已经在上面看到了

from pymongo import MongoClient
c = MongoClient('mongodb://192.168.0.187:25001,192.168.0.4:25001')
c['test']['test'].insert_many([{'yoyo':'lets go'}, {'aa':123}])

后来我看了看,大概这么写会更好些

client = pymongo.MongoClient(['192.168.0.187:25001,192.168.0.4:25001'],replicaset='myrs')

这个client和单机的没啥差别(事实上也是访问一个库),只不过在发生故障时会自动切换。有很多信息可以看的:

client.is_primary
True

client.primary
('192.168.0.187', 25001)

client.secondaries
{('192.168.0.4', 25001)}

client.arbiters
set()

4 Next

4.1 MongoAgent

  • 1 连接。因为MongoAgent的连接和之前不一样,所以要修改连接接口(add_a_connection)
  • 2 用户信息认证。目前是无用户密码的,之后加上(这样和单机就保持一致了)。
  • 3 集群信息的展示。

4.2 集群配置

这次不得不把线程管理设成了false,

processManagement:
 fork: false

不然会报这样的错,需要再研究一下

about to fork child process, waiting until server is ready for connections.
forked process: 23
child process started successfully, parent exiting

可以给集群再加上通信秘钥,毕竟将来会有公网可达的副本。

# security:
#   keyFile: /etc/mongo.key
#  authorization: enabled