ローカル (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);
しかし、その行は私の開発サーバーで実行されます:
[エラー] [メイン] [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 を使用しています
- ローカル マシンとリモート dev サーバーの両方がまったく同じ cassandra インスタンスに接続しています。
- 私のローカル マシンとリモート開発サーバーの両方で、まったく同じテストが実行され、新しい行ファミリーが作成され、1 つが削除される前に 10 個のレコードが追加されます。
- dev でエラーが発生した場合、log.error("ロケーションを削除できませんでした" + value, e); 実行されませんでした (つまり、削除コマンドを実行しても例外は発生しませんでした)。
- 私は 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<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());
}
2回目の更新
まず、問題は削除だけに関連するものではありません。データベース内のレコードを更新し、それらを読み取り、書き込んだばかりの更新を読み取ることができないときに、同様の問題を観察します
次に、次の操作を 100 回実行するテストを作成しました。
- カサンドラに行を書き込む
- カサンドラでその行を更新します
- カサンドラからその行を読み返し、行が実際に更新されたかどうかを確認し、更新されていない場合は遅延後に定期的に再度確認します
そのテストから私が観察したことは、次のことです。
- 繰り返しますが、そのコードをローカルで実行すると、100 回の反復すべてがすぐに完了します (再試行は必要ありません)。
- そのコードをリモートサーバーで実行すると、繰り返しの一部が成功し、一部が失敗します。それらが失敗すると、遅延がどれほど大きくても (私は最大 10 秒待ちます)、テストは常に失敗します。
この時点で、テストのためにまったく同じサーバーに接続し、挿入する遅延が接続時にテストを実行する必要がある可能性のある追加の遅延よりもはるかに大きいため、cassandra のセットアップがこの動作をどのように説明できるかは本当にわかりません。私のローカルマシンから。
唯一の関連する違いは、コードが実行されているマシンのようです。
3回目の更新
前回の更新で説明したテストで、2 つの書き込みの間に遅延を挿入すると、遅延が 1,000 ミリ秒以上の場合にコードが通過し始めます。たとえば、100 ミリ秒の遅延は役に立ちません。また、デフォルトの読み取りと書き込みの一貫性を最も要求の厳しい ALL に設定するようにビルダーを変更しましたが、テストの結果には影響しませんでした (書き込み間の遅延が 1 秒を超えない限り、約半分の時間で失敗します)。
final AstyanaxConfigurationImpl conf = new AstyanaxConfigurationImpl()
.setDiscoveryType(NodeDiscoveryType.NONE)
.setRetryPolicy(new RunOnce()).setDefaultReadConsistencyLevel(ConsistencyLevel.CL_ALL).setDefaultWriteConsistencyLevel(ConsistencyLevel.CL_ALL);