尝试通过前缀删除所有键并重新放入时,在txn请求中给出重复键

Kir*_*ill 8 etcd etcd3

尝试coreos/jetcd用于etcd从Java代码更新haproxy设置.

我想要实现的是:

  1. 删除单个主机的所有端点
  2. 为给定的主机添加更新的数据

我想通过前缀删除所有键,并将实际数据作为原子操作放入etcd中.

这就是我尝试使用etcd交易的原因.我的代码是:

Op.DeleteOp deleteOp = Op.delete(
        fromString(prefix),
        DeleteOption.newBuilder().withPrefix(fromString(prefix)).build()
);
Txn tx = kvClient.txn().Else(deleteOp);
newKvs.forEach((k,v) -> {
    tx.Else(Op.put(fromString(k), fromString(v), DEFAULT));
});
try {
    tx.commit().get();
} catch (InterruptedException | ExecutionException e) {
    log.error("ETCD transaction failed", e);
    throw new RuntimeException(e);
}
Run Code Online (Sandbox Code Playgroud)

使用ETCD v3 API(etcd v3.2.9).KVstore最初是空的,我想添加3条记录. prefix价值是:

/proxy-service/hosts/example.com
Run Code Online (Sandbox Code Playgroud)

并且kvs是一张地图:

"/proxy-service/hosts/example.com/FTP/0" -> "localhost:10021"
"/proxy-service/hosts/example.com/HTTPS/0" -> "localhost:10443"
"/proxy-service/hosts/example.com/HTTP/0" -> "localhost:10080"
Run Code Online (Sandbox Code Playgroud)

异常发生在commit().get()以下根本原因:

Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: etcdserver: duplicate key given in txn request
    at io.grpc.Status.asRuntimeException(Status.java:526)
    at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:427)
    at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:41)
    at com.coreos.jetcd.internal.impl.ClientConnectionManager$AuthTokenInterceptor$1$1.onClose(ClientConnectionManager.java:267)
    at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:419)
    at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:60)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:493)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$500(ClientCallImpl.java:422)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:525)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:102)
    ... 3 more
Run Code Online (Sandbox Code Playgroud)

我做错了什么以及如何在原子操作中完成几个etcd更改?

小智 0

看起来删除一个键然后为同一键添加新值的操作不能在同一个txn. 根据etcd APIv3 文档

Txn 在单个事务中处理多个请求。txn 请求会增加键值存储的修订版本,并为每个完成的请求生成具有相同修订版本的事件。不允许在一次 txn 内多次修改同一密钥