我有一个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)。
我的问题是:
如果有一些方法可以加速初始化和AddMessageAsync操作,我甚至可以在Storage Queue上返回任何帮助。
谢谢
答案 0 :(得分:1)
伟大的Qstn!这是我的看法:
var msgFactory = MessagingFactory.CreateFromConnectionString(@"Endpoint=amqps://---namespaceName----.servicebus.windows.net;SharedAccessKeyName=---SasKeyName----;SharedAccessKey=----SasKey----");
var ehClient = msgFactory.CreateEventHubClient("----eventHubName----");
HTH! SREE
答案 1 :(得分:0)
如果您每个服务器每秒生成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 - ,并且不会丢失任何消息。