【发布时间】:2022-12-10 14:02:18
【问题描述】:
我正在使用event store client for .Net,我正在努力寻找使用客户端的正确方法。当我在 .Net 依赖注入中将客户端注册为单例并在一段较长的时间内运行我的应用程序时,内存使用量随着每次订阅而不断增长。
我通过以下方式创建和注册客户端。可以找到遇到问题的完整最小应用程序here.
var esdbConnectionString = configuration.GetValue("ESDB_CONNECTION_STRING", "esdb://admin:changeit@localhost:2113?tls=false");
var eventStoreClientSettings = EventStoreClientSettings.Create(esdbConnectionString);
var eventStoreClient = new EventStoreClient(eventStoreClientSettings);
services.AddSingleton(eventStoreClient);
我的应用程序在很长一段时间内有大量短流
重现
重现该行为的步骤:
- 按照 documentation 中的建议将 EventStore 客户端注册为单例。
- 在较长时间内订阅大量流。
- 取消发送到流订阅的CancellationToken,让它被垃圾回收。
- 观察服务的内存使用量增长。
我如何创建和订阅流:
var streamName = CreateStreamName(); var payload = new PingEvent { StreamNr = _currentStreamNumber }; var eventData = new EventData(Uuid.NewUuid(), typeof(PingEvent).Name, EventSerialization.SerializeEventData(payload)); await _client.AppendToStreamAsync(streamName, StreamState.Any, new[] { eventData }); var streamCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(30)); await _client.SubscribeToStreamAsync(streamName, FromStream.Start, async (sub, evnt, token) => { if (evnt.Event.EventType == "PongEvent") { _previousStreamIsDone = true; streamCancellationTokenSource.Cancel(); } }, cancellationToken: streamCancellationTokenSource.Token);尝试的方法
注册为 Transient 或 Scoped如果我在 .Net DI 中将客户端注册为 Transient 或 Scoped,它会在内部抛出数千个异常并导致多个问题。
手动处理客户端的生命周期通过拥有处理客户端生命周期的单例服务,我尝试每隔一段时间处理一次客户端并创建一个新客户端,以确保同时只存在一个客户端实例。这会导致与将服务注册为 Transient 或 Scoped 相同的问题。
I am using version 22.0.0 of the Event Store client 在 .Net 6 中针对事件存储数据库 21.10.0。在 Windows 和标准 aspnet:6.0 linux docker 容器上运行时都会出现问题。
通过检查 these dotnet-dumps 的结果,内存增长似乎发生在 gRPC 客户端的 this HashSet of ActiveCalls 内部。
我希望找到一种不会导致内存增长的使用客户端的方法。
【问题讨论】:
标签: dependency-injection grpc .net-6.0 eventstoredb grpc-c#