我在本地 (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("Unable to delete location "+ value, e); 未执行(即运行删除 命令没有产生任何异常)。
- 我 100% 肯定没有其他代码影响 我在 dev 上运行测试时的数据库,所以这不是一些 奇怪的并发问题。
有什么可能解释 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 设置如何解释这种行为,因为我连接到同一台服务器进行测试,并且因为我插入的延迟比我可能需要运行的任何额外延迟大得多从我的本地计算机连接时进行测试。
唯一相关的区别似乎是代码在哪台机器上运行。
第三次更新
如果在之前更新中提到的测试中,我在两次写入之间插入了一个延迟,如果延迟 >= 1,000 毫秒,代码将开始通过。比方说 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 block 之前和之后,只获取该列,而不是整行。我不太确定如何在 astynax 中执行此操作,在 cli 上它将是 get[id][ip]。
请记住,即使没有可删除的内容,删除也不会失败。对 cassandra 来说,它是一个写入,唯一会导致它被删除的是,如果在读取时它是针对该行/列名称的最新时间戳条目。
关于java - Cassandra 更新不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15342621/