3

У меня проблема с консистенцией Кассандры. У меня есть 3 узла Cassandra (версия 2.0.14.352) в кластере, и я читаю и записываю с уровень согласованности QUORUM и мой replicationfactor - это 3. Если я понимаю this прямо в моем случае, Кассандра должна быть последовательной, потому что 2 + 2> 3. Но я написал тест в Java, где я вставить некоторые данные очень быстро в Кассандре с помощью datastax-драйвера:Кассандра не согласуется, несмотря на уровень согласованности QUORUM с коэффициентом репликации 3

final Instant t1 = Instant.parse("2000-01-01T00:00:00.000Z"); 
final Instant t2 = Instant.parse("2000-02-01T00:00:00.000Z"); 

for (int i = 0; i < 100; i++) { 
    dataProvider.setValue(t1, new Double(1)); 
    //If the next line is removed, the test will pass 
    dataProvider.setValue(t2, new Double(3)); 

    dataProvider.saveToDB(); 
    dataProvider.clear(); 
    assertEquals("i=" + i, new Double(3), dataProvider.getValue(t2)); 
    assertEquals("i=" + i, new Double(1), dataProvider.getValue(t1)); 

    dataProvider.setValue(t1, new Double(2)); 
    dataProvider.saveToDB(); 
    dataProvider.clear(); 
    assertEquals("i=" + i, new Double(2), dataProvider.getValue(t1)); 

    dataProvider.setValue(t1, new Double(101)); 
    dataProvider.saveToDB(); 
    dataProvider.clear(); 
    assertEquals("i=" + i, new Double(101), dataProvider.getValue(t1)); 
} 

с соответствующей таблицей

CREATE TABLE keyspace.table(
    id text, 
    year int, 
    month int, 
    time timestamp, 
    value double, 
    PRIMARY KEY ((id, year, month), time) 
) 

dataProvider.setValue() internaly Переводит заданное значение в NavigableMap. dataProvider.saveToDB() вставляет данные в Cassandra. Здесь я попытался, с одной стороны, вставить данные асинхронными и дождаться завершения всех результатов ResultSetFuture, а с другой стороны, я выполнил операторы синхронно. Но это повлияло только на производительность. Подробно метод сохранения выглядит как

final List<ResultSetFuture> sets = newLinkedList(); 
Batch batch = QueryBuilder.batch(); 
int batchsize=0; 
for (Map.Entry<Instant, Double> entry : valueMap) { 
    final Instant instant = entry.getKey(); 
    final ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("UTC")); 
    final Date date = Date.from(instant); 
    final Insert insert = QueryBuilder.insertInto(table) 
      .value(ID, id) 
      .value(YEAR, zonedDateTime.getYear()) 
      .value(MONTH, zonedDateTime.getMonthValue()) 
      .value(TIME, date) 
      .value(VALUE, entry.getValue()); 
    batch.add(insert); 
    ++batchsize; 
    if(batchsize % 200 == 0){ 
     sets.add(cassandraConnector.executeAsync(batch)); 
     batch = QueryBuilder.batch(); 
    } 
} 
if(batchsize % 200 != 0) { //es gibt noch nicht abgeschickte Statements 
    sets.add(cassandraConnector.executeAsync(batch)); 
} 
cassandraConnector.waitForFinish(sets); 

cassandraConnector управляет соединением. Я жду, пока все ResultSets закончил с

public boolean waitForFinish(List<ResultSetFuture> sets) { 
    ResultSet result = null; 
    for (final ResultSetFuture resultSetFuture : sets) { 
     // Wait until finished 
     try { 
      result = resultSetFuture.get(); 
     } catch (InterruptedException e) { 
      resultSetFuture.cancel(true); 
      e.printStackTrace(); 
      return false; 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
      if (result != null) { 
       ExecutionInfo executionInfo = result.getExecutionInfo(); 
       System.out.println("Timout from server with IP: " + executionInfo.getTriedHosts()); 
      } 
      return false; 
     } 
    } 
    return true; 
} 

Любопытство в том, что если я удалить строку под комментарием, тест будет проходить и это не распространяется того, как часто я исполню ее. Но если я запустил тест, не удаляя строку, иногда он терпит неудачу в первом цикле, но иногда он запускает 3 цикла до тех пор, пока не сработает. Кроме того, он всегда терпит неудачу в разных направлениях. Например

java.lang.AssertionError: i=0 
Expected :101 
Actual :2 

Я также получил

java.lang.AssertionError: i=2 
Expected :2 
Actual :101 

Так что, похоже, что Кассандра написал 1 и после того, что вместо сочинительство 2 Cassandra восстановила 101 я написал до 1. Кто-нибудь есть объяснение для этого поведения? Почему тест проходит, если я удаляю строку? Я пишу по разным разделам. Я попытался изменить уровень согласованности на ВСЕ, но поведение не изменилось.

+0

Можете ли вы также показать код класса DataProvider? – shutty

+0

Я добавил еще код. Там вы можете увидеть, как я создаю и выполняю инструкции. – Julia

+0

Это похоже на общее недопонимание пакетов http://stackoverflow.com/questions/30317877/cassandra-batch-statement-execution-order – RussS

ответ

1

Я решил. Очевидно, что часы не на 100% синхронны. Когда я создаю инструкцию insert, я добавил .using (timestamp (System.nanoTime()/1000)); и теперь проходит тест.