Обновления Кассандры не работают последовательно

Я запускаю следующий код на моей локальной (Mac) машине и на удаленном сервере Unix:

public void deleteValue(final String id, final String value) {
    log.info("Removing value " + value);
    final Collection<String> valuesBeforeRemoval = getValues(id);
    final MutationBatch m = keyspace.prepareMutationBatch();
    m.withRow(VALUES_CF, id).deleteColumn(value);
    try {
      m.execute();
    } catch (final ConnectionException e) {
      log.error("Unable to delete  location " + value, e);
    }
    final Collection<String> valuesAfterRemoval = getValues(id);
    if (valuesAfterRemoval.size()!=(valuesBeforeRemoval.size()-1)) {
      log.error("value " + value + " was supposed to be removed from list "  + valuesBeforeRemoval + " but it wasn't: " + valuesAfterRemoval);
    }
...
  }

protected Collection<String> getValues(final String id) {
  try {
    final OperationResult<ColumnList<String>> operationResult = keyspace
            .prepareQuery(VALUES_CF).getKey(id).execute();
    final ColumnList<String> result = operationResult.getResult();
    if (result.isEmpty()) {
      log.info("No  value found for id: " + id);
      return new ArrayList<String>();
    }
    return result.getColumnNames();
  } catch (final ConnectionException e) {
    log.error("Unable to retrieve session " + id, e);
  }
  return new ArrayList<String>();
}

Локально эта строка никогда не выполняется, что имеет смысл:

log.error("value " + value + " was supposed to be removed from list "  + valuesBeforeRemoval + " but it wasn't: " + valuesAfterRemoval);

но эта строка выполняется на моем сервере dev:

[ОШИБКА] [main] [nowsdSessionDaoCassandraImpl] [2013-03-08 13:12:24,801] [] - значение 3 должно быть удалено из списка [3, 2, 1, 0, 7, 6, 5, 4, 9, 8] но не было: [3, 2, 1, 0, 7, 6, 5, 4, 9, 8]

  • Я использую com.netflix.astyanax
  • И моя локальная машина, и удаленный сервер dev подключаются к одному и тому же экземпляру cassandra.
  • Как на моей локальной машине, так и на удаленном сервере разработки выполняется один и тот же тест, создающий новое семейство строк и добавляющий 10 записей перед удалением одной.
  • Когда ошибка возникает в dev, log.error("Невозможно удалить местоположение" + значение, e); не был выполнен (т. е. при выполнении команды удаления не возникло никаких исключений).
  • Я на 100% уверен, что никакой другой код не влияет на содержимое базы данных, пока я запускаю тест на dev, так что это не какая-то странная проблема параллелизма.

Что может объяснить, что запрос deleteColumn(значение) выполняется без каких-либо ошибок, но по-прежнему не удаляет столбец из базы данных?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ

Вот как я создал пространство клавиш:

create keyspace sessiondata
    with placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy'
    and strategy_options = {replication_factor:1};

Вот как я создал значения семейства столбцов, на которые ссылается VALUES_CF в приведенном выше коде:

create column family values
    with comparator = UTF8Type
;

Вот как определяется пространство клавиш, указанное в приведенном выше коде Java:

final AstyanaxContext.Builder contextBuilder = getBuilder();
final AstyanaxContext<Keyspace> keyspaceContext = contextBuilder
        .forKeyspace(keyspaceName).buildKeyspace(
                ThriftFamilyFactory.getInstance());
keyspaceContext.start();
keyspace = keyspaceContext.getEntity();

где getBuilder:

  private Builder getBuilder() {
    final AstyanaxConfigurationImpl conf = new AstyanaxConfigurationImpl()
    .setDiscoveryType(NodeDiscoveryType.NONE)
    .setRetryPolicy(new RunOnce());

    final ConnectionPoolConfigurationImpl poolConf = new ConnectionPoolConfigurationImpl("MyPool")
    .setPort(port)
    .setMaxConnsPerHost(1)
    .setSeeds(value);

    return new AstyanaxContext.Builder()
    .forCluster(cluster)
    .withAstyanaxConfiguration(conf)
    .withConnectionPoolConfiguration(poolConf)
    .withConnectionPoolMonitor(new CountingConnectionPoolMonitor());
  }

ВТОРОЕ ОБНОВЛЕНИЕ

  • Во-первых, проблемы связаны не только с удалениями. Я наблюдаю аналогичные проблемы при обновлении записей в базе данных, их чтении и невозможности прочитать только что написанные обновления

  • Во-вторых, я создал тест, который в 100 раз выполняет следующие операции:

    • написать ряд в Кассандру
    • обновить эту строку в Кассандре
    • прочитайте эту строку от Кассандры и проверьте, действительно ли строка была обновлена, и регулярно проверяйте после задержек, не было ли это

    Из этого теста я наблюдаю следующее:

    • опять же, когда я запускаю этот код локально, все 100 итераций проходят сразу (повторных попыток не требуется)
    • когда я запускаю этот код на удаленном сервере, некоторые итерации проходят, а некоторые не выполняются. Когда они терпят неудачу, независимо от того, насколько велика задержка (я жду до 10 секунд), тест всегда терпит неудачу.

На данный момент, я действительно не уверен, как любая установка cassandra могла бы объяснить это поведение, так как я подключаюсь к тому же серверу для своих тестов, и поскольку задержки, которые я вставляю, намного больше, чем любая дополнительная задержка, которая может понадобиться для запуска теста при подключении с моей локальной машины.

Единственное существенное различие заключается в том, на какой машине выполняется код.

ТРЕТЬЕ ОБНОВЛЕНИЕ

Если в тесте, упомянутом в предыдущем обновлении, я вставляю задержку между двумя записями, код начинает проходить, если задержка>= 1000 мс. Задержка, скажем, 100 мс не помогает. Я также изменил компоновщик, чтобы установить согласованность чтения и записи по умолчанию для самого требовательного: ALL, и это никак не повлияло на результаты теста (по-прежнему происходил сбой примерно в половине случаев, если задержка между записями>1 с):

final AstyanaxConfigurationImpl conf = new AstyanaxConfigurationImpl()
.setDiscoveryType(NodeDiscoveryType.NONE)
.setRetryPolicy(new RunOnce()).setDefaultReadConsistencyLevel(ConsistencyLevel.CL_ALL).setDefaultWriteConsistencyLevel(ConsistencyLevel.CL_ALL);

1 ответ

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

Еще одна вещь, требующая двойной проверки, заключается в том, что ip действительно то, что вы думаете, как в вашем приложении, так и в cassandra. Когда вы получите его, напечатайте его между чем-то, например println("-" + ip "-"). До и после вашего блока try для execute в deleteSecureLocation выполните get только для этого столбца, а не для всей строки. Я не слишком уверен, как это сделать в astynax, в конце концов это будет получить [id][ip].

Следует иметь в виду, что удаление не завершится неудачей, даже если нечего удалять. Для cassandra это запись, единственное, что сделает его удалением, это если при чтении это последняя запись с меткой времени для этого имени строки / столбца.

Другие вопросы по тегам