【发布时间】:2013-02-26 20:49:35
【问题描述】:
我在本地 (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);
但该行是在我的开发服务器上执行的:
[错误] [main] [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% 肯定没有其他代码影响 数据库,而我在 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代码中引用的keyspace是如何定义的:
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 毫秒,则代码开始通过。比如说,100 毫秒的延迟没有帮助。我还修改了构建器,将默认的读写一致性设置为最苛刻的:ALL,这对测试结果没有影响(大约一半的时间仍然失败,除非写入之间的延迟>1s):
final AstyanaxConfigurationImpl conf = new AstyanaxConfigurationImpl()
.setDiscoveryType(NodeDiscoveryType.NONE)
.setRetryPolicy(new RunOnce()).setDefaultReadConsistencyLevel(ConsistencyLevel.CL_ALL).setDefaultWriteConsistencyLevel(ConsistencyLevel.CL_ALL);
【问题讨论】:
-
您是否了解墓碑行为并防范它?我不熟悉 astyanax API,但是当您执行删除时,有问题的项目将继续出现在结果中,直到 Cassandra 清理它,您需要仔细查看结果以查看该项目是否实际被删除。
-
嗯,不,我对墓碑行为一无所知,从我读到的内容来看,这可能是原因,尽管这不能很好地解释为什么它发生在我的机器上而不是一个开发人员,除非我连接到 cassandra 的延迟足够长,以至于如果我在开发人员上运行,条目有时间消失。无论如何,我会在你刚才建议的那个角度更仔细地看待这个问题。谢谢。
-
列删除不会显示在 Cassandra 返回的响应中,只有行删除才会显示。所以这是一个你没有读回你立即写的东西的情况。 Cassandra 在使用最终一致性时有这种行为。您使用什么复制策略和复制选项?你读写的一致性级别是多少?很可能删除尚未传播,并且您的读取使用了未看到删除的其他节点。也许你从你的 unix 机器上的连接比你的 mac 快,所以你只能在那里看到它。
-
据我所知,你们都描述了同样的问题并且确实是正确的:我在读取我已删除的数据之前插入了 1 秒的延迟并且没有看到任何不一致之处。你们中是否至少有一个人想将您的评论作为答案,以便我接受?理查德,我正在使用 placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy' 和 strategy_options = {replication_factor:1};现在我可以看到,我可以为我的查询设置一致性级别,以覆盖 Astyaniax 使用的任何默认值。
-
如果你真的使用replication_factor 1 这无法解释,除非你使用ConsistencyLevel ANY 进行写入,这几乎肯定不是Astyanax 的默认设置。除了 CL.ANY 写入之外,RF 1 数据始终是一致的。您可以粘贴您的架构吗?