MongoDB java驅動如何判斷副本集是否處於自動故障轉移過程中? (How can MongoDB java driver determine if replica set is in the process of automatic failover?)


問題描述

MongoDB java驅動如何判斷副本集是否處於自動故障轉移過程中? (How can MongoDB java driver determine if replica set is in the process of automatic failover?)

Our application is build upon mongodb replica set. I'd like to catch all exceptions thrown among the time frame when replica set is in process of automatic failover. I will make application retry or wait for failover completes. So that the failover won't influence user. I found document describing the behavior of java driver here: https://jira.mongodb.org/browse/DOCS‑581

I write a test program to find all possible exceptions, they are all MongoException but with different message:

  1. MongoException.Network: "Read operation to server /10.11.0.121:27017 failed on database test"
  2. MongoException: "can't find a master"
  3. MongoException: "not talking to master and retries used up"
  4. MongoException: "No replica set members available in [ here is replica set status ]  for { "mode" : "primary"}"
  5. Maybe more...

I'm confused and not sure if it is safe to determine by error message. Also I don't want to catch all MongoException. Any suggestion?

Thanks


參考解法

方法 1:

I am now of the opinion that Mongo in Java is particularly weak in this regards.  I don't think your strategy of interpreting the error codes scales well or will survive driver evolution.  This is, of course, opinion.

The good news is that the Mongo driver provides a way get the status of a ReplicaSet:  http://api.mongodb.org/java/2.11.1/com/mongodb/ReplicaSetStatus.html.  You can use it directly to figure out whether there is a Master visible to your application.  If that is all you want to know, the http://api.mongodb.org/java/2.11.1/com/mongodb/Mongo.html#getReplicaSetStatus() is all you need.  Grab that kid and check for a not‑null master and you are on your way.

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

If what you really need is to figure out if the ReplSet is dead, read‑only, or read‑write, this gets more difficult.  Here is the code that kind‑of works for me.  I hate it.

@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;
}

I hate it because it doesn't follow the Mongo Java Driver convention of your application only needs a single Mongo and through this singleton you connect to the rest of the Mongo data structures (DB, Collection, etc).  I have only been able to observe this working by new'ing up a second Mongo during the check so that I can rely upon the ReplicaSetStatus null check to discriminate between "ReplSet‑DOWN" and "read‑only".

What is really needed in this driver is some way to ask direct questions of the Mongo to see if the ReplSet can be expected at this moment to support each of the WriteConcerns or ReadPreferences.  Something like...

/**
 * @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 ) 

This makes sense to me because it acknowledges the fact that the ReplSet may have been great when the Mongo was created, but conditions right now mean that Read or Write operations of a specific type may fail due to changing conditions.

In any event, maybe http://api.mongodb.org/java/2.11.1/com/mongodb/ReplicaSetStatus.html gets you what you need.

方法 2:

When Mongo is failing over, there are no nodes in a PRIMARY state. You can just get the replica set status via the replSetGetStatus command and look for a master node. If you don't find one, you can assume that the cluster is in a failover transition state, and can retry as desired, checking the replica set status on each failed connection.

方法 3:

I don't know the Java driver implementation itself, but I'd do catch all MongoExceptions, then filter them on getCode() basis. If the error code does not apply to replica sets failures, then I'd rethrow the MongoException.

The problem is, to my knowledge there is no error codes reference in the documentation. Well there is a stub here, but this is fairly incomplete. The only way is to read the code of the Java driver to know what code it uses…

(by William BaoBob KuharChris HealdStephane Godbillon)

參考文件

  1. How can MongoDB java driver determine if replica set is in the process of automatic failover? (CC BY‑SA 3.0/4.0)

#mongodb-java #mongoDB






相關問題

GridFS Java 對像是線程安全的嗎? (Are GridFS Java objects thread safe?)

Драйвер MongoDB Java: такога cmd: aggregate няма (MongoDB Java driver : no such cmd: aggregate)

Стварэнне парадкавага нумара ў mongoDB (Generating sequence number in mongoDB)

MongoDB java驅動如何判斷副本集是否處於自動故障轉移過程中? (How can MongoDB java driver determine if replica set is in the process of automatic failover?)

優化 mongodb 中的查詢 (Optimising queries in mongodb)

查詢數據時應該使用 MongoTemplate 還是 DBCollection (Should i use MongoTemplate or DBCollection when query data)

org.bson.codecs.configuration.CodecConfigurationException:找不到類 [Ljava.lang.String; 的編解碼器; (org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class [Ljava.lang.String;)

如何使用 Java MongoDB 驅動程序檢索字段子集? (How to retrieve a subset of fields using the Java MongoDB driver?)

當使用 karras 和 clojure 給出字段時,如何更新 MongoDB 中的文檔? (How to update a Document in MongoDB when a field is given with karras & clojure?)

如何使用 java 代碼轉換 mongodb 查詢 (How to Transform mongodb query using java code)

MongoDB 文檔使用 Java 中的 findOneAndUpdate 方法更新數組元素 (MongoDB document update array element using findOneAndUpdate method in Java)

aws documentdb 是否為兩種方式的 ssl 驗證 mongodb 客戶端證書? (Does aws documentdb validate mongodb client certificate for two way ssl?)







留言討論