【问题标题】:Cassandra - Write doesn't fail, but values aren't insertedCassandra - 写入不会失败,但不会插入值
【发布时间】:2015-10-15 05:23:43
【问题描述】:

我有一个由 3 个 Cassandra 2.0 节点组成的集群。我的应用程序我编写了一个测试,它试图向 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.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

【问题讨论】:

  • 您能发布您的应用程序端查询和 INSERT 代码吗?
  • 您使用什么一致性级别进行读取和写入?您的键空间上的复制因子是多少?
  • 这通常发生在使用默认的 ONE 一致性级别而不是 QUORUM。除非明确设置,否则 cqlsh shell 使用 ONE。如果您等待一两秒钟或再试一次,您会得到正确的值吗?
  • 你说一致性级别是 QUORUM 但我没有看到它设置在查询生成器构建的查询上?
  • 在执行每条语句之前我会做statement = statement.setConsistencyLevel(ConsistencyLevel.QUORUM); 但即使我等了一个小时,测试也会失败。在截断列族之后,测试通过了。

标签: cassandra cql cassandra-2.0 datastax-java-driver cassandra-cli


【解决方案1】:

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

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。

...

只有在计算同一 Java 虚拟机实例中获得的两个此类值之间的差异时,此方法返回的值才有意义。

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 之间的原子计数器一起使用,然后将其用作时间戳。但是,如果多个客户端同时插入同一行,这将中断。

【讨论】:

  • 谢谢。现在我使用long currentTimeMicros = currentTimeMillis * 1000 + nanoTime / 1000 - (nanoTime > 1000000 ? (nanoTime / 1000000) * 1000 : 0); 得到微秒,这对我有用。
  • @Marcus Olsson 这条线是什么意思the write that occured before the restart could have been performed "in the future" compared to the write after the restart?这是否意味着如果 Cassandra 收到带有未来时间戳但在 Cassandra 中尚未达到的内容,它可以忽略写入?我们看到了类似的问题,但我们正在使用其他系统的System.currentTimeMillis()
猜你喜欢
  • 2012-09-07
  • 2016-03-29
  • 2014-11-23
  • 2015-12-31
  • 2020-04-24
  • 2016-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多