第一次使用 MongoDB + Docker - 从 docker 撰写
First time with MongoDB + Docker - Set up from docker compose
我想尝试在 GitHub 上找到的 project,所以我在 MacOS 上安装了 MongoDB,现在我正在尝试了解如何正确设置它通过目录中的 docker 撰写文件。这是 docker 文件:
version: '3'
services:
# replica set 1
mongors1n1:
container_name: mongors1n1
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27017:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data1:/data/db
mongors1n2:
container_name: mongors1n2
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27027:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data2:/data/db
mongors1n3:
container_name: mongors1n3
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27037:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data3:/data/db
# replica set 2
mongors2n1:
container_name: mongors2n1
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27047:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data4:/data/db
mongors2n2:
container_name: mongors2n2
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27057:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data5:/data/db
mongors2n3:
container_name: mongors2n3
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27067:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data6:/data/db
# mongo config server
mongocfg1:
container_name: mongocfg1
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config1:/data/db
mongocfg2:
container_name: mongocfg2
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config2:/data/db
mongocfg3:
container_name: mongocfg3
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config3:/data/db
# mongos router
mongos1:
container_name: mongos1
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017
ports:
- 27019:27017
expose:
- "27017"
mongos2:
container_name: mongos2
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017
ports:
- 27020:27017
expose:
- "27017"
# TODO after running docker-compose
# conf = rs.config();
# conf.members[0].priority = 2;
# rs.reconfig(conf);
这是 运行 和创建分片等的脚本。:
#!/bin/sh
docker-compose up
# configure our config servers replica set
docker exec -it mongocfg1 bash -c "echo 'rs.initiate({_id: \"mongors1conf\",configsvr: true, members: [{ _id : 0, host : \"mongocfg1\" },{ _id : 1, host : \"mongocfg2\" }, { _id : 2, host : \"mongocfg3\" }]})' | mongo"
# building replica shard
docker exec -it mongors1n1 bash -c "echo 'rs.initiate({_id : \"mongors1\", members: [{ _id : 0, host : \"mongors1n1\" },{ _id : 1, host : \"mongors1n2\" },{ _id : 2, host : \"mongors1n3\" }]})' | mongo"
docker exec -it mongors2n1 bash -c "echo 'rs.initiate({_id : \"mongors2\", members: [{ _id : 0, host : \"mongors2n1\" },{ _id : 1, host : \"mongors2n2\" },{ _id : 2, host : \"mongors2n3\" }]})' | mongo"
# we add shard to the routers
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors1/mongors1n1\")' | mongo "
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors2/mongors2n1\")' | mongo "
如果我尝试直接 运行 脚本我得到错误:
mongos1 | {"t":{"$date":"2021-07-25T09:03:56.101+00:00"},"s":"I", "c":"-", "id":4333222, "ctx":"ReplicaSetMonitor-TaskExecutor","msg":"RSM received error response","attr":{"host":"mongocfg3:27017","error":"HostUnreachable: Error connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by :: Connection refused","replicaSet":"mongors1conf","response":"{}"}}
mongos1 | {"t":{"$date":"2021-07-25T09:03:56.101+00:00"},"s":"I",
"c":"NETWORK", "id":4712102,
"ctx":"ReplicaSetMonitor-TaskExecutor","msg":"Host failed in replica
set","attr":{"replicaSet":"mongors1conf","host":"mongocfg3:27017","error":{"code":6,"codeName":"HostUnreachable","errmsg":"Error
connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by ::
Connection
refused"},"action":{"dropConnections":true,"requestImmediateCheck":false,"outcome":{"host":"mongocfg3:27017","success":false,"errorMessage":"HostUnreachable:
Error connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by ::
Connection refused"}}}}
以及其他错误,例如:
mongos1 | {"t":{"$date":"2021-07-25T09:05:39.743+00:00"},"s":"I",
"c":"-", "id":4939300,
"ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key
cache","attr":{"error":"FailedToSatisfyReadPreference: Could not find
host matching read preference { mode: "nearest" } for set
mongors1conf","nextWakeupMillis":1800}}
不应该 docker 配置所有文件而不需要用户配置吗?或者我是否需要手动创建一些东西,比如数据库等?
编辑:这是我 运行 脚本时出现的第一个错误:log
所以这里尝试提供帮助。在大多数情况下,docker compose yaml 文件非常接近,除了一些次要端口和绑定参数。期望初始化将是额外的命令。示例:
- docker-搭建环境
- 运行 一些初始化环境的脚本
...但这已经是原始内容的一部分 post。
所以这是一个 docker 撰写文件
docker-compose.yml
version: '3'
services:
# mongo config server
mongocfg1:
container_name: mongocfg1
hostname: mongocfg1
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config1:/data/db
mongocfg2:
container_name: mongocfg2
hostname: mongocfg2
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config2:/data/db
mongocfg3:
container_name: mongocfg3
hostname: mongocfg3
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config3:/data/db
# replica set 1
mongors1n1:
container_name: mongors1n1
hostname: mongors1n1
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data1:/data/db
mongors1n2:
container_name: mongors1n2
hostname: mongors1n2
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data2:/data/db
mongors1n3:
container_name: mongors1n3
hostname: mongors1n3
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data3:/data/db
# replica set 2
mongors2n1:
container_name: mongors2n1
hostname: mongors2n1
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data4:/data/db
mongors2n2:
container_name: mongors2n2
hostname: mongors2n2
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data5:/data/db
mongors2n3:
container_name: mongors2n3
hostname: mongors2n3
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data6:/data/db
# mongos router
mongos1:
container_name: mongos1
hostname: mongos1
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27019,mongocfg2:27019,mongocfg3:27019 --port 27017 --bind_ip_all
ports:
- 27017:27017
mongos2:
container_name: mongos2
hostname: mongos2
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27019,mongocfg2:27019,mongocfg3:27019 --port 27017 --bind_ip_all
ports:
- 27016:27017
...和一些完成初始化的脚本...
docker-compose up -d
...给它几秒钟结束,然后发出...
# Init the replica sets (use the MONGOS host)
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id: \"mongors1conf\",configsvr: true, members: [{ _id : 0, host : \"mongocfg1:27019\", priority: 2 },{ _id : 1, host : \"mongocfg2:27019\" }, { _id : 2, host : \"mongocfg3:27019\" }]})' | mongo --host mongocfg1:27019"
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id : \"mongors1\", members: [{ _id : 0, host : \"mongors1n1:27018\", priority: 2 },{ _id : 1, host : \"mongors1n2:27018\" },{ _id : 2, host : \"mongors1n3:27018\" }]})' | mongo --host mongors1n1:27018"
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id : \"mongors2\", members: [{ _id : 0, host : \"mongors2n1:27018\", priority: 2 },{ _id : 1, host : \"mongors2n2:27018\" },{ _id : 2, host : \"mongors2n3:27018\" }]})' | mongo --host mongors2n1:27018"
...再次,给10-15秒让系统适应最近的命令...
# ADD TWO SHARDS (mongors1, and mongors2)
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n2:27018\")' | mongo"
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018\")' | mongo"
现在,尝试使用 docker 运行ning 从主机连接到 mongos(假设您已经在该主机上安装了 mongo shell主持人)。使用 2 mongo 台主机作为种子列表。
mongo --host "localhost:27017,localhost:27016"
评论
注意到在 init() 调用中如何将 node0 的优先级设置为优先级 2 了吗?
注意配置服务器都是端口 27019 - 这遵循 MongoDB 的建议。
注意分片服务器都是端口 27018 - 同样,遵循 mongo 建议。
mongos 公开了 2 个端口 27017(MongoDB 的自然端口)和端口 27016(用于高可用性的辅助 mongos)。
出于安全原因,配置服务器和分片服务器不公开其各自的端口。应该使用 mongos 来获取数据。如果出于管理目的需要打开这些端口,只需添加到 docker 撰写文件即可。
副本集相互通信未使用身份验证。这是安全禁忌。需要确定哪种身份验证机制最适合您的场景 - 可以使用密钥文件(只是副本集成员之间相同的文本文件)或 x509 证书。如果使用 x509,那么您需要在每个 docker 容器中包含 CA.cert 以供参考,以及每个服务器的单独证书以及正确的主机名对齐方式。需要为 mongod 个进程添加启动配置项以使用选择的任何一种身份验证方法。
未指定日志记录。将 mongod 和 mongos 的日志输出设置为默认位置 /var/log/mongodb/mongod.log 和 /var/log/mongodb/mongos.log 可能是有意义的。在没有指定日志记录策略的情况下,我相信 mongo 会记录到标准输出,如果 运行ning docker-compose up -d
.
超级用户:系统上还没有创建用户。通常,对于我在将其添加到分片集群之前站起来的每个副本集,我喜欢添加一个超级用户帐户 - 一个具有 root 访问权限的帐户 - 所以如果我需要在副本集级别进行管理更改,我可以。使用 docker-compose 方法,您可以从 mongo 的角度创建超级用户并执行分片集群上所需的大部分操作,但仍然 - 我喜欢让副本集用户可用。
OS 可调参数 - Mongo 喜欢占用所有系统资源。对于一个物理主机托管一堆 mongo 进程的共享生态系统,您可能需要考虑指定 wiredTiger 缓存大小等。WiredTiger 默认需要 (System Memory Size
- 1 GB) / 2。此外,将 ulimits 设置为适当的值会让您受益 - 即,每个用户 64000 个文件句柄是一个好的开始 - mongo 可能喜欢使用大量文件。另外,文件系统应该安装在有 xfs 的地方。此策略使用主机系统用户主目录作为数据库数据目录。在这里可以欢迎更周到的方法。
还有什么吗?
我确定我遗漏了什么。有什么问题可以留言,我会回复的。
更新 1
上面的 docker-compose.yml 文件缺少一些主机的主机名属性,这导致了平衡器问题,所以我编辑了 docker-compose.yml 在所有主机上包含主机名。
此外,addShard() 方法仅引用了副本集的一台主机。为了完整起见,我将其他主机添加到上述 addShard() 方法中。
按照这些步骤将产生一个全新的分片集群,但还没有用户数据库。因此,没有用户数据库被分片。因此,让我们花点时间添加一个数据库并将其分片,然后查看分片分布(A.K.A。,平衡器结果)。
我们必须通过 mongo 连接到数据库(如上所述)。此示例假定使用 mongo shell.
mongo --host "localhost:27017,localhost:27016"
Mongo 中的数据库可以通过多种方式创建。虽然没有明确的数据库创建命令,但有一个明确的创建集合命令 (db.createCollection())。我们必须首先使用 'use ' 命令设置数据库上下文...
use mydatabase
db.createCollection("mycollection")
... 但我们可以通过在不存在的集合上创建索引来创建数据库和集合,而不是使用此命令。 (如果您已经创建了集合,不用担心,下一个命令应该仍然成功)。
use mydatabase
db.mycollection.createIndex({lastName: 1, creationDate: 1})
在这个例子中,我在两个字段上创建了一个复合索引...
- 姓氏
- 创建日期
... 在尚不存在的集合上,在尚不存在的数据库上。一旦我发出这个命令,数据库和集合都将被创建。此外,我现在有了分片键的基础——分片分布将基于的键。该分片键将基于具有这两个字段的新索引。
分片数据库
假设我已经发出了 createIndex 命令,我现在可以在数据库上打开分片并发出 shardCollection 命令...
sh.enableSharding("mydatabase")
sh.shardCollection("mydatabase.mycollection", { "lastName": 1, "creationDate": 1})
注意命令 'shardCollection()' 是如何引用我们之前创建的索引字段的?假设已成功应用分片,我们现在可以通过发出 sh.status() 命令
查看数据分布
sh.status()
输出示例:(新集合,还没有数据,因此没有真正的数据分布 - 需要插入超过 64MB 的数据,以便有不止一个块要分布)
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("6101c030a98b2cc106034695")
}
shards:
{ "_id" : "mongors1", "host" : "mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504744, 1) }
{ "_id" : "mongors2", "host" : "mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504753, 1) }
active mongoses:
"5.0.1" : 2
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
{ "_id" : "mydatabase", "primary" : "mongors2", "partitioned" : true, "version" : { "uuid" : UUID("bc890722-00c6-4cbe-a3e1-eab9692faf93"), "timestamp" : Timestamp(1627504768, 2), "lastMod" : 1 } }
mydatabase.mycollection
shard key: { "lastName" : 1, "creationDate" : 1 }
unique: false
balancing: true
chunks:
mongors2 1
{ "lastName" : { "$minKey" : 1 }, "creationDate" : { "$minKey" : 1 } } -->> { "lastName" : { "$maxKey" : 1 }, "creationDate" : { "$maxKey" : 1 } } on : mongors2 Timestamp(1, 0)
插入一些数据
为了测试分片,我们可以添加一些测试数据。同样,我们要按 lastName 和 creationDate 进行分发。
在mongoshell中我们可以运行javascript。这是一个脚本,它将创建测试记录,以便拆分和平衡数据。这将创建 500,000 个假记录。我们需要超过 64MB 的数据来创建另一个块来平衡。 500,000 条记录将产生大约。 5块。这需要几分钟 运行 并完成。
use mydatabase
function randomInteger(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function randomAlphaNumeric(length) {
var result = [];
var characters = 'abcdef0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));
}
return result.join('');
}
function generateDocument() {
return {
lastName: randomAlphaNumeric(8),
creationDate: new Date(),
stringFixedLength: randomAlphaNumeric(8),
stringVariableLength: randomAlphaNumeric(randomInteger(5, 50)),
integer1: NumberInt(randomInteger(0, 2000000)),
long1: NumberLong(randomInteger(0, 100000000)),
date1: new Date(),
guid1: new UUID()
};
}
for (var j = 0; j < 500; j++) {
var batch=[];
for (var i = 0; i < 1000; i++) {
batch.push(
{insertOne: {
document: generateDocument()
}
}
);
}
db.mycollection.bulkWrite(batch, {ordered: false});
}
请花几分钟时间查看 mongoshell,如果我们现在查看分片状态,我们应该会看到块分布在两个分片中...
sh.status()
...我们应该看到类似于...
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("6101c030a98b2cc106034695")
}
shards:
{ "_id" : "mongors1", "host" : "mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504744, 1) }
{ "_id" : "mongors2", "host" : "mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504753, 1) }
active mongoses:
"5.0.1" : 2
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes
Collections with active migrations:
config.system.sessions started at Wed Jul 28 2021 20:44:25 GMT+0000 (UTC)
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
60 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
mongors1 965
mongors2 59
too many chunks to print, use verbose if you want to force print
{ "_id" : "mydatabase", "primary" : "mongors2", "partitioned" : true, "version" : { "uuid" : UUID("bc890722-00c6-4cbe-a3e1-eab9692faf93"), "timestamp" : Timestamp(1627504768, 2), "lastMod" : 1 } }
mydatabase.mycollection
shard key: { "lastName" : 1, "creationDate" : 1 }
unique: false
balancing: true
chunks:
mongors1 2
mongors2 3
{ "lastName" : { "$minKey" : 1 }, "creationDate" : { "$minKey" : 1 } } -->> {
"lastName" : "00001276",
"creationDate" : ISODate("2021-07-28T20:42:00.867Z")
} on : mongors1 Timestamp(2, 0)
{
"lastName" : "00001276",
"creationDate" : ISODate("2021-07-28T20:42:00.867Z")
} -->> {
"lastName" : "623292c2",
"creationDate" : ISODate("2021-07-28T20:42:01.046Z")
} on : mongors1 Timestamp(3, 0)
{
"lastName" : "623292c2",
"creationDate" : ISODate("2021-07-28T20:42:01.046Z")
} -->> {
"lastName" : "c3f2a99a",
"creationDate" : ISODate("2021-07-28T20:42:06.474Z")
} on : mongors2 Timestamp(3, 1)
{
"lastName" : "c3f2a99a",
"creationDate" : ISODate("2021-07-28T20:42:06.474Z")
} -->> {
"lastName" : "ed75c36c",
"creationDate" : ISODate("2021-07-28T20:42:03.984Z")
} on : mongors2 Timestamp(1, 6)
{
"lastName" : "ed75c36c",
"creationDate" : ISODate("2021-07-28T20:42:03.984Z")
} -->> { "lastName" : { "$maxKey" : 1 }, "creationDate" : { "$maxKey" : 1 } } on : mongors2 Timestamp(2, 1)
...在这里我们可以看到平衡活动的证据。请参阅 mongors1 和 mongors2 的标签“块”。在平衡我们的测试集合的同时,它还预拆分和平衡会话数据的不同集合。我相信这是一次性系统自动化。
希望这些细节对您有所帮助。如果您还有其他问题,请告诉我。
我想尝试在 GitHub 上找到的 project,所以我在 MacOS 上安装了 MongoDB,现在我正在尝试了解如何正确设置它通过目录中的 docker 撰写文件。这是 docker 文件:
version: '3'
services:
# replica set 1
mongors1n1:
container_name: mongors1n1
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27017:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data1:/data/db
mongors1n2:
container_name: mongors1n2
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27027:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data2:/data/db
mongors1n3:
container_name: mongors1n3
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27017
ports:
- 27037:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data3:/data/db
# replica set 2
mongors2n1:
container_name: mongors2n1
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27047:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data4:/data/db
mongors2n2:
container_name: mongors2n2
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27057:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data5:/data/db
mongors2n3:
container_name: mongors2n3
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27017
ports:
- 27067:27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/data6:/data/db
# mongo config server
mongocfg1:
container_name: mongocfg1
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config1:/data/db
mongocfg2:
container_name: mongocfg2
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config2:/data/db
mongocfg3:
container_name: mongocfg3
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27017
expose:
- "27017"
volumes:
- ~/mongo_cluster/config3:/data/db
# mongos router
mongos1:
container_name: mongos1
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017
ports:
- 27019:27017
expose:
- "27017"
mongos2:
container_name: mongos2
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27017,mongocfg2:27017,mongocfg3:27017 --port 27017
ports:
- 27020:27017
expose:
- "27017"
# TODO after running docker-compose
# conf = rs.config();
# conf.members[0].priority = 2;
# rs.reconfig(conf);
这是 运行 和创建分片等的脚本。:
#!/bin/sh
docker-compose up
# configure our config servers replica set
docker exec -it mongocfg1 bash -c "echo 'rs.initiate({_id: \"mongors1conf\",configsvr: true, members: [{ _id : 0, host : \"mongocfg1\" },{ _id : 1, host : \"mongocfg2\" }, { _id : 2, host : \"mongocfg3\" }]})' | mongo"
# building replica shard
docker exec -it mongors1n1 bash -c "echo 'rs.initiate({_id : \"mongors1\", members: [{ _id : 0, host : \"mongors1n1\" },{ _id : 1, host : \"mongors1n2\" },{ _id : 2, host : \"mongors1n3\" }]})' | mongo"
docker exec -it mongors2n1 bash -c "echo 'rs.initiate({_id : \"mongors2\", members: [{ _id : 0, host : \"mongors2n1\" },{ _id : 1, host : \"mongors2n2\" },{ _id : 2, host : \"mongors2n3\" }]})' | mongo"
# we add shard to the routers
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors1/mongors1n1\")' | mongo "
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors2/mongors2n1\")' | mongo "
如果我尝试直接 运行 脚本我得到错误:
mongos1 | {"t":{"$date":"2021-07-25T09:03:56.101+00:00"},"s":"I", "c":"-", "id":4333222, "ctx":"ReplicaSetMonitor-TaskExecutor","msg":"RSM received error response","attr":{"host":"mongocfg3:27017","error":"HostUnreachable: Error connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by :: Connection refused","replicaSet":"mongors1conf","response":"{}"}}
mongos1 | {"t":{"$date":"2021-07-25T09:03:56.101+00:00"},"s":"I", "c":"NETWORK", "id":4712102, "ctx":"ReplicaSetMonitor-TaskExecutor","msg":"Host failed in replica set","attr":{"replicaSet":"mongors1conf","host":"mongocfg3:27017","error":{"code":6,"codeName":"HostUnreachable","errmsg":"Error connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by :: Connection refused"},"action":{"dropConnections":true,"requestImmediateCheck":false,"outcome":{"host":"mongocfg3:27017","success":false,"errorMessage":"HostUnreachable: Error connecting to mongocfg3:27017 (172.18.0.2:27017) :: caused by :: Connection refused"}}}}
以及其他错误,例如:
mongos1 | {"t":{"$date":"2021-07-25T09:05:39.743+00:00"},"s":"I", "c":"-", "id":4939300, "ctx":"monitoring-keys-for-HMAC","msg":"Failed to refresh key cache","attr":{"error":"FailedToSatisfyReadPreference: Could not find host matching read preference { mode: "nearest" } for set mongors1conf","nextWakeupMillis":1800}}
不应该 docker 配置所有文件而不需要用户配置吗?或者我是否需要手动创建一些东西,比如数据库等?
编辑:这是我 运行 脚本时出现的第一个错误:log
所以这里尝试提供帮助。在大多数情况下,docker compose yaml 文件非常接近,除了一些次要端口和绑定参数。期望初始化将是额外的命令。示例:
- docker-搭建环境
- 运行 一些初始化环境的脚本
...但这已经是原始内容的一部分 post。
所以这是一个 docker 撰写文件
docker-compose.yml
version: '3'
services:
# mongo config server
mongocfg1:
container_name: mongocfg1
hostname: mongocfg1
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config1:/data/db
mongocfg2:
container_name: mongocfg2
hostname: mongocfg2
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config2:/data/db
mongocfg3:
container_name: mongocfg3
hostname: mongocfg3
image: mongo
command: mongod --configsvr --replSet mongors1conf --dbpath /data/db --port 27019 --bind_ip_all
volumes:
- ~/mongo_cluster/config3:/data/db
# replica set 1
mongors1n1:
container_name: mongors1n1
hostname: mongors1n1
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data1:/data/db
mongors1n2:
container_name: mongors1n2
hostname: mongors1n2
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data2:/data/db
mongors1n3:
container_name: mongors1n3
hostname: mongors1n3
image: mongo
command: mongod --shardsvr --replSet mongors1 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data3:/data/db
# replica set 2
mongors2n1:
container_name: mongors2n1
hostname: mongors2n1
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data4:/data/db
mongors2n2:
container_name: mongors2n2
hostname: mongors2n2
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data5:/data/db
mongors2n3:
container_name: mongors2n3
hostname: mongors2n3
image: mongo
command: mongod --shardsvr --replSet mongors2 --dbpath /data/db --port 27018 --bind_ip_all
volumes:
- ~/mongo_cluster/data6:/data/db
# mongos router
mongos1:
container_name: mongos1
hostname: mongos1
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27019,mongocfg2:27019,mongocfg3:27019 --port 27017 --bind_ip_all
ports:
- 27017:27017
mongos2:
container_name: mongos2
hostname: mongos2
image: mongo
depends_on:
- mongocfg1
- mongocfg2
command: mongos --configdb mongors1conf/mongocfg1:27019,mongocfg2:27019,mongocfg3:27019 --port 27017 --bind_ip_all
ports:
- 27016:27017
...和一些完成初始化的脚本...
docker-compose up -d
...给它几秒钟结束,然后发出...
# Init the replica sets (use the MONGOS host)
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id: \"mongors1conf\",configsvr: true, members: [{ _id : 0, host : \"mongocfg1:27019\", priority: 2 },{ _id : 1, host : \"mongocfg2:27019\" }, { _id : 2, host : \"mongocfg3:27019\" }]})' | mongo --host mongocfg1:27019"
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id : \"mongors1\", members: [{ _id : 0, host : \"mongors1n1:27018\", priority: 2 },{ _id : 1, host : \"mongors1n2:27018\" },{ _id : 2, host : \"mongors1n3:27018\" }]})' | mongo --host mongors1n1:27018"
docker exec -it mongos1 bash -c "echo 'rs.initiate({_id : \"mongors2\", members: [{ _id : 0, host : \"mongors2n1:27018\", priority: 2 },{ _id : 1, host : \"mongors2n2:27018\" },{ _id : 2, host : \"mongors2n3:27018\" }]})' | mongo --host mongors2n1:27018"
...再次,给10-15秒让系统适应最近的命令...
# ADD TWO SHARDS (mongors1, and mongors2)
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n2:27018\")' | mongo"
docker exec -it mongos1 bash -c "echo 'sh.addShard(\"mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018\")' | mongo"
现在,尝试使用 docker 运行ning 从主机连接到 mongos(假设您已经在该主机上安装了 mongo shell主持人)。使用 2 mongo 台主机作为种子列表。
mongo --host "localhost:27017,localhost:27016"
评论
注意到在 init() 调用中如何将 node0 的优先级设置为优先级 2 了吗?
注意配置服务器都是端口 27019 - 这遵循 MongoDB 的建议。
注意分片服务器都是端口 27018 - 同样,遵循 mongo 建议。
mongos 公开了 2 个端口 27017(MongoDB 的自然端口)和端口 27016(用于高可用性的辅助 mongos)。
出于安全原因,配置服务器和分片服务器不公开其各自的端口。应该使用 mongos 来获取数据。如果出于管理目的需要打开这些端口,只需添加到 docker 撰写文件即可。
副本集相互通信未使用身份验证。这是安全禁忌。需要确定哪种身份验证机制最适合您的场景 - 可以使用密钥文件(只是副本集成员之间相同的文本文件)或 x509 证书。如果使用 x509,那么您需要在每个 docker 容器中包含 CA.cert 以供参考,以及每个服务器的单独证书以及正确的主机名对齐方式。需要为 mongod 个进程添加启动配置项以使用选择的任何一种身份验证方法。
未指定日志记录。将 mongod 和 mongos 的日志输出设置为默认位置 /var/log/mongodb/mongod.log 和 /var/log/mongodb/mongos.log 可能是有意义的。在没有指定日志记录策略的情况下,我相信 mongo 会记录到标准输出,如果 运行ning docker-compose up -d
.
超级用户:系统上还没有创建用户。通常,对于我在将其添加到分片集群之前站起来的每个副本集,我喜欢添加一个超级用户帐户 - 一个具有 root 访问权限的帐户 - 所以如果我需要在副本集级别进行管理更改,我可以。使用 docker-compose 方法,您可以从 mongo 的角度创建超级用户并执行分片集群上所需的大部分操作,但仍然 - 我喜欢让副本集用户可用。
OS 可调参数 - Mongo 喜欢占用所有系统资源。对于一个物理主机托管一堆 mongo 进程的共享生态系统,您可能需要考虑指定 wiredTiger 缓存大小等。WiredTiger 默认需要 (System Memory Size
- 1 GB) / 2。此外,将 ulimits 设置为适当的值会让您受益 - 即,每个用户 64000 个文件句柄是一个好的开始 - mongo 可能喜欢使用大量文件。另外,文件系统应该安装在有 xfs 的地方。此策略使用主机系统用户主目录作为数据库数据目录。在这里可以欢迎更周到的方法。
还有什么吗?
我确定我遗漏了什么。有什么问题可以留言,我会回复的。
更新 1
上面的 docker-compose.yml 文件缺少一些主机的主机名属性,这导致了平衡器问题,所以我编辑了 docker-compose.yml 在所有主机上包含主机名。
此外,addShard() 方法仅引用了副本集的一台主机。为了完整起见,我将其他主机添加到上述 addShard() 方法中。
按照这些步骤将产生一个全新的分片集群,但还没有用户数据库。因此,没有用户数据库被分片。因此,让我们花点时间添加一个数据库并将其分片,然后查看分片分布(A.K.A。,平衡器结果)。
我们必须通过 mongo 连接到数据库(如上所述)。此示例假定使用 mongo shell.
mongo --host "localhost:27017,localhost:27016"
Mongo 中的数据库可以通过多种方式创建。虽然没有明确的数据库创建命令,但有一个明确的创建集合命令 (db.createCollection())。我们必须首先使用 'use ' 命令设置数据库上下文...
use mydatabase
db.createCollection("mycollection")
... 但我们可以通过在不存在的集合上创建索引来创建数据库和集合,而不是使用此命令。 (如果您已经创建了集合,不用担心,下一个命令应该仍然成功)。
use mydatabase
db.mycollection.createIndex({lastName: 1, creationDate: 1})
在这个例子中,我在两个字段上创建了一个复合索引...
- 姓氏
- 创建日期
... 在尚不存在的集合上,在尚不存在的数据库上。一旦我发出这个命令,数据库和集合都将被创建。此外,我现在有了分片键的基础——分片分布将基于的键。该分片键将基于具有这两个字段的新索引。
分片数据库
假设我已经发出了 createIndex 命令,我现在可以在数据库上打开分片并发出 shardCollection 命令...
sh.enableSharding("mydatabase")
sh.shardCollection("mydatabase.mycollection", { "lastName": 1, "creationDate": 1})
注意命令 'shardCollection()' 是如何引用我们之前创建的索引字段的?假设已成功应用分片,我们现在可以通过发出 sh.status() 命令
查看数据分布sh.status()
输出示例:(新集合,还没有数据,因此没有真正的数据分布 - 需要插入超过 64MB 的数据,以便有不止一个块要分布)
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("6101c030a98b2cc106034695")
}
shards:
{ "_id" : "mongors1", "host" : "mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504744, 1) }
{ "_id" : "mongors2", "host" : "mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504753, 1) }
active mongoses:
"5.0.1" : 2
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
{ "_id" : "mydatabase", "primary" : "mongors2", "partitioned" : true, "version" : { "uuid" : UUID("bc890722-00c6-4cbe-a3e1-eab9692faf93"), "timestamp" : Timestamp(1627504768, 2), "lastMod" : 1 } }
mydatabase.mycollection
shard key: { "lastName" : 1, "creationDate" : 1 }
unique: false
balancing: true
chunks:
mongors2 1
{ "lastName" : { "$minKey" : 1 }, "creationDate" : { "$minKey" : 1 } } -->> { "lastName" : { "$maxKey" : 1 }, "creationDate" : { "$maxKey" : 1 } } on : mongors2 Timestamp(1, 0)
插入一些数据
为了测试分片,我们可以添加一些测试数据。同样,我们要按 lastName 和 creationDate 进行分发。
在mongoshell中我们可以运行javascript。这是一个脚本,它将创建测试记录,以便拆分和平衡数据。这将创建 500,000 个假记录。我们需要超过 64MB 的数据来创建另一个块来平衡。 500,000 条记录将产生大约。 5块。这需要几分钟 运行 并完成。
use mydatabase
function randomInteger(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function randomAlphaNumeric(length) {
var result = [];
var characters = 'abcdef0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));
}
return result.join('');
}
function generateDocument() {
return {
lastName: randomAlphaNumeric(8),
creationDate: new Date(),
stringFixedLength: randomAlphaNumeric(8),
stringVariableLength: randomAlphaNumeric(randomInteger(5, 50)),
integer1: NumberInt(randomInteger(0, 2000000)),
long1: NumberLong(randomInteger(0, 100000000)),
date1: new Date(),
guid1: new UUID()
};
}
for (var j = 0; j < 500; j++) {
var batch=[];
for (var i = 0; i < 1000; i++) {
batch.push(
{insertOne: {
document: generateDocument()
}
}
);
}
db.mycollection.bulkWrite(batch, {ordered: false});
}
请花几分钟时间查看 mongoshell,如果我们现在查看分片状态,我们应该会看到块分布在两个分片中...
sh.status()
...我们应该看到类似于...
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("6101c030a98b2cc106034695")
}
shards:
{ "_id" : "mongors1", "host" : "mongors1/mongors1n1:27018,mongors1n2:27018,mongors1n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504744, 1) }
{ "_id" : "mongors2", "host" : "mongors2/mongors2n1:27018,mongors2n2:27018,mongors2n3:27018", "state" : 1, "topologyTime" : Timestamp(1627504753, 1) }
active mongoses:
"5.0.1" : 2
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: yes
Collections with active migrations:
config.system.sessions started at Wed Jul 28 2021 20:44:25 GMT+0000 (UTC)
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
60 : Success
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
mongors1 965
mongors2 59
too many chunks to print, use verbose if you want to force print
{ "_id" : "mydatabase", "primary" : "mongors2", "partitioned" : true, "version" : { "uuid" : UUID("bc890722-00c6-4cbe-a3e1-eab9692faf93"), "timestamp" : Timestamp(1627504768, 2), "lastMod" : 1 } }
mydatabase.mycollection
shard key: { "lastName" : 1, "creationDate" : 1 }
unique: false
balancing: true
chunks:
mongors1 2
mongors2 3
{ "lastName" : { "$minKey" : 1 }, "creationDate" : { "$minKey" : 1 } } -->> {
"lastName" : "00001276",
"creationDate" : ISODate("2021-07-28T20:42:00.867Z")
} on : mongors1 Timestamp(2, 0)
{
"lastName" : "00001276",
"creationDate" : ISODate("2021-07-28T20:42:00.867Z")
} -->> {
"lastName" : "623292c2",
"creationDate" : ISODate("2021-07-28T20:42:01.046Z")
} on : mongors1 Timestamp(3, 0)
{
"lastName" : "623292c2",
"creationDate" : ISODate("2021-07-28T20:42:01.046Z")
} -->> {
"lastName" : "c3f2a99a",
"creationDate" : ISODate("2021-07-28T20:42:06.474Z")
} on : mongors2 Timestamp(3, 1)
{
"lastName" : "c3f2a99a",
"creationDate" : ISODate("2021-07-28T20:42:06.474Z")
} -->> {
"lastName" : "ed75c36c",
"creationDate" : ISODate("2021-07-28T20:42:03.984Z")
} on : mongors2 Timestamp(1, 6)
{
"lastName" : "ed75c36c",
"creationDate" : ISODate("2021-07-28T20:42:03.984Z")
} -->> { "lastName" : { "$maxKey" : 1 }, "creationDate" : { "$maxKey" : 1 } } on : mongors2 Timestamp(2, 1)
...在这里我们可以看到平衡活动的证据。请参阅 mongors1 和 mongors2 的标签“块”。在平衡我们的测试集合的同时,它还预拆分和平衡会话数据的不同集合。我相信这是一次性系统自动化。
希望这些细节对您有所帮助。如果您还有其他问题,请告诉我。