Cassandra更新不一致
我在本地(mac)机器和远程unix服务器上运行以下代码:
public void deleteValue(final String id, final String value) { log.info("Removing value " + value); final Collection 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 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 getValues(final String id) { try { final OperationResult<ColumnList> operationResult = keyspace .prepareQuery(VALUES_CF).getKey(id).execute(); final ColumnList result = operationResult.getResult(); if (result.isEmpty()) { log.info("No value found for id: " + id); return new ArrayList(); } return result.getColumnNames(); } catch (final ConnectionException e) { log.error("Unable to retrieve session " + id, e); } return new ArrayList(); }
在本地,该行永远不会被执行,这是有道理的:
log.error("value " + value + " was supposed to be removed from list " + valuesBeforeRemoval + " but it wasn't: " + valuesAfterRemoval);
但该行在我的开发服务器上执行:
[错误] [主要] [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
- 我的本地计算机和远程开发服务器都连接到同一个cassandra实例。
- 我的本地计算机和远程开发服务器都运行相同的测试,创建一个新的行系列,并在删除一个之前添加10个记录。
- 当dev,log.error发生错误时(“无法删除位置”+值,e); 没有执行(即运行删除命令没有产生任何exception)。
- 当我在dev上运行测试时,我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 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);
要进行调试,请尝试打印整行而不仅仅是列名。 当我说完整行时,我的意思是列名,列值和时间戳。 很长一段时间是你的一台测试机器上的时钟错误,而这是另一方面的测试。
另一件需要仔细检查的事情是,在你的应用程序和cassandra中,ip确实是你的想法。 当你检索它时,在println(“ – ”+ ip“ – ”)之类的东西之间打印。 在deleteSecureLocation中执行try块之前和之后,只对该列执行get,而不是整行。 我不太确定如何在astynax中做到这一点,在cli它会得到[id] [ip]。
需要记住的是,即使没有任何内容可以删除,删除也不会失败。 对于cassandra它是一个写入,唯一能使它成为删除的是如果在读取它是针对该行/列名称的最新时间戳条目。