状态: 已弃用
本文介绍了不再受支持的 Ubuntu 版本。 如果您当前正在运行运行 Ubuntu 12.04 的服务器,我们强烈建议您升级或迁移到受支持的 Ubuntu 版本:
原因: Ubuntu 12.04 已于 2017 年 4 月 28 日终止生命周期 (EOL) and no longer receives security patches or updates. This guide is no longer maintained.
请参阅: 本指南可能仍可用作参考,但可能不适用于其他 Ubuntu 版本。 如果可用,我们强烈建议使用为您正在使用的 Ubuntu 版本编写的指南。 您可以使用页面顶部的搜索功能来查找更新的版本。
介绍
MongoDB是一个NoSQL文档数据库系统,可以很好地横向扩展,通过key-value系统实现数据存储。 作为 Web 应用程序和网站的流行选择,MongoDB 易于以编程方式实现和访问。
MongoDB 通过一种称为“分片”的技术实现扩展。 分片是跨不同服务器写入数据以分配读写负载和数据存储需求的过程。
在之前的教程中,我们介绍了 如何在 Ubuntu 12.04 VPS 上安装 MongoDB。 我们将以此为起点来讨论如何跨多个不同节点实现分片。
MongoDB 分片拓扑
分片是通过三个独立的组件实现的。 每个部分执行特定的功能:
Config Server:每个生产分片实现必须包含三个配置服务器。 这是为了确保冗余和高可用性。
配置服务器用于存储将请求数据与包含它的分片链接的元数据。 它组织数据,以便可以可靠且一致地检索信息。
查询路由器:查询路由器是您的应用程序实际连接的机器。 这些机器负责与配置服务器通信,以确定所请求数据的存储位置。 然后它从适当的分片访问并返回数据。
每个查询路由器都运行“mongos”命令。
Shard Servers:分片负责实际的数据存储操作。 在生产环境中,单个分片通常由副本集而不是单个机器组成。 这是为了确保在主分片服务器离线的情况下仍然可以访问数据。
实现复制集超出了本教程的范围,因此我们将分片配置为单机而不是复制集。 如果您想为您自己的配置 配置副本集 ,您可以轻松地修改它。
初始设置
如果您在上面注意过,您可能会注意到此配置需要相当多的机器。 在本教程中,我们将配置一个示例分片集群,其中包含:
- 3 个配置服务器(生产环境中需要)
- 2 个查询路由器(至少需要 1 个)
- 4 个分片服务器(至少需要 2 个)
这意味着您将需要 9 个 VPS 实例才能完全遵循。 实际上,其中一些功能可以重叠(例如,您可以在用作配置服务器的同一 VPS 上运行查询路由器)并且您只需要一个查询路由器和至少 2 个分片服务器。
我们将超过这个最小值,以演示添加每种类型的多个组件。 为了清楚和简单起见,我们还将所有这些组件视为离散机器。
设置初始基本图像
首先,使用本指南在 Ubuntu 上安装和配置初始 MongoDB 服务器。 我们将使用它来引导其余的分片组件。
完成第一台服务器的教程后,使用以下命令关闭实例:
sudo shutdown -h now
现在,我们将拍摄这个配置的 Droplet 的快照,并使用它来启动我们的其他 VPS 实例。 虽然可以对正在运行的系统进行快照,但关闭电源可确保文件系统处于一致状态。 快照的成本为每月每 GB 0.05 美元,具体取决于文件系统中的已用空间量,因此最好在完成后删除快照。
在您的 DigitalOcean 控制面板中,选择水滴。 单击“快照”选项卡。 输入快照名称,然后单击“拍摄快照”:
将拍摄您的快照并重新启动初始服务器。
基于快照启动 VPS 实例
现在我们已经通过快照过程保存了一个图像,我们可以将其用作其余 MongoDB 组件的基础。
在控制面板中,单击“创建”按钮。 输入描述您的 Droplet 在分片配置中的用途的名称:
选择液滴大小和区域。 最好为所有组件选择相同的区域。
在“选择图像”部分下,单击“我的图像”选项卡并选择您刚刚创建的 MongoDB 快照。
添加您需要的任何 SSH 密钥并选择您想要使用的设置。 单击“创建 Droplet”以启动您的新 VPS 实例。
对每个分片组件重复此步骤。 请记住,要完全按照本教程进行操作(不是必需的,但可以演示),您需要 3 个配置服务器、2 个查询服务器和 4 个分片服务器。
为每个组件配置 DNS 子域条目(可选)
MongoDB 文档建议您使用 DNS 可解析名称而不是特定 IP 地址来引用所有组件。 这很重要,因为它允许您更改服务器或重新部署某些组件,而无需重新启动与之关联的每个服务器。
为了便于使用,我建议您在您希望使用的域上为每台服务器提供自己的子域。 您可以使用本指南学习 如何使用 DigitalOcean 的控制面板 设置 DNS 子域。
出于本教程的目的,我们将这些组件称为可在这些子域中访问的组件:
- 配置服务器
- config0.example.com
- config1.example.com
- config2.example.com
- 查询路由器
- query0.example.com
- query1.example.com
- 分片服务器
- shard0.example.com
- shard1.example.com
- shard2.example.com
- shard3.example.com
如果您不设置子域,您仍然可以继续操作,但您的配置不会那么健壮。 如果您想走这条路,只需将子域规范替换为您的 Droplet 的 IP 地址。
初始化配置服务器
必须设置的第一个组件是配置服务器。 在配置查询路由器或分片之前,这些必须在线且可操作。
以 root 身份登录到您的第一个配置服务器。
我们需要做的第一件事是创建一个数据目录,配置服务器将在其中存储关联位置和内容的元数据:
mkdir /mongo-metadata
现在,我们只需使用适当的参数启动配置服务器。 提供配置服务器的服务称为mongod
。 此组件的默认端口号为 27019
。
我们可以使用以下命令启动配置服务器:
mongod --configsvr --dbpath /mongo-metadata --port 27019
服务器将开始输出信息并开始侦听来自其他组件的连接。
在其他两个配置服务器上完全重复此过程。 所有三台服务器的端口号应该相同。
配置查询路由器实例
此时,您应该让所有三个配置服务器都在运行并侦听连接。 在继续之前,它们必须是可操作的。
以 root 身份登录到您的第一个查询路由器。
我们需要做的第一件事是停止该实例上的 mongodb
进程(如果它已经在运行)。 查询路由器使用与 MongoDB 主进程冲突的数据锁:
service mongodb stop
接下来,我们需要使用特定的配置字符串启动查询路由器服务。 对于您配置的每个查询路由器,配置字符串必须完全相同(包括参数的顺序)。 它由每个配置服务器的地址和它正在运行的端口号组成,用逗号分隔。
他们查询路由器服务称为mongos
。 该进程的默认端口号为27017
(但配置中的端口号指的是配置服务器端口号,默认为27019
)。
最终结果是查询路由器服务以如下字符串启动:
mongos --configdb config0.example.com :27019, config1.example.com :27019, config2.example.com :27019
您的第一个查询路由器应该开始连接到三个配置服务器。 在另一个查询路由器上重复这些步骤。 请记住,在键入命令之前必须停止 mongodb
服务。
另外,请记住,必须使用 exact 相同的命令来启动每个查询路由器。 不这样做将导致错误。
将分片添加到集群
现在我们已经配置了配置服务器和查询路由器,我们可以开始将实际的分片服务器添加到我们的集群中。 这些分片将各自保存总数据的一部分。
以 root 身份登录您的其中一台分片服务器。
正如我们在开头提到的,在本指南中,我们将只使用单机分片而不是副本集。 这是为了演示的简洁和简单。 在生产环境中,强烈建议使用副本集,以确保数据的完整性和可用性。 要在 MongoDB 中 配置副本集,请遵循本指南。
要真正将分片添加到集群,我们需要通过查询路由器,这些路由器现在被配置为我们与集群的接口。 我们可以通过连接到查询路由器的 any 来做到这一点,如下所示:
mongo --host query0.example.com --port 27017
这将连接到适当的查询路由器并打开一个 mongo 提示符。 我们将从此提示添加所有分片服务器。
要添加我们的第一个分片,请键入:
sh.addShard(“ shard0.example.com:27017 ”)
然后,您可以在同一界面中添加剩余的碎片液滴。 您不需要单独登录每个分片服务器。
sh.addShard(“ shard1.example.com:27017 ”) sh.addShard(“ shard2.example.com:27017 ”) sh.addShard(“ shard3.example.com:27017 ”)
如果您正在配置生产集群,并带有复制集,则必须指定复制集名称和复制集成员以将每个集建立为不同的分片。 语法看起来像这样:
sh.addShard(“ rep_set_name / rep_set_member :27017”)
如何为数据库集合启用分片
MongoDB 将信息组织到数据库中。 在每个数据库内部,数据通过“集合”进一步划分。 集合类似于传统关系数据库模型中的表。
在本节中,我们将再次使用查询路由器进行操作。 如果您还没有连接到查询路由器,您可以使用上一节中使用的相同 mongo 命令再次访问它:
mongo --host config0.example.com --port 27017
在数据库级别启用分片
我们将首先在数据库级别启用分片。 为此,我们将创建一个名为(适当地)test_db
的测试数据库。
要创建这个数据库,我们只需要更改它。 当我们第一次向其中输入数据时,它将被标记为我们当前的数据库并动态创建:
use test_db
我们可以通过键入以下内容来检查我们当前是否正在使用我们刚刚创建的数据库:
db
test_db
我们可以通过键入以下内容查看所有可用的数据库:
show dbs
您可能会注意到我们刚刚创建的数据库没有显示出来。 这是因为它没有数据,所以它还不是很真实。
我们可以通过发出以下命令在该数据库上启用分片:
sh.enableSharding("test_db")
同样,如果我们输入 show dbs
命令,我们将看不到我们的新数据库。 但是,如果我们切换到自动生成的 config
数据库,并发出 find()
命令,将返回我们的新数据库:
use config db.databases.find()
{ "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "test_db", "partitioned" : true, "primary" : "shard0003" }
当 MongoDB 将一些数据添加到新数据库时,您的数据库将显示 show dbs
命令。
在集合级别启用分片
现在我们的数据库被标记为可用于分片,我们可以在特定集合上启用分片。
此时,我们需要决定分片策略。 分片的工作原理是根据其存储的文档中指定为 shard key
的特定字段将数据组织成不同的类别。 它将所有具有匹配分片键的文档放在同一个分片上。
例如,如果您的数据库存储公司的员工,并且您的分片键基于最喜欢的颜色,那么 MongoDB 会将所有在最喜欢的颜色字段中带有 blue
的员工放在一个分片上。 如果每个人都喜欢几种颜色,这可能会导致存储不成比例。
片键的更好选择是保证分布更均匀的东西。 例如,在一家大公司中,生日(月和日)字段可能会相当均匀地分布。
如果您不确定事物将如何分布,或者没有合适的字段,您可以基于现有字段创建“散列”分片键。 这就是我们将为我们的数据做的事情。
我们可以创建一个名为 test_collection
的集合并对其“_id”字段进行哈希处理。 确保我们正在使用我们的 test_db 数据库,然后发出命令:
use test_db db.test_collection.ensureIndex( { _id : "hashed" } )
然后,我们可以通过发出以下命令对集合进行分片:
sh.shardCollection("test_db.test_collection", { "_id": "hashed" } )
这将在所有可用分片中对集合进行分片。
将测试数据插入集合
我们可以通过使用循环创建一些对象来查看我们的分片。 这个循环直接来自MongoDB网站,用于生成测试数据。
我们可以使用这样的简单循环将数据插入到集合中:
use test_db for (var i = 1; i <= 500; i++) db.test_collection.insert( { x : i } )
这将创建 500 个简单文档(只有一个 ID 字段和一个包含数字的“x”字段)并将它们分布在不同的分片中。 您可以通过键入以下内容查看结果:
db.test_collection.find()
{ "_id" : ObjectId("529d082c488a806798cc30d3"), "x" : 6 } { "_id" : ObjectId("529d082c488a806798cc30d0"), "x" : 3 } { "_id" : ObjectId("529d082c488a806798cc30d2"), "x" : 5 } { "_id" : ObjectId("529d082c488a806798cc30ce"), "x" : 1 } { "_id" : ObjectId("529d082c488a806798cc30d6"), "x" : 9 } { "_id" : ObjectId("529d082c488a806798cc30d1"), "x" : 4 } { "_id" : ObjectId("529d082c488a806798cc30d8"), "x" : 11 } . . .
要获取更多值,请键入:
it
{ "_id" : ObjectId("529d082c488a806798cc30cf"), "x" : 2 } { "_id" : ObjectId("529d082c488a806798cc30dd"), "x" : 16 } { "_id" : ObjectId("529d082c488a806798cc30d4"), "x" : 7 } { "_id" : ObjectId("529d082c488a806798cc30da"), "x" : 13 } { "_id" : ObjectId("529d082c488a806798cc30d5"), "x" : 8 } { "_id" : ObjectId("529d082c488a806798cc30de"), "x" : 17 } { "_id" : ObjectId("529d082c488a806798cc30db"), "x" : 14 } { "_id" : ObjectId("529d082c488a806798cc30e1"), "x" : 20 } . . .
要获取有关特定分片的信息,您可以键入:
sh.status()
--- Sharding Status --- sharding version: { "_id" : 1, "version" : 3, "minCompatibleVersion" : 3, "currentVersion" : 4, "clusterId" : ObjectId("529cae0691365bef9308cd75") } shards: { "_id" : "shard0000", "host" : "162.243.243.156:27017" } { "_id" : "shard0001", "host" : "162.243.243.155:27017" } . . .
这将提供有关 MongoDB 在分片之间分布的块的信息。
结论
在本指南结束时,您应该能够实现自己的 MongoDB 分片配置。 您的服务器的特定配置和您为每个集合选择的分片键将对集群的性能产生很大影响。
选择具有最佳分布属性并且最能代表将反映在数据库查询中的逻辑分组的一个或多个字段。 如果 MongoDB 只需要去一个分片来检索你的数据,它会更快地返回。