这是一个非常好的问题,最近我自己也经历了这段非常痛苦的旅程。我在这里写了一个相当广泛的答案,希望通过 CloudFormation 运行 MongoDB 集群的一些想法对其他人有用。
我假设您正在创建一个 MongoDB 生产集群,如下所示:-
- 3 个配置服务器(微型/小型实例可以在这里工作)
- 至少 1 个分片,例如2 个(主要和次要)分片实例(最小或大型),为数据/日志/日志磁盘配置了大磁盘。
- 投票仲裁机(微可能还可以)。
即https://docs.mongodb.org/manual/core/sharded-cluster-architectures-production/
像您一样,我最初尝试了您在链接 (https://s3.amazonaws.com/quickstart-reference/mongodb/latest/templates/MongoDB-VPC.template) 中发布的 AWS MongoDB CloudFormation 模板,但老实说,它太复杂了,即它有 9,300 行长并且设置了多个服务器(即副本分片) ,配置,仲裁等)。运行 CloudFormation 模板需要很长时间,并且一直失败(例如 15 分钟后),这意味着服务器都再次终止,我不得不再试一次,这真的令人沮丧/耗时。
我最终采用的解决方案(我对此非常满意)是为集群中的每种类型的 MongoDB 服务器创建单独的模板,例如
-
MongoDbConfigServer.template (创建配置服务器的模板 - 运行 3 次)
-
MongoDbShardedReplicaServer.template (创建副本的模板 - 每个分片运行 2 次)
-
MongoDbArbiterServer.template (创建仲裁器的模板 - 每个分片运行一次)
注意:https://github.com/adoreboard/aws-cloudformation-templates提供模板
然后的想法是单独启动集群中的每个服务器,即 3 个配置服务器、2 个分片副本服务器(用于 1 个分片)和一个仲裁器。然后,您可以将自定义参数添加到每个模板中,例如副本服务器的参数可能包括:-
-
InstanceType 例如t2.micro
-
ReplicaSetName 例如s1r (分片 1 副本)
-
ReplicaSetNumber 例如2 (与ReplicaSetName 一起使用以创建名称,例如名称变为s1r2)
-
VpcId 例如vpc-e4ad2b25 (显然不是真正的 VPC!)
-
SubnetId 例如subnet-2d39a157 (显然不是真正的子网!)
-
GroupId (现有 MongoDB 组 ID 的名称)
-
Route53 (将记录添加到内部 DNS 的布尔值 - 最佳实践)
-
Route53HostedZone (如果布尔值为真,则使用 Route53 的内部 DNS 的 ID)
CloudFormation 真正酷的地方在于,这些自定义参数可以具有 (a) 对运行它的人有用的描述,(b) 特殊类型(例如,当运行创建一个预过滤的组合框,因此更难出错)和 (c ) 默认值。这是一个例子:-
"Route53HostedZone": {
"Description": "Route 53 hosted zone for updating internal DNS (Only applicable if the parameter [ UpdateRoute53 ] = \"true\"",
"Type": "AWS::Route53::HostedZone::Id",
"Default": "YA3VWJWIX3FDC"
},
这使得运行 CloudFormation 模板变得轻而易举,因为很多时候我们可以依赖默认值,并且只根据我们正在创建(或替换)的服务器实例进行一些调整。
除了参数之外,前面提到的 3 个模板中的每一个都有一个 "Resources" 部分,用于创建实例。我们也可以通过"AWS::CloudFormation::Init" 部分做一些很酷的事情。例如
"Resources": {
"MongoDbConfigServer": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets" : {
"Install" : [ "Metric-Uploading-Config", "Install-MongoDB", "Update-Route53" ]
},
前面示例中的"configSets" 表明,创建 MongoDB 服务器不仅仅是创建 AWS 实例并在其上安装 MongoDB,而且我们还可以 (a) 安装 CloudWatch 磁盘/内存指标 (b) 更新Route53 DNS 等。这个想法是您希望尽可能地自动化 DNS / 监控等。
IMO,创建一个模板,因此为每个服务器创建一个堆栈具有非常好的优势,即能够通过 CloudFormation Web 控制台非常快速地更换服务器。此外,因为我们有一个 server-per-template,所以很容易一点一点地构建 MongoDB 集群。
我对创建模板的最后一点建议是从其他 GitHub MongoDB CloudFormation 模板中复制适合您的内容,例如我使用以下内容来创建副本服务器以使用 RAID10(而不是更昂贵的 AWS 预置 IOPS 磁盘)。
https://github.com/CaptainCodeman/mongo-aws-vpc/blob/master/src/templates/mongo-master.template
在您提到的问题中,您提到了自动缩放 - 我的偏好是手动添加分片/替换损坏的实例(自动缩放对 Web 容器(例如 Tomcat / Apache)有意义,但 MongoDB 集群确实应该随着时间慢慢增长) .但是,监控非常重要,尤其是分片服务器上的磁盘大小,以便在磁盘已满时提醒您(因此您可以添加新分片以删除数据)。使用 AWS CloudWatch 指标/警报或使用 MongoDB MMS 服务可以相当轻松地实现监控。
如果一个节点出现故障,例如分片中的一个副本,那么您可以简单地终止服务器,使用您的 CloudFormation 模板重新创建它,磁盘将自动同步。如果实例出现故障并且通常不需要重新配置,这是我的正常流程。过去我在修复服务器上浪费了太多时间——有时很幸运/有时没有。我现在的备份策略是每天通过crontab、zip 运行一次数据库重要集合的mongodump 并上传到AWS S3。这意味着如果核选项发生(数据库完全损坏),我们可以在一小时或两小时内重新创建整个数据库和mongorestore。
但是,如果您创建新分片(因为空间不足),则需要进行配置。例如,如果您要添加一个新的 Shard 3,您将创建 2 个副本节点(例如,名称 => mongo-s3r1 的主节点/名称 => mongo-s3r2 的辅助节点)和 1 个仲裁器(例如名称 mongo-s3r-arb) 然后您将通过 MongoDB shell 连接到 mongos(MongoDB 路由器)并运行以下命令:-
sh.addShard("s3r/mongo-s3r1.internal.mycompany.com:27017,mongo-s3r2.internal.mycompany.com:27017")
注意: - 此命令假定您通过 Route53 使用私有 DNS(最佳实践)。您可以在addShard 命令中简单地使用两个副本的私有 IP,但过去我对此非常不满(例如,几个月前,所有 AWS 实例都重新启动,并为所有这些实例生成了新的私有 IP。修复 MongoDB 集群花了我 2 天时间,因为我必须手动重新配置所有内容 - 而更改 Route53 中的 IP 需要几秒钟... ;-)
您可能会争辩说,我们还应该将 addShard 命令添加到另一个 CloudFormation 模板,但 IMO 这增加了不必要的复杂性,因为它必须知道具有 MongoDB 路由器 (mongos) 的服务器并连接到该服务器以运行addShard 命令。因此,我只是在创建新 MongoDB 分片中的实例后运行它。
无论如何,这是我对此事的漫不经心的想法。最重要的是,一旦您有了模板,您的生活就会变得更加轻松,而且值得付出努力!祝你好运! :-)