Cassandra更新不一致

时间:2013-03-11 15:37:19

标签: java cassandra astyanax

我在本地(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);

但该行在我的开发服务器上执行:

[错误] [主要] [n.o.w.s.d.SessionDaoCassandraImpl] [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
  • 我的本地计算机和远程开发服务器都连接到了 同样的cassandra实例。
  • 我的本地计算机和远程开发服务器都运行相同的测试 创建一个新的行系列,并在删除一个之前添加10个记录。
  • 当dev,log.error发生错误时(“无法删除 location“+ value,e);未执行(即运行删除) 命令没有产生任何异常)。
  • 我100%肯定没有其他代码影响到的内容 数据库,而我在开发运行测试,所以这不是一些 奇怪的并发问题。

什么可以解释deleteColumn(value)请求运行时没有产生任何错误但仍然没有从数据库中删除该列?

附加信息

以下是我创建键空间的方法:

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次以下操作:

    • 在cassandra中写一行
    • 更新cassandra中的那行
    • 从cassandra读回那行并检查该行是否确实已更新,如果不是
    • 则会在延迟后定期检查

    我从该测试中观察到的是:

    • 再次,当我在本地运行该代码时,所有100次迭代立即通过(不需要重试)
    • 当我在远程服务器上运行该代码时,一些迭代通过,一些失败。当它们失败时,无论延迟有多大(我等待10秒),测试总是失败。

此时,我真的不确定任何cassandra设置如何解释这种行为,因为我连接到我的测试的同一台服务器,因为我插入的延迟远远大于我可能需要运行的任何额外延迟从本地计算机连接时测试。

唯一相关的差异似乎是运行代码的机器。

第三次更新

如果在上一次更新中提到的测试中,我在2次写入之间插入延迟,则如果延迟> = 1,000 ms,则代码开始通过。延迟,例如,100毫秒没有帮助。我还修改了构建器,将默认的读写和一致性设置为最苛刻的:ALL,这对测试结果没有影响(除非写入之间的延迟> 1s,否则仍然会失败大约一半的时间):

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

1 个答案:

答案 0 :(得分:1)

要进行调试,请尝试打印整行而不仅仅是列名。当我说完整行时,我的意思是列名,列值和时间戳。很长一段时间是你的一台测试机器上的时钟错误,而这是另一方面的测试。

另一件需要仔细检查的事情是,在你的应用程序和cassandra中,ip确实是你的想法。当你检索它时,它会在某些东西之间打印出来,比如println(&#34; - &#34; + ip&#34; - &#34;)。在deleteSecureLocation中执行try块之前和之后,只对该列执行get,而不是整行。我不太确定如何在astynax中做到这一点,在cli上它会得到[id] [ip]。

要记住的是,即使没有删除内容,删除也不会失败。为了使它成为一个写入,唯一能使它成为删除的是,如果在读取时它是针对该行/列名称的最新时间戳记条目。