我的一个角色实例需要同时从20-40个EventHub分区读取数据(上下文:这是我们的内部虚拟分区方案--20-40个分区代表横向扩展单元)。
在我的原型中,我使用下面的代码。通过我获得最大8 MBPS的吞吐量。因为如果我多次运行相同的控制台,我的吞吐量(perfmon计数器)相应地相乘,那么我认为这既不是VM网络限制也不是EventHub服务端限制。
我想知道我是否在这里正确创建了客户......
谢谢! 扎基
const string EventHubName = "...";
const string ConsumerGroupName = "...";
var connectionStringBuilder = new ServiceBusConnectionStringBuilder();
connectionStringBuilder.SharedAccessKeyName = "...";
connectionStringBuilder.SharedAccessKey = "...";
connectionStringBuilder.Endpoints.Add(new Uri("sb://....servicebus.windows.net/"));
connectionStringBuilder.TransportType = TransportType.Amqp;
var clientConnectionString = connectionStringBuilder.ToString();
var eventHubClient = EventHubClient.CreateFromConnectionString(clientConnectionString, EventHubName);
var runtimeInformation = await eventHubClient.GetRuntimeInformationAsync().ConfigureAwait(false);
var consumerGroup = eventHubClient.GetConsumerGroup(ConsumerGroupName);
var offStart = DateTime.UtcNow.AddMinutes(-10);
var offEnd = DateTime.UtcNow.AddMinutes(-8);
var workUnitManager = new WorkUnitManager(runtimeInformation.PartitionCount);
var readers = new List<PartitionReader>();
for (int i = 0; i < runtimeInformation.PartitionCount; i++)
{
var reader = new PartitionReader(
consumerGroup,
runtimeInformation.PartitionIds[i],
i,
offStart,
offEnd,
workUnitManager);
readers.Add(reader);
}
internal async Task Read()
{
try
{
Console.WriteLine("Creating a receiver for '{0}' with offset {1}", this.partitionId, this.startOffset);
EventHubReceiver receiver = await this.consumerGroup.CreateReceiverAsync(this.partitionId, this.startOffset).ConfigureAwait(false);
Console.WriteLine("Receiver for '{0}' has been created.", this.partitionId);
var stopWatch = new Stopwatch();
stopWatch.Start();
while (true)
{
var message =
(await receiver.ReceiveAsync(1, TimeSpan.FromSeconds(10)).ConfigureAwait(false)).FirstOrDefault();
if (message == null)
{
continue;
}
if (message.EnqueuedTimeUtc >= this.endOffset)
{
break;
}
this.processor.Push(this.partitionIndex, message);
}
this.Duration = TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
答案 0 :(得分:1)
您提供的上述代码段实际上是:创建1个连接到ServiceBus服务,然后在一个连接上运行所有接收器(在protocl级别,基本上,在同一连接上创建多个Amqp链接< /强>)。
或者 - 为了实现接收操作的高吞吐量,您需要创建多个连接并将 接收器映射到连接比率 微调您的吞吐量。这就是在多个进程中运行上述代码时会发生的情况。
以下是:
您需要在.Net客户端SDK API和MessagingFactory级别的代码中使用一层 - 您可以从每个EventHubClient的1个MessagingFactory 开始。 MessagingFactory就是一个 - 它代表1连接到EventHubs服务。用于为每个EventHubClient创建专用连接的代码:
var connStr = new ServiceBusConnectionStringBuilder("Endpoint=sb://servicebusnamespacename.servicebus.windows.net/;SharedAccessKeyName=saskeyname;SharedAccessKey=sakKey");
connStr.TransportType = TransportType.Amqp;
var msgFactory = MessagingFactory.CreateFromConnectionString(connStr.ToString());
var ehClient = msgFactory.CreateEventHubClient("teststream");
如果你使用每个EventHubClient的1个MessagingFactory(或合理的比例)重写你的代码 - 你们都已经设置好了(在你的代码中 - 你需要将EventHubClient创建移动到Reader)!
创建多个连接时需要考虑的唯一额外条件是Bill - only 100 connections are included (including senders and receivers) in basic sku。我猜你已经达到了标准(因为你有> 1个TU) - 它提供了包中包含的1000个连接 - 所以不必担心 - 但只提一下这种情况。
〜SREE
答案 1 :(得分:0)
一个好的选择是为每个分区创建一个任务。 这是我的实现的副本,它能够处理每个分区每秒2.5k消息的速率。此费率也与您的下游速度有关。
static void EventReceiver()
{
for (int i = 0; i <= EventHubPartitionCount; i++)
{
Task.Factory.StartNew((state) =>
{
Console.WriteLine("Starting worker to process partition: {0}", state);
var factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", "tests-eventhub", ""), new MessagingFactorySettings()
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider("Listen", "PGSVA7L="),
TransportType = TransportType.Amqp
});
var client = factory.CreateEventHubClient("eventHubName");
var group = client.GetConsumerGroup("customConsumer");
Console.WriteLine("Group: {0}", group.GroupName);
var receiver = group.CreateReceiver(state.ToString(), DateTime.Now);
while (true)
{
if (cts.IsCancellationRequested)
{
receiver.Close();
break;
}
var messages = receiver.Receive(20);
messages.ToList().ForEach(aMessage =>
{
// Process your event
});
Console.WriteLine(counter);
}
}, i);
}
}