我也能理解的系列:MongoDB的复制
这篇文章是MongoDB Advent Calendar 2015的第17天。
简要总结
这是一篇充满了何必现在才的回顾文章。
建议阅读 MongoDB Manual 3.0 中的 Replication 文档,因为它可能包含无意中的谎言。
Replica Set是什么?
Replication Introduction — MongoDB Manual 3.0
复制集是MongoDB提供的强大的复制和自动故障转移机制。
在由多个MongoDB服务器构建的复制集中,可以将其作为分片(Shard)添加到另一个MongoDB强大的功能中,即分片(水平分割)。
无论是构建大规模高可用的MongoDB数据库,都需要使用这些东西,并且可以将其作为MongoDB的标准功能,这被认为是MongoDB的一大优势。
复制集成员
Replica Set Members — MongoDB Manual 3.0
为了实现副本集的功能,至少需要3台MongoDB服务器。这包括1台主节点,1台或多台从节点以及0台或1台仲裁者。
目前主要的
我是复制的源头成员。
从原理上讲,由于写入操作集中在这台服务器上,所以后面提到的读取偏好使用的方法将成为提高复制集性能的关键。
中学的
作为一个成为复制品的子节点,并且按照Primary进行数据复制的成员。
主要成员的投票决定了当Primary成员死亡时,哪个Secondary成员将升为Primary。如果是读操作较多的数据库系统,由于可以进行数据读取,可以通过增加Secondary成员的数量来分担读操作的负载,而无需进行分片的水平分割。此外,增加Secondary成员还能增强系统对同时成员死亡的韧性。
隐藏的 de)
这是一个被设置为不被引用,并且不会晋升为Primary的Secondary。它不会被引用,只会追随Primary的数据,所以相比其他Secondary,它的负载较低。
当需要定期备份整个数据库时,为了创建一个快照点,需要这样的成员使得停止对文件系统的同步也不会有问题。
另外,还有一个称为Delayed成员的概念,可以有意地保留延迟的数据。
仲裁者
DBのデータは保持せず、単にPrimary死亡時の昇格投票のみを行います。実データの読み書きが一切なく、負荷は非常に低いです。Arbiterは必須ではなく、通常PrimaryとSecondaryのメンバー数の合計が偶数になってしまう場合に数合わせとして参加させるメンバーです。
复制集的配置
Replica Set Deployment Architectures — MongoDB Manual 3.0
要求的性能方面,
主要 = 次要 >> 隐藏 >> 仲裁者
为了实现这一目标,可以考虑以下各种组合(按照可能降低成本的顺序排列)。
偶数台での構成も可能なのですが、そのような場合はArbiterを加えて必ず奇数にするように推奨されています。
ここに書いていない、例えば遅らせる時間を変えた複数台のDelayedメンバーを加えるという構成も考えられます(その場合、合計台数と同時死亡許容数の計算はこの表の通りではありません)。
阅读偏好
Read Preference — MongoDB Manual 3.0
Read Preference是一个功能,可以在从客户端读取MongoDB时选择访问哪个成员。
这个功能是在客户端进行的,因此服务器端没有特别的配置。
通常はsecondaryPreferredを指定しておき、常に最新のデータを読み出したい(レプリケーション遅延が一切許されない)場合のみprimaryPreferredを使う、というのが普通かと思います。
そのように使ったらSecondaryばかりCPUが上がる!という場合には、nearestを検討するのもよいかもしれません。
在Mongoose中的指定方式
Mongoose是Node.js的对象文档映射工具(ODM)。它不是关系型数据库的对象关系映射工具(ORM),而是针对非关系型数据库的。当创建Schema对象时,可以指定读取偏好(Read Preference)如下。
var schema = new Schema({ name: String, inventory: {} }, { minimize: false, read: 'secondaryPreferred' });
var Character = mongoose.model('Character', schema);
// will store `inventory` if empty
var sam = new Character({ name: 'Sam', inventory: {}});
Character.findOne({ name: 'Sam' }, function(err, character) {
console.log(character); // { name: 'Sam', inventory: {}}
});
写入关注
Write Concern Reference — MongoDB Manual 3.2
在客户端的功能中,我们也可以明确指定“在写入多少内容时视作写入成功”。客户端可以设置对重要的写入进行严格检查。
可以使用以下选项组合来指定:{w: ‘majority’, j: true, wtimeout: 2000}。
w选项
指定数字或多数。
当指定了数字时,只要成功地向该数量的副本集成员写入数据,就被认为写入操作成功。
当指定为majority时,只要具有投票权的副本集成员中超过半数的写入操作完成,即可被判定为写入成功。
デフォルトはw: 1です(Primaryに書き込み完了したら書き込み成功)。
J选项
可以指定为 true 或者 false。
当条件为真时,一旦写入到journal(存储)完成,就会被视为写入成功。
wtimeout选项
这是指定写入完成的超时时间。单位是毫秒。
在Mongoose中的设置方式
同样地,可以在生成Schema对象时通过传递一个表示写入关注的对象作为选项来指定。
var safe = { w: "majority", wtimeout: 10000 };
new Schema({ .. }, { safe: safe });
Replica SetまわりのMongoDBコマンド
因为没有尽头,所以简要介绍。
rs.initiate()开始
rs.initiate() — MongoDB Manual 3.0
通过使用最初的Primary成员执行此操作,将初始化Replica Set。
rs.add():添加一条记录。
rs.add() — MongoDB Manual 3.0
使用Primary服务器执行操作,向复制集中添加成员。
以下的例子是,上面是将其作为常规的Secondary添加,而下面是将其作为隐藏成员添加。
rs.add({host: "oreno-mongodb-1.internal:27017"});
rs.add({host: "oreno-mongodb-backup.internal:27017", priority: 0, hidden: true});
由于参数可以是对象或字符串,所以也可以按照以下方式进行指定。
rs.add("oreno-mongodb-1.internal:27017");
在操作时,要小心不要让正在实际运行的Replica Set中的新的Secondary参与其中,这可能会导致意外。
rs.status() – 获取副本集的状态
rs.status() — MongoDB Manual 3.0
replSetGetStatus — MongoDB Manual 3.0
replSetGetStatus — MongoDB Manual 3.0
显示副本集的状态。在调查过程中非常常用。
现在有什么成员,哪些成员是主要成员,能否进行有效沟通等等。
rs.stepDown() 可以被改写为 rs.主动降级()
rs.stepDown() — MongoDB Manual 3.0
在主服务器上执行,并将自身降级为次要服务器。自动故障转移将触发,并且其他次要服务器中的一台将成为新的主服务器。
rs.conf()可以重述为rs.conf就可以了
rs.conf() — MongoDB Manual 3.0
現在のReplica Setの設定を表示します。以下のようなオブジェクトが帰ってきます。
{
"_id" : "oreno-mongodb0-sh00",
"version" : 10,
"members" : [
{
"_id" : 0,
"host" : "oreno-mongodb0-sh00-000:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 2,
"host" : "oreno-mongodb0-sh00-backup:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true,
"priority" : 0,
"tags" : {
},
"slaveDelay" : 0,
"votes" : 1
},
{
"_id" : 3,
"host" : "oreno-mongodb0-sh00-001:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : 0,
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatTimeoutSecs" : 10,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}
}
単体でも使用しますが、後述のrs.reconfig()と併せて使うことが多いです。
rs.reconfig() 重新配置集群
rs.reconfig() — MongoDB Manual 3.0
在Primary上执行,并改写Replica Set的设置。
通常情况下,该命令的参数通常使用从rs.conf()方法中获取的对象作为基础,并只对需要更改的部分进行修改。
举例来说,如果要将oreno-mongodb0-sh00-001设置为上述rs.conf()结果中的隐藏成员,则操作如下所示。由于MongoDB的Shell是基于JavaScript的,因此这种操作有些像编程一样。
var conf = rs.conf();
conf.members[2].priority = 0;
conf.members[2].hidden = true;
rs.reconfig(conf);
“_id” : 3,却是members[2]??
察觉到此事的人真是聪明。由于 conf.members 只是一个简单的数组,所以这样就足够了。务必小心不要错误地操作其他成员的设置!
另外,如果将Secondary的priority设置为比当前Primary的priority更高的值,那么在执行rs.reconfig()时,会立即产生与rs.stepDown()相同的行为。
删除rs
rs.remove() — MongoDB Manual 3.0
在主节点上执行并从副本集中排除成员。社会是残酷的。
让我们从rs.status()中复制粘贴members[n].name以指定参数中的主机名。
db.printSlaveReplicationInfo()的本地化中文释义是:”打印从复制信息”
db.printSlaveReplicationInfo() — MongoDB Manual 3.2
使用rs.status()可以比较optime来确认复制延迟,但是用肉眼解析Unix Timestamp对人类来说太慢了。使用这个方法可以一目了然。
中国的母语学者可以用以下方式改述:
冷知识
为什么是主/从而不是主/从呢?
在MongoDB 1.6之前(很久以前了),在引入复制集功能之前,MongoDB中存在着不包含自动故障切换机制的主/从复制功能。
随后,添加了由两个主要组成的”副本对”功能,该功能进一步发展成为可以在任意节点上进行复制的”副本集”。因此,为了强调随时可以切换的意义,更名为”Primary(主节点)/Secondary(从节点)”而不是”Master/Slave(主/从)”。