Cassandra - 写入不会失败,但不会插入值

Cassandra - Write doesn't fail, but values aren't inserted

我有一个由 3 个 Cassandra 2.0 节点组成的集群。我的应用程序我写了一个测试,试图写入和读取一些数据 into/from Cassandra。一般来说,这工作正常。

奇怪的是,在我重新启动计算机后,这个测试会失败,因为在写入之后我读取了我之前写入的相同值并且在那里我得到了 null 而不是值,但是写入时也不例外. 如果我手动截断使用的列族,测试将通过。之后我可以按我想要的频率执行这个测试,它一次又一次地通过。此外,Cassandra 中是否有值并不重要。结果总是一样的。

如果我查看 CLI 和 CQL-shell 有两种不同的观点:

有人知道哪里出了问题吗?重新执行后,CLI 中的时间戳更新了,所以这似乎是一个读取问题?

我的部分代码: 对于插入,我尝试了

Insert.Options insert =   QueryBuilder.insertInto(KEYSPACE_NAME,TABLENAME)
                .value(ID, id)
                .value(JAHR, zonedDateTime.getYear())
                .value(MONAT, zonedDateTime.getMonthValue())
                .value(ZEITPUNKT, date)
                .value(WERT, entry.getValue())
                .using(timestamp(System.nanoTime() / 1000));

Insert insert = QueryBuilder.insertInto(KEYSPACE_NAME,TABLENAME)
                .value(ID, id)
                .value(JAHR, zonedDateTime.getYear())
                .value(MONAT, zonedDateTime.getMonthValue())
                .value(ZEITPUNKT, date)
                .value(WERT, entry.getValue());

我的select长得像

Select.Where select = QueryBuilder.select(WERT)
            .from(KEYSPACE_NAME,TABLENAME)
            .where(eq(ID, id))
            .and(eq(JAHR, zonedDateTime.getYear()))
            .and(eq(MONAT, zonedDateTime.getMonthValue()))
            .and(eq(ZEITPUNKT, Date.from(instant)));

Consistencylevel 是 QUORUM(对于两者)和 replicationfactor 3

我想说这似乎是时间戳的问题,因为截断解决了这个问题。在 Cassandra 中,最后一次写入获胜,这可能是由于使用 System.nanoTime() since

引起的问题

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.

...

The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.

http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()

这意味着与重启后的写入相比,重启前发生的写入可能“在未来”执行。这不会使查询失败,但由于存在可用的“较新”值,写入值将根本不可见。

您是否要求插入时间戳使用亚毫秒精度?如果可能的话,我建议使用 System.currentTimeMillis() 而不是 nanoTime()。

http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#currentTimeMillis()

如果您需要使用亚毫秒精度,则可以将 System.currentTimeMillis() 与某种介于 0-999 之间的原子计数器一起使用,然后将其用作时间戳。但是,如果多个客户端同时插入同一行,这将中断。