【发布时间】:2013-02-25 15:50:03
【问题描述】:
我正在使用 cloudQueue.BeginAddMessage 和 EndAddMessage 发送许多消息。 我将尚未返回的开始数量限制为 500。但我遇到了异常,代码为 10048(表示套接字耗尽)。
Microsoft.WindowsAzure.Storage.StorageException: Unable to connect to the remote server ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted
我在搜索后发现的解决方案都建议修改注册表,但是由于这是在 Azure 中的辅助角色中计划的,所以我不能这样做。
我还有其他插入到表服务的功能,它们运行速度一样快但没有任何问题。似乎 EndAddMessage 函数几乎没有关闭连接或其他东西(我对套接字的了解有限)。
我的问题:这里有 azure 方面的错误吗?除了人为地减慢添加消息的速度外,我应该怎么做才能解决这个问题?
这是我用来发送消息的测试函数。在我的情况下,在添加了大约 16500 条消息并且回调正确且稳定地结束后,它会变慢并在一段时间后抛出上述异常。
很抱歉代码太长了,但这应该是复制粘贴,以便您重现问题。
从AsyncCallback endAddCallback抛出异常。
static void Main()
{
Console.SetBufferSize(205, Int16.MaxValue - 1);
// Set the maximum number of concurrent connections (12*6 in my case)
ServicePointManager.DefaultConnectionLimit = 12 * Environment.ProcessorCount;
//setting UseNagleAlgorithm to true reduces network traffic by buffering small packets of data and transmitting them as a single packet, but setting to false can significantly reduce latencies for small packets.
ServicePointManager.UseNagleAlgorithm = false;
//if true, "Expect: 100-continue" header is sent to ensure a call can be made. This uses an entire roundtrip to the service point (azure), so setting to false sends the call directly.
ServicePointManager.Expect100Continue = false;
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(__CONN_STRING);
CloudQueueClient client = storageAccount.CreateCloudQueueClient();
CloudQueue queue = client.GetQueueReference(__QUEUE_NAME);
queue.CreateIfNotExists();
List<Guid> ids = new List<Guid>();
for (Int32 i = 0; i < 40000; i++)
ids.Add(Guid.NewGuid());
SendMessages(queue, ids.Select(id => new CloudQueueMessage(id.ToString())).ToList().AsReadOnly());
}
public static void SendMessages(CloudQueue queue, IReadOnlyCollection<CloudQueueMessage> messages)
{
List<CloudQueueMessage> toSend = messages.ToList();
Object exceptionSync = new Object();
Exception exception = null;
CountdownEvent cde = new CountdownEvent(toSend.Count);
AsyncCallback endAddCallback = asyncResult =>
{
Int32 endedItem = (Int32)asyncResult.AsyncState;
try
{
queue.EndAddMessage(asyncResult);
Console.WriteLine("SendMessages: Ended\t\t{0}\t/{1}", endedItem + 1, toSend.Count);
}
catch (Exception e)
{
Console.WriteLine("SendMessages: Error adding {0}/{1} to queue: \n{2}", endedItem + 1, toSend.Count, e);
lock (exceptionSync)
{
if (exception == null)
exception = e;
}
}
finally { cde.Signal(); }
};
for (Int32 i = 0; i < toSend.Count; i++)
{
lock (exceptionSync)
{
if (exception != null)
throw exception;
}
//if number of added but not ended is larger than the MAX, yield and check again.
while (true)
{
Int32 currentOngoing = (i- (cde.InitialCount - cde.CurrentCount));
if (currentOngoing > 500)
Thread.Sleep(5);
else
break;
}
Console.WriteLine("SendMessages: Beginning\t{0}\t/{1}", i + 1, toSend.Count);
queue.BeginAddMessage(toSend[i], endAddCallback, i);
}
cde.Wait();
if (exception != null)
throw exception;
Console.WriteLine("SendMessages: Done.");
}
【问题讨论】:
-
Azure 中的辅助角色应该授予您通过 OnStart 事件或通过 RDP 修改某些(如果不是全部)密钥的权利。您不能修改的密钥是什么?
-
我不知道我可以在工作角色中修改注册表?键是 HKLM\System\CurrentControlSet\Services\Tcpip\Parameters(值 MaxUserPort 和 TCPTimeWaitDelay)。正如这个答案和其他地方所建议的那样stackoverflow.com/questions/1339142/…
-
是的,可以编辑注册表。有两种方式:A startup task, or the OnStart event
-
我会试试这个并报告,谢谢。我不知道为什么我认为它无法完成。然而,奇怪的是我没有得到这个错误的表客户端,即使它也非常快。
-
无论如何我应该指出,这只会移动或使问题不那么明显(并使用更多资源),并且似乎仍然存在套接字未关闭的错误。跨度>