You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EventStoreDB三节点集群gRPC连接失败问题求助

EventStoreDB集群连接问题排查

我在Azure VM上部署了3节点EventStoreDB集群,使用C#代码连接并追加事件流时,出现**DiscoveryException(10次尝试未发现候选节点)及Grpc.Core.RpcException(StatusCode=DeadlineExceeded)**错误。本地可通过telnet连通节点地址,但gRPC连接存在问题。以下是相关信息:

客户端代码

var settings = EventStoreClientSettings.Create("esdb://admin:changeit@{node1IP}:2113,{node2IP}:2113,{node3IP}:2113?tls=true&tlsVerifyCert=false&keepAliveTimeout=10000&keepAliveInterval=10000");

var client = new EventStoreClient(settings);
                
var evt = new 
{
    EntityId = Guid.NewGuid().ToString("N"),
    ImportantData = "I wrote my first event!"
};
                
var eventData = new EventData(
    Uuid.NewUuid(),
    "TestEvent",
    JsonSerializer.SerializeToUtf8Bytes(evt)
);
                
await client.AppendToStreamAsync(
    "some-stream",
    StreamRevision.None, 
    new[] { eventData });
                
var result = client.ReadStreamAsync(
    Direction.Forwards,
    "some-stream",
    StreamPosition.Start);
                
var events = await result.ToListAsync();
foreach (var eventIn in events)
{
    Console.WriteLine($"event: {eventIn.ToString()}\n");
}

核心错误信息

DiscoveryException: Failed to discover candidate in 10 attempts.

节点配置文件(其余节点仅IP不同)

---
# Paths
Db: /var/lib/eventstore
Index: /var/lib/eventstore/index
Log: /var/log/eventstore
LogLevel: Information
# LogFileInterval: 62
LogFileRetentionCount: 100

SkipDbVerify: True
SkipIndexVerify: True
ChunksCacheSize: 1073741824
CachedChunks: 4

# Certificates configuration
CertificateFile: /etc/eventstore/certs/node.crt
CertificatePrivateKeyFile: /etc/eventstore/certs/node.key
TrustedRootCertificatesPath: /etc/eventstore/certs/ca

# Network configuration
## TCP/IP Settings
IntIp: 10.3.0.4
ExtIp: 10.3.0.4
IntTcpPort: 1112
ExtTcpPort: 1113
IntTcpHeartbeatInterval: 5000
IntTcpHeartbeatTimeout: 2000
ExtTcpHeartbeatInterval: 5000
ExtTcpHeartbeatTimeout: 2000

## HTTP Settings
HttpPort: 2113
HttpPortAdvertiseAs: 2113

# Cluster gossip
ClusterSize: 3
DiscoverViaDns: false
GossipSeed: 10.3.0.5:2113,10.3.0.6:2113

# Projections configuration
RunProjections: All
StartStandardProjections: True

# Misc Settings
EnableExternalTcp: True
EnableAtomPubOverHTTP: True
---

控制台错误日志

Grpc.Core.RpcException: Status(StatusCode="DeadlineExceeded", Detail="")
   at EventStore.Client.Interceptors.TypedExceptionInterceptor.<AsyncUnaryCall>b__5_0[TRequest,TResponse](Task`1 t)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at EventStore.Client.GrpcServerCapabilitiesClient.GetAsync(CallInvoker callInvoker, CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClientBase.GetChannelInfoExpensive(ReconnectionRequired reconnectionRequired, Action`1 onReconnectionRequired, IChannelSelector channelSelector, CancellationToken cancellationToken)
   at EventStore.Client.SharingProvider`2.FillBoxAsync(TaskCompletionSource`1 box, TInput input)
   at EventStore.Client.TaskExtensions.WithCancellation[T](Task`1 task, CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClientBase.GetChannelInfo(CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClient.<CreateStreamAppender>g__GetCall|14_0()
   at EventStore.Client.EventStoreClient.StreamAppender.IsUsable()
   at EventStore.Client.EventStoreClient.AppendToStreamAsync(String streamName, StreamRevision expectedRevision, IEnumerable`1 eventData, Action`1 configureOperationOptions, Nullable`1 deadline, UserCredentials userCredentials, CancellationToken cancellationToken)
   at TestClusterConnection.Program.Main() in /Users/krishna/Desktop/TestClusterConnection/TestClusterConnection/Program.cs:line 97
Unhandled exception. Grpc.Core.RpcException: Status(StatusCode="DeadlineExceeded", Detail="")
   at EventStore.Client.Interceptors.TypedExceptionInterceptor.<AsyncUnaryCall>b__5_0[TRequest,TResponse](Task`1 t)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at EventStore.Client.GrpcServerCapabilitiesClient.GetAsync(CallInvoker callInvoker, CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClientBase.GetChannelInfoExpensive(ReconnectionRequired reconnectionRequired, Action`1 onReconnectionRequired, IChannelSelector channelSelector, CancellationToken cancellationToken)
   at EventStore.Client.SharingProvider`2.FillBoxAsync(TaskCompletionSource`1 box, TInput input)
   at EventStore.Client.TaskExtensions.WithCancellation[T](Task`1 task, CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClientBase.GetChannelInfo(CancellationToken cancellationToken)
   at EventStore.Client.EventStoreClient.<CreateStreamAppender>g__GetCall|14_0()
   at EventStore.Client.EventStoreClient.StreamAppender.IsUsable()
   at EventStore.Client.EventStoreClient.AppendToStreamAsync(String streamName, StreamRevision expectedRevision, IEnumerable`1 eventData, Action`1 configureOperationOptions, Nullable`1 deadline, UserCredentials userCredentials, CancellationToken cancellationToken)
   at TestClusterConnection.Program.Main() in /Users/krishna/Desktop/TestClusterConnection/TestClusterConnection/Program.cs:line 97
   at TestClusterConnection.Program.<Main>()

排查与解决步骤

1. 修复集群Gossip配置

当前节点的GossipSeed仅包含其他两个节点,需修改为包含所有集群节点(含自身),确保每个节点的配置一致:

GossipSeed: 10.3.0.4:2113,10.3.0.5:2113,10.3.0.6:2113

修改后重启所有EventStore节点,保证集群内部能正常发现彼此。

2. 检查Azure网络规则

  • 确认Azure NSG(网络安全组)允许2113端口(gRPC/HTTP)、**1112/1113端口(内部/外部TCP)**的入站/出站流量,覆盖客户端IP和集群VM的IP范围。
  • 检查VM本地防火墙,确保上述端口未被拦截。

3. 调整客户端连接参数

  • 在连接字符串中添加discover=false,强制客户端使用指定节点列表,跳过集群自动发现:
    var settings = EventStoreClientSettings.Create("esdb://admin:changeit@{node1IP}:2113,{node2IP}:2113,{node3IP}:2113?tls=true&tlsVerifyCert=false&keepAliveTimeout=10000&keepAliveInterval=10000&discover=false");
    
  • 增加gRPC超时时间,避免网络延迟导致超时:
    settings.TimeoutAfter = TimeSpan.FromSeconds(30);
    

4. 验证证书有效性

尽管客户端关闭了证书验证,仍需确保:

  • 节点的node.crt和node.key文件有效,且EventStore进程拥有读取权限。
  • 自签名CA证书已放置在TrustedRootCertificatesPath指定的目录中。

5. 确认集群运行状态

在每个节点执行以下命令,检查集群节点信息:

curl -k https://<node-ip>:2113/cluster/nodeinfo

若返回正常节点数据,说明集群内部通信正常;若无法访问,检查节点服务状态和端口监听:

netstat -tulpn | grep eventstore

内容的提问来源于stack exchange,提问作者Krishna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 09:09:17