Azure EventHubs inizialization性能和WebApi2

时间:2016-01-28 04:34:36

标签: asp.net-web-api2 azure-cloud-services azure-queues azure-eventhub azure-storage-queues

我有一个WebApi2控制器,它从JavaScript接收XmlHttpRequests。

我每秒对api进行+500次调用,并且任何请求执行一些快速计算,然后我创建一个Azure存储队列(不是服务总线)传入序列化对象以供以后处理。 直到这里一切正常,问题是10-15%的时间,只是初始化存储队列并添加20k JSON消息需要500ms到2秒之间的时间。 我将请求分成10个不同的队列,但问题仍然存在,似乎与流量没有关系,基本上有时队列只会陷入创建并慢下来。

我已经禁用了Nagle和Expect100Continue。

我想在使用EventHUbs时转换这种架构,因为我的情况可能需要一个事件的摄取器而不是一个简单的队列,需要最大的速度。

但EventHub的初始化具有同样的问题!有时需要2或3秒才能启动和接收单条消息,平均时间为400毫秒。

我用秒表测量了速度。

这是我在API控制器中的代码:

  var eventHubClient = StorageHelpers.InitializeEventHub("name", "Send");
                           await eventHubClient.SendAsync(new EventData(Encoding.UTF8.GetBytes(QueueSerialized)));

InizializeEventHub是:

        public static EventHubClient InitializeEventHub(string eventHubName, string type)
    {
        string connectionString = RoleEnvironment.GetConfigurationSettingValue("Hub"+type+eventHubName);
        return EventHubClient.CreateFromConnectionString(connectionString, eventHubName);}

该服务使用云服务托管在azure上,该服务托管在ServiceBus和存储的同一位置(WestUS)。

我的问题是:

  • 1)这段时间是否正常使用连接?
  • 2)Web Api是否有办法为所有呼叫共享同一个EventHubClient实例?类似于Redis在Lazy类中使用ConnectionMultiplexer完成的任务。
  • 3)我可以缓存EventHubClient对象吗?

如果有一些方法可以加速初始化和AddMessageAsync操作,我甚至可以在Storage Queue上返回任何帮助。

谢谢

3 个答案:

答案 0 :(得分:1)

伟大的Qstn!这是我的看法:

  1. 在Azure最繁忙的一个规模单元(如西部我们)上 - 400毫秒的订单。确实发出了eventhubs发送延迟的可能数量。您正在寻找的平均延迟是多少? 第一个电话需要2-3秒才能创建一个连接&特别是对于SSL协商。这些地区的各种天蓝色服务之间差别不大。这次只有前几个电话才会开始。所有后续调用应按 millis 的顺序排列。 EventHubClient.Send API(there are 3 types of sends - and you are using this 1)专为HighAvailability而设计,它首先将消息发送到高可用性的ServiceBus网关,然后转发到其中一个可用的EventHub分区 - 使其高度可用发送操作。这确实为网关添加了较小的初始化开销,以便在第一次发送时发现分区。可以说,如果您的分区数是4,那么您对该EventHub的前4次发送呼叫可能需要更高的延迟 - &从它们开始 - 它具有很高的性能。
  2. 只要您正在与之交谈的EventHub相同 - 您就可以在WebAPI中共享EventHubClient。每个EventHubClient都与一个Connection相关联。但是,在EventHub .net SDK中,只要2个EventHubClients的连接字符串相同 - 连接将被重用。 这里有一个优化 - 如果你拥有更少的流量,并通过拥有更多的事件集线器来拥有扇出架构:即,如果你的场景有多个eventhubs&所有的EventHub都在单一命名空间中,并且想要使用1个EventHubClient对象(这意味着每个webapi进程只有1个套接字)发送到EventHubs服务,您可以使用MessagingFactory(使用命名空间级别SasKey)来创建EventHubClient。
  3. var msgFactory = MessagingFactory.CreateFromConnectionString(@"Endpoint=amqps://---namespaceName----.servicebus.windows.net;SharedAccessKeyName=---SasKeyName----;SharedAccessKey=----SasKey----"); var ehClient = msgFactory.CreateEventHubClient("----eventHubName----");

    1. 您可以考虑缓存EventHubClient对象。它可以节省几行客户端代码执行,以从缓存中获取MessagingFactory(它保存对Connection的引用)。
    2. HTH! SREE

答案 1 :(得分:0)

  1. 不确定,我从不打扰时间,因为如果你重复使用它,它就不会像它原来那样重要。鉴于network connection gets reused
  2. ,似乎过长
  3. 这取决于缓存的含义。如果你的意思是序列化并在内存中保存,那么没有。如果你的意思是放入ConcurrentBag(像池一样使用它),那么肯定。
  4. 如果您每个服务器每秒生成500个请求,每个20KB,那么您应确认已设置足够的吞吐量单位,因为大于10MB /秒的流入量需要至少10个吞吐量单位。限制可以解释延迟问题。要检查的另一件事是初始化的组件需要花费时间,例如我从未对GetConfigurationSettingValue进行基准测试,并且可能没有进行高速缓存。

    但假设这个问题都不是问题,那么你需要做些什么才能让它变得快速?您当然可以重用EventHubClient或您自己创建的对象来处理创建时间。没有太多连接到WebAPI,简单的方法就是拥有一个包含实例的静态变量(可能在Lazy内部使用构造函数初始化)。重复使用时,您应该知道EventHubClient是not officially threadsafe(虽然发送实际上是),这意味着您需要管理它。但是,单个EventHubClient或多个共享相同网络连接的EventHubClient可能无法为每台服务器提供10MB / s的速度。在这种情况下,我会将注意力转移到this portion of the documentation

      

    最后,还可以从MessagingFactory实例创建EventHubClient对象,如以下示例所示。

    var factory = MessagingFactory.CreateFromConnectionString("your_connection_string"); var client = factory.CreateEventHubClient("MyEventHub");

      

    请务必注意,从消息传递工厂实例创建的其他EventHubClient对象将重用相同的底层TCP连接。因此,这些对象对吞吐量有客户端限制。 Create方法重用单个消息传递工厂。如果您需要来自单个发件人的非常高的吞吐量,那么您可以从每个邮件工厂创建多个邮件工厂和一个EventHubClient对象。

    如果你这样做,那么我强烈建议汇集它们/编写你自己的多路复用器。

答案 2 :(得分:0)

我最终得到了一个疯狂的简单解决方案。 EventHubs和StorageQueues都需要时间进行初始化,特别是在向流添加消息时,EventHubs通常很慢。现在,在99.99%的情况下,300毫秒并不慢,但就我而言,它是。

StorageQueue超级便宜,快速而简单,但随着地狱添加消息而变慢。 经过几个小时的基准测试和其他解决方案检查,如Redis Pub / Sub,我最终使用了StorageQueues,只是没有等待异步调用。

所以标准电话是

await queue.AddMessageAsync(message);

和await部分是问题,如果任务没有回来,WebApi无法返回。应该是火与忘记,但事实并非如此。

我解决了不等待电话的问题,使用变量隐藏警告

var nowait = queue.AddMessageAsync(message);

在任何情况下,队列中的插入都是 -immediate - ,并且不会丢失任何消息。