Ошибка StaleConfig в кластере сегментированных данных ошибка из-за изменения размещения данных в кластере, вызванная несоответствием версии, обнаруженной для db.collection_name " - PullRequest
0 голосов
/ 04 августа 2020

Спасибо за вашу помощь, в некоторых случаях мы получаем ошибки StaleConfig при вставке документа в коллекцию mongodb, которая является сегментированной.

Я знаю, что мы получаем проблему StaleConfig во время миграции фрагментов , но в этой ошибке мы видим, что :: обнаружено несоответствие версии для db.collection_name .

Ваша помощь очень ценится.

Сведения о версии

Версия Spring Data: 2.1.3.RELEASE

Java Mon go Драйвер: 3.12.5

Версия MongoServer: 4.2.8

Выполняется только вставка документа в три разные коллекции

org.springframework.data.mongodb.UncategorizedMongoDbException: 
Command failed with error 13388 (StaleConfig): 'Transaction 178d5e17-5cd1-459e-b425-eca33bf776a6:472 was aborted on statement 1 
due to: an error from cluster data placement change :: caused by :: Encountered error from <hostname>:<port> during a transaction 
:: caused by :: version mismatch detected for db.collection_name' on server "server_name:<port>". 
The full response is {"ok": 0.0, "errmsg": "Transaction 178d5e17-5cd1-459e-b425-eca33bf776a6:472 
was aborted on statement 1 due to: an error from cluster data placement change :: 
caused by :: Encountered error from <hostname>:<port> during a transaction 
:: caused by :: version mismatch detected for db.collection_name", "code": 13388, 
"codeName": "StaleConfig", "ns": "db.collection_name", "vReceived": {"$timestamp": {"t": 382, "i": 3}}, 
"vReceivedEpoch": {"$oid": "5ec573a0ccf6d56864230435"}, "vWanted": {"$timestamp": {"t": 383, "i": 3}}, 
"vWantedEpoch": {"$oid": "5ec573a0ccf6d56864230435"}, "operationTime": {"$timestamp": {"t": 1596542628, "i": 36}}, 
"$clusterTime": {"clusterTime": {"$timestamp": {"t": 1596542628, "i": 38}}, 
"signature": {"hash": {"$binary": "1fuZwXBpaoKtWb7NrH+tuSnpFYk=", "$type": "00"}, "keyId": {"$numberLong": "6823864140331745310"}}}, 
"errorLabels": ["TransientTransactionError"]}; nested exception is com.mongodb.MongoCommandException: 
Command failed with error 13388 (StaleConfig): 'Transaction 178d5e17-5cd1-459e-b425-eca33bf776a6:472 was aborted on statement 1 
due to: an error from cluster data placement change :: caused by :: Encountered error 
from <hostname>:<port> during a transaction :: caused by :: version mismatch detected for db.collection_name' on server <server>:<port>.

1 Ответ

0 голосов
/ 26 августа 2020

С MongoDB в кластере сегментированных данных вы можете увидеть такого рода исключение, вы можете решить это, просто повторив транзакцию, MongoDB предоставит API обратного вызова или вы можете иметь собственную реализацию повтора.

Если вы используете Spring-data и mongoTemplate из Spring и хотите использовать withTransaction API, то API обратного вызова не будет работать, потому что он повторяет попытку для класса исключения « MongoException » Фрагмент из ClientSessionImpl class.

public <T> T withTransaction(final TransactionBody<T> transactionBody, final TransactionOptions options) {
        notNull("transactionBody", transactionBody);
        long startTime = ClientSessionClock.INSTANCE.now();
        outer:
        while (true) {
            T retVal;
            try {
                startTransaction(options);
                retVal = transactionBody.execute();
            } catch (RuntimeException e) {
                if (transactionState == TransactionState.IN) {
                    abortTransaction();
                }
                if (e instanceof MongoException) {
                    if (((MongoException) e).hasErrorLabel(TRANSIENT_TRANSACTION_ERROR_LABEL)
                            && ClientSessionClock.INSTANCE.now() - startTime < MAX_RETRY_TIME_LIMIT_MS) {
                        continue;
                    }
                }
                throw e;
            }
            if (transactionState == TransactionState.IN) {
                while (true) {
                    try {
                        commitTransaction();
                        break;
                    } catch (MongoException e) {
                        unpinServerAddressOnError(e);
                        if (ClientSessionClock.INSTANCE.now() - startTime < MAX_RETRY_TIME_LIMIT_MS) {
                            applyMajorityWriteConcernToTransactionOptions();

                            if (!(e instanceof MongoExecutionTimeoutException)
                                    && e.hasErrorLabel(UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL)) {
                                continue;
                            } else if (e.hasErrorLabel(TRANSIENT_TRANSACTION_ERROR_LABEL)) {
                                continue outer;
                            }
                        }
                        throw e;
                    }
                }
            }
            return retVal;
        }
    }

Поскольку mongoTemplate с Spring-data и с аннотацией Transactional оборачивает исключение, связанное с транзакцией, в « MongoTransactionException », следовательно, withTransaction api с mongoTemplate не выполняет повторных попыток, потому что он ищет класс « MongoException ».

Итак, если вы хотите повторить попытку, используя весенние данные с mongoTemplate, вы можете используйте Retryable framework, как показано ниже.

@Transactional(value = "mongoTransactionManager", propagation = Propagation.REQUIRED)
@Retryable(value = {MongoCommandException.class, MongoException.class}, exclude = {MongoTransactionException.class, UncategorizedMongoDbException.class},
        backoff = @Backoff(delay = 10), maxAttempts = 10)
public void performingTransactionaOperations(DocumentBean1 document1, DocumentBean2 document2, DocumentBean3 document3){
    try {
        mongoTemplate.insert(document1);
        mongoTemplate.insert(document2);
        mongoTemplate.insert(document3);
        
    }catch (MongoTransactionException | UncategorizedMongoDbException ex){
        MongoException mongoException = null;
        if(ex.getCause() instanceof MongoException) {
            mongoException = (MongoException) ex.getCause();
        }else if(ex.getCause() instanceof MongoCommandException){
            mongoException = (MongoCommandException) ex.getCause();
        }
        if(mongoException!=null && mongoException.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)) {
            System.out.println("TransientTransactionError aborting transaction and retrying ...");
            throw mongoException;
        }else if(mongoException!=null &&  mongoException.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL)){
            log.debug("UnknownTransactionCommitResult, retrying commit operation ...");
            throw mongoException;
        }
        throw ex;
    }
}
...