英文:
How to use different ports using Couchbase Java SDK 3
问题
Context:
我正在使用 Docker 编写一些集成测试(使用 testcontainers)。并且我想使用 toxiproxy 连接到 couchbase。
The problem:
我无法使用与默认端口不同的端口连接到 couchbase。文档上说只需使用 SeedNode,但不起作用。
Client:
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>3.0.5</version>
</dependency>
Couchbase setup:
echo "Initializing new cluster"
docker-compose exec couchbase \
couchbase-cli cluster-init -c 127.0.0.1 --cluster-username Administrator --cluster-password password \
--services data,index,query --cluster-ramsize 4096
echo "Creating new bucket"
docker-compose exec couchbase \
couchbase-cli bucket-create -c couchbase:8091 --username Administrator \
--password password --bucket default --bucket-type couchbase \
--bucket-ramsize 1024
It works:
services:
couchbase:
image: couchbase:latest
volumes:
- .couchbase:/opt/couchbase/var
ports:
- "8091:8091"
- "11210:11210"
SeedNode seedNode = SeedNode.create("127.0.0.1", Optional.of(11210), Optional.of(8091));
ClusterOptions clusterOptions = ClusterOptions.clusterOptions("Administrator", "password");
Cluster cluster = Cluster.connect(Collections.singleton(seedNode), clusterOptions);
Bucket bucket = cluster.bucket("default");
Collection collection = bucket.defaultCollection();
collection.insert("key", "Hello, Couchbase!");
It doesn't work:
services:
couchbase:
image: couchbase:latest
volumes:
- .couchbase:/opt/couchbase/var
ports:
- "28091:8091"
- "21210:11210"
SeedNode seedNode = SeedNode.create("127.0.0.1", Optional.of(21210), Optional.of(28091));
Error:
我看到很多警告,如下所示:
[cb-events] WARN com.couchbase.endpoint - [com.couchbase.endpoint][EndpointConnectionFailedEvent][1282us] Connect attempt 7 failed because of AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:11210 {"bucket":"default","circuitBreaker":"DISABLED","coreId":"0xdf4c6e800000001","remote":"127.0.0.1:11210","type":"KV"}
com.couchbase.client.core.deps.io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:11210
并且在插入行上失败:
com.couchbase.client.core.error.AmbiguousTimeoutException: InsertRequest
{"cancelled":true,"completed":true,"coreId":"0xdf4c6e800000001","idempotent":false,"reason":"TIMEOUT","requestId":3,"requestType":"InsertRequest","retried":14,"retryReasons":["ENDPOINT_NOT_AVAILABLE","BUCKET_OPEN_IN_PROGRESS"],"service":{"bucket":"default","collection":"_default","documentId":"key","opaque":"0x2","scope":"_default","syncDurability":{"present":false},"type":"kv"},"timeoutMs":2500,"timings":{"encodingMicros":5015,"totalMicros":2509788}}
...
使用 CouchbaseContainer 取代我自己的 docker-compose 后,它可以使用容器的随机端口正常工作,但对我来说不够,因为我想设置 toxiproxy 端口。这是一个 bug 还是我做错了什么?
英文:
Context:
I'm writing some integration tests using docker (using testcontainers).
And I want to connect to couchbase using toxiproxy.
The problem:
I can't connect to couchbase using different ports than the default ones.
The docs says to just use SeedNode, but it does not work.
Client:
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>3.0.5</version>
</dependency>
Couchbase setup:
echo "Initializing new cluster"
docker-compose exec couchbase \
couchbase-cli cluster-init -c 127.0.0.1 --cluster-username Administrator --cluster-password password \
--services data,index,query --cluster-ramsize 4096
echo "Creating new bucket"
docker-compose exec couchbase \
couchbase-cli bucket-create -c couchbase:8091 --username Administrator \
--password password --bucket default --bucket-type couchbase \
--bucket-ramsize 1024
It works:
services:
couchbase:
image: couchbase:latest
volumes:
- .couchbase:/opt/couchbase/var
ports:
- "8091:8091"
- "11210:11210"
SeedNode seedNode = SeedNode.create("127.0.0.1", Optional.of(11210), Optional.of(8091));
ClusterOptions clusterOptions = ClusterOptions.clusterOptions("Administrator", "password");
Cluster cluster = Cluster.connect(Collections.singleton(seedNode), clusterOptions);
Bucket bucket = cluster.bucket("default");
Collection collection = bucket.defaultCollection();
collection.insert("key", "Hello, Couchbase!");
It doesn't work:
services:
couchbase:
image: couchbase:latest
volumes:
- .couchbase:/opt/couchbase/var
ports:
- "28091:8091"
- "21210:11210"
SeedNode seedNode = SeedNode.create("127.0.0.1", Optional.of(21210), Optional.of(28091));
Error:
I see many warnings like:
[cb-events] WARN com.couchbase.endpoint - [com.couchbase.endpoint][EndpointConnectionFailedEvent][1282us] Connect attempt 7 failed because of AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:11210 {"bucket":"default","circuitBreaker":"DISABLED","coreId":"0xdf4c6e800000001","remote":"127.0.0.1:11210","type":"KV"}
com.couchbase.client.core.deps.io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:11210
And it fails on the insert line:
com.couchbase.client.core.error.AmbiguousTimeoutException: InsertRequest
{"cancelled":true,"completed":true,"coreId":"0xdf4c6e800000001","idempotent":false,"reason":"TIMEOUT","requestId":3,"requestType":"InsertRequest","retried":14,"retryReasons":["ENDPOINT_NOT_AVAILABLE","BUCKET_OPEN_IN_PROGRESS"],"service":{"bucket":"default","collection":"_default","documentId":"key","opaque":"0x2","scope":"_default","syncDurability":{"present":false},"type":"kv"},"timeoutMs":2500,"timings":{"encodingMicros":5015,"totalMicros":2509788}}
at com.couchbase.client.java.AsyncUtils.block(AsyncUtils.java:51)
at com.couchbase.client.java.Collection.insert(Collection.java:381)
at ToxyproxyCouchbaseIT.testCouchbase(ToxyproxyCouchbaseIT.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Suppressed: java.lang.Exception: The above exception was originally thrown by another thread at the following location.
at com.couchbase.client.core.msg.BaseRequest.cancel(BaseRequest.java:163)
at com.couchbase.client.core.Timer.lambda$register$2(Timer.java:157)
at com.couchbase.client.core.deps.io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:672)
at com.couchbase.client.core.deps.io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:747)
at com.couchbase.client.core.deps.io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:472)
at com.couchbase.client.core.deps.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Somehow, using CouchbaseContainer instead of my own docker-compose it works with container's random ports, but it's not enough for me because I want to set toxiproxy ports instead.
Is it a bug or am I doing something wrong?
答案1
得分: 1
为了回答问题(但不幸的是无法解决 OP 的问题),在 SDK 3 中,您可以像这样指定自定义 KV 端口:
Cluster cluster = Cluster.connect("localhost:12345", username, password);
如果您不知道 KV 端口,您可以像这样指定管理端口:
Cluster cluster = Cluster.connect("localhost:45678=manager", username, password);
(作为替代方案,您可以创建 SeedNode
对象,但我个人认为那有点繁琐。)
为了使自定义端口起作用,您需要使用支持 alternate addresses 的 Couchbase Server 6.5 或更高版本,并使用 setting-alternate-address 命令配置 Couchbase 以使用 "external" 地址来广播非标准端口。
SDK 使用传递给 Cluster.connect
的地址来引导连接。一旦连接到服务器,它会丢弃您提供的地址,而是使用从服务器获取的地址。服务器需要配置为报告 "external" 地址,以便告诉客户端将来请求时使用哪些主机和端口。
英文:
To answer the question (but not solve OP's problem, unfortunately), with SDK 3 you can specify a custom KV port like this:
Cluster cluster = Cluster.connect("localhost:12345", username, password);
If you don't know the KV port, you can specify a manager port like this:
Cluster cluster = Cluster.connect("localhost:45678=manager", username, password);
(As an alternative you can create SeedNode
objects, but personally I find that a bit cumbersome.)
In order for custom ports to work, you will need to use Couchbase Server 6.5 or later which supports alternate addreses, and use the setting-alternate-address command to configure Couchbase to advertise the non-standard ports using "external" addresses.
The SDK uses the addresses passed to Cluster.connect
to bootstrap the connections. Once it connects to the server, it throws away the addresses you gave it and instead uses the addresses it gets from the server. The server needs to be configured to report the "external" addresses so it can tell the client which hosts and ports to use for future requests.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论