MongoDB java驱动程序如何确定副本集是否处于自动故障转移的过程中?

时间:2013-08-01 08:06:10

标签: mongodb mongodb-java

我们的应用程序基于mongodb副本集构建。 我希望捕获副本集处于自动故障转移过程中的时间范围内抛出的所有异常。 我将使应用程序重试或等待故障转移完成。 这样故障转移不会影响用户。 我在这里找到了描述java驱动程序行为的文档:https://jira.mongodb.org/browse/DOCS-581

我编写了一个测试程序来查找所有可能的异常,它们都是MongoException但有不同的消息:

  1. MongoException.Network:"对服务器/10.11.0.121:27017的读取操作在数据库测试时失败"
  2. MongoException:"无法找到主人"
  3. MongoException:"不与主人交谈,重试用完"
  4. MongoException:" {"模式"在[这里是副本集状态]中没有可用的副本集成员:" primary"}"
  5. 也许更多......
  6. 我很困惑,不确定通过错误消息确定是否安全。 此外,我不想捕捉所有MongoException。 有什么建议吗?

    由于

3 个答案:

答案 0 :(得分:1)

当Mongo故障转移时,没有处于PRIMARY状态的节点。您可以通过replSetGetStatus命令获取副本集状态,并查找主节点。如果找不到,则可以假设群集处于故障转移过渡状态,并且可以根据需要重试,检查每个失败连接上的副本集状态。

答案 1 :(得分:1)

我现在认为Java中的Mongo在这方面特别薄弱。我不认为你解释错误代码的策略可以很好地扩展或者在驱动程序演变中存活下来。当然,这是意见。

好消息是Mongo驱动程序提供了一种获取ReplicaSet状态的方法:http://api.mongodb.org/java/2.11.1/com/mongodb/ReplicaSetStatus.html。您可以直接使用它来确定应用程序是否可以看到Master。如果您只想知道,http://api.mongodb.org/java/2.11.1/com/mongodb/Mongo.html#getReplicaSetStatus()就是您所需要的。抓住那个孩子并检查一个非空主人,你就在路上。

ReplicaSetStatus rss = mongo.getReplicaSetStatus();
boolean driverInFailover = rss.getMaster() == null;

如果你真正需要的是弄清楚ReplSet是死了,只读还是读写,这就变得更加困难了。这段代码对我有用。我恨它。

@Override
public ReplSetStatus getReplSetStatus() {
    ReplSetStatus rss = ReplSetStatus.DOWN;
    MongoClient freshClient = null;
    try {
        if ( mongo != null ) {
            ReplicaSetStatus replicaSetStatus = mongo.getReplicaSetStatus();
            if ( replicaSetStatus != null ) {
                if ( replicaSetStatus.getMaster() != null ) {
                    rss = ReplSetStatus.ReadWrite;
                } else {
                    /*
                     * When mongo.getReplicaSetStatus().getMaster() returns null, it takes a a
                     * fresh client to assert whether the ReplSet is read-only or completely
                     * down. I freaking hate this, but take it up with 10gen.
                     */
                    freshClient = new MongoClient( mongo.getAllAddress(), mongo.getMongoClientOptions() );
                    replicaSetStatus = freshClient.getReplicaSetStatus();
                    if ( replicaSetStatus != null ) {
                        rss = replicaSetStatus.getMaster() != null ? ReplSetStatus.ReadWrite : ReplSetStatus.ReadOnly;
                    } else {
                        log.warn( "freshClient.getReplicaSetStatus() is null" );
                    }
                }
            } else {
                log.warn( "mongo.getReplicaSetStatus() returned null" );
            }
        } else {
            throw new IllegalStateException( "mongo is null?!?" );
        }
    } catch ( Throwable t ) {
        log.error( "Ingore unexpected error", t );
    } finally {
        if ( freshClient != null ) {
            freshClient.close();
        }
    }
    log.debug( "getReplSetStatus(): {}", rss );
    return rss;
}

我讨厌它,因为它不遵循应用程序的Mongo Java Driver约定只需要一个Mongo,并通过这个单例连接到其余的Mongo数据结构(DB,Collection等)。我只能通过在检查期间新建第二个Mongo来观察这个工作,这样我就可以依赖ReplicaSetStatus null检查来区分“ReplSet-DOWN”和“read-only”。

这个驱动程序真正需要的是一些方法来询问Mongo的直接问题,看看此时是否可以预期ReplSet支持WriteConcerns或ReadPreferences。有点像...

/**
 * @return true if current state of Client can support readPreference, false otherwise
 */
boolean mongo.canDoRead( ReadPreference readPreference )

/**
 * @return true if current state of Client can support writeConcern; false otherwise
 */
boolean mongo.canDoWrite( WriteConcern writeConcern ) 

这对我有意义,因为它承认在创建Mongo时ReplSet可能很好,但现在的条件意味着特定类型的读或写操作可能会因条件的变化而失败。

无论如何,也许http://api.mongodb.org/java/2.11.1/com/mongodb/ReplicaSetStatus.html可以满足您的需求。

答案 2 :(得分:0)

我不知道Java驱动程序实现本身,但我会捕获所有MongoException,然后基于getCode()过滤它们。如果错误代码不适用于副本集失败,那么我将重新抛出MongoException

问题是,据我所知,文档中没有错误代码参考。好吧有一个stub here,但这还不完整。唯一的方法是读取Java驱动程序的代码,以了解它使用的代码......