如何使用 Ubuntu 12.04 VPS 在 MongoDB 中创建分片集群
状态:已弃用
本文涵盖不再受支持的 Ubuntu 版本。如果您目前正在运行运行 Ubuntu 12.04 的服务器,我们强烈建议您升级或迁移到受支持的 Ubuntu 版本:
- 升级到 Ubuntu 14.04。
- 从 Ubuntu 14.04 升级到 Ubuntu 16.04
- 将服务器数据迁移到支持的版本
原因:
请参阅:
介绍
MongoDB 是一个 NoSQL 文档数据库系统,具有很好的水平扩展性,通过 key-value 系统实现数据存储。 MongoDB 是 Web 应用程序和网站的热门选择,易于以编程方式实施和访问。
MongoDB 通过一种称为“分片”的技术实现扩展。分片是跨不同服务器写入数据以分配读写负载和数据存储需求的过程。
在之前的教程中,我们介绍了如何在 Ubuntu 12.04 VPS 上安装 MongoDB。我们将以此为起点来讨论如何跨多个不同节点实现分片。
MongoDB 分片拓扑
分片是通过三个独立的组件实现的。每个部分执行特定功能:
- <李> 配置服务器:每个生产分片实现必须恰好包含三个配置服务器。这是为了确保冗余和高可用性。 配置服务器用于存储将请求的数据与包含它的分片链接起来的元数据。它组织数据,以便可以可靠且一致地检索信息。 <李> 查询路由器:查询路由器是您的应用程序实际连接到的机器。这些机器负责与配置服务器通信,以确定所请求数据的存储位置。然后它访问并返回来自适当分片的数据。 每个查询路由器运行“mongos”命令。 <李> 分片服务器:分片负责实际的数据存储操作。在生产环境中,单个分片通常由副本集而不是单台机器组成。这是为了确保在主分片服务器脱机时仍可访问数据。 实施复制集超出了本教程的范围,因此我们将分片配置为单机而不是副本集。如果您想为自己的配置配置副本集,您可以轻松修改它。
初始设置
如果您注意上面的内容,您可能会注意到此配置需要相当多的机器。在本教程中,我们将配置一个示例分片集群,其中包含:
- 3 个配置服务器(生产环境需要)
- 2 个查询路由器(至少需要 1 个)
- 4 个分片服务器(至少需要 2 个)
这意味着您将需要九个 VPS 实例才能完全遵循。实际上,其中一些功能可以重叠(例如,您可以在用作配置服务器的同一 VPS 上运行查询路由器)并且您只需要一个查询路由器和至少 2 个分片服务器。
我们将超越这个最小值,以演示添加每种类型的多个组件。为了清晰和简单起见,我们还将所有这些组件视为离散机器。
设置初始基础图像
首先,使用本指南在 Ubuntu 上安装和配置初始 MongoDB 服务器。我们将使用它来引导其余的分片组件。
完成第一个服务器的教程后,使用以下命令关闭实例:
sudo shutdown -h now
现在,我们要为这个配置好的 Droplet 拍一张快照,并用它来启动我们的其他 VPS 实例。虽然可以拍摄正在运行的系统的快照,但关闭电源可确保文件系统处于一致状态。快照费用为每月每 GB 0.05 美元,具体取决于文件系统中的已用空间量,因此最好在完成后删除快照。
在您的 DigitalOcean 控制面板中,选择 Droplet。单击“快照”选项卡。输入快照名称并单击“拍摄快照”:

将拍摄您的快照并重新启动初始服务器。
基于快照启动 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
)。
最终结果是查询路由器服务以这样的字符串启动:
<前>
您的第一个查询路由器应该开始连接到三个配置服务器。在另一个查询路由器上重复这些步骤。请记住,必须在键入命令之前停止 mongodb
服务。
另外,请记住必须使用完全相同的命令来启动每个查询路由器。不这样做将导致错误。
将分片添加到集群
现在我们已经配置了配置服务器和查询路由器,我们可以开始将实际的分片服务器添加到集群中。这些分片将各自持有总数据的一部分。
以 root 身份登录到您的其中一个分片服务器。
正如我们在开始时提到的,在本指南中我们将只使用单机分片而不是副本集。这是为了演示的简洁和简单。在生产环境中,强烈建议使用副本集,以确保数据的完整性和可用性。要在 MongoDB 中配置副本集,请遵循本指南。
要将分片实际添加到集群中,我们需要通过查询路由器,这些路由器现在配置为充当我们与集群的接口。我们可以像这样连接到任何查询路由器来做到这一点:
<前>
这将连接到适当的查询路由器并打开 mongo 提示符。我们将从此提示添加我们所有的分片服务器。
要添加我们的第一个分片,请键入:
<前>
然后,您可以在同一界面中添加剩余的碎片液滴。您不需要单独登录每个分片服务器。
<前>
如果您正在配置一个生产集群,完成复制集,您必须改为指定复制集名称和复制集成员,以将每个集建立为一个不同的分片。语法看起来像这样:
<前>
如何为数据库集合启用分片
MongoDB 将信息组织到数据库中。在每个数据库中,数据通过“集合”进一步划分。集合类似于传统关系数据库模型中的表。
在本节中,我们将再次使用查询路由器进行操作。如果您还没有连接到查询路由器,您可以使用上一节中使用的相同 mongo 命令再次访问它:
<前>
在数据库级别启用分片
我们将首先在数据库级别启用分片。为此,我们将创建一个名为(适当地)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 只需转到单个分片来检索您的数据,它将返回得更快。