更加复杂,但是灵活的方法,用于路由报表查询到一个专属节点去使用标签和读偏好。

因为使用隐藏成员,设置一个成员为priority: 0,但是不设置它为隐藏。然而,分配一个标签use: reporting:

PRIMARY> conf = rs.config()    { "_id" : "test", "version" : 21, "members" : [ { "_id" : 0, "host" : "xucy.local:27017", }, { "_id" : 1, "host" : "xucy.local:28017", }, { "_id" : 2, "host" : "xucy.local:29017", } ] } // we'll use members[1], the instance on port 28017     PRIMARY> conf.members[1].priority = 0     PRIMARY> conf.members[1].tags = { "use": "reporting" }     PRIMARY> conf.version += 1     PRIMARY> rs.reconfig(conf)    [...]

像之前一样,xucy.local:28017绝不会成为主;然而,在这种情况下其他两个机器变得不可达,你的应用将能处理读到报表服务器。它会继续不用说你的报表应该在这样一个事件期间暂停。

你的报表代码将会像这样(用Python,这次):

from pymongo import MongoReplicaSetClient    from pymongo.read_preferences import ReadPreference     rep_set = MongoReplicaSetClient( 'xucy.local:27017,xucy.local:28017,xucy.local:29017', replicaSet = 'test', read_preference = ReadPreference.SECONDARY, tag_sets = [{'use':'reporting'}] ) # check to ensure we're not running reporting against the sole remaining secondary if rep_set.primary is not None: rep_set.my_application.users.aggregate(...)

以上只发送报表查询到副本标记有use: reporting,并且如果没有可用的主,它根本上避免运行。在实践中,你会抛出异常并在你的扩展代码中处理它们,如果你发现没有主!更好的还是,你的监控可以设置运行时可用的值,你可以转移,例如,reporting_system.ok()。

益处和考虑

使用标签和读偏好允许一些级别的灵活性,而那在隐藏成员中是不可能的。

报表实例可以容易添加

因为你的连接代码是可定义的,而不是指定到一个专门的主机,添加更多节点为报表作业,只添加他们并标记他们,像这样:

PRIMARY> rs.add({_id:3, host:"xucy.local:30017", priority:0, tags:{'use':'reporting'}})

你存在的代码将会利用新的容量,并且复制集将继续运行,不用触发选举和从客户端断开连接。

报表实例可以被跳过或删除

报表标记可以被移动,或者甚至移除,如果你需要提供读带宽给其他作业在必要时。像这样的一个重新配置将会触发选举,并重连所有客户端,但是这不会比其他选项更糟糕。注意:这是一个反模式的通过发布生产读到副本成员来增加常用容量。这只是一个紧急方式。

一些驱动需要手工同步

Ruby驱动(像1.9.2),例如,不会刷新副本集的视图除非客户端像这样显式初始化,使用refresh_mode: :sync。检查你的驱动文档。

结论

简单的复制配置已经成为我喜欢MongoDB原因之一,它使得MySQL复制看起来像出自石器时代。它有些粗糙,但是已经在不断提升性能。无论你使用标记集合或者隐藏成员,构建一个报表架构在MongoDB的复制属性上,简化操作,让你专注于构建一个伟大的应用。