如何防止套接字/端口耗尽? [英] How do I prevent Socket/Port Exhaustion?

查看:34
本文介绍了如何防止套接字/端口耗尽?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过使用跨多个线程的请求来对网站进行性能测试.每个线程执行 n 次.(在 for 循环中)

I am attempting to performance test a website by hitting it with requests across multiple threads. Each thread executes n times. (in a for loop)

但是,我遇到了问题.特别是带有内部异常的 WebException(无法连接到远程服务器"):

However, I am running into problems. Specifically the WebException ("Unable to connect to remote server") with the inner exception:

无法执行对套接字的操作,因为系统缺乏足够的缓冲空间或因为队列已满127.0.0.1:52395

An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full 127.0.0.1:52395

我试图以每个线程 500 次迭代运行 100 个线程.

I am attempting to run 100 threads at 500 iterations per thread.

最初我在 System.Net 中使用 HttpWebRequest 向服务器发出 GET 请求.目前我正在使用 WebClient 因为我假设每次迭代都使用一个新的套接字(所以在短时间内有 100 * 500 个套接字).我假设 WebClient(每个线程实例化一次)只会使用一个套接字.

Initially I was using HttpWebRequest in System.Net to make the GET request to the server. Currently I am using WebClient as I assumed that each iteration was using a new socket (so 100 * 500 sockets in a short period of time). I assumed WebClient (which is instantiated once per thread) would only use one socket.

我不需要一次打开 50 000 个套接字,因为我想发送 GET 请求,接收响应,然后关闭套接字,将其释放以供下一次循环迭代使用.我知道这是一个问题

I don't need 50 000 sockets open at once, as I would like to send the GET request, receive the response, and close the socket, freeing it for use in the next loop iteration. I understand that it would be a problem to

然而,即使使用 WebClient,也会请求一堆套接字,导致一堆处于 TIME_WAIT 模式的套接字(使用 netstat 检查).这会导致其他应用程序(如互联网浏览器)挂起并停止运行.

However, even with WebClient, a bunch of sockets are being requested resulting in a bunch of sockets in TIME_WAIT mode (checked using netstat). This causes other applications (like internet browsers) to hang and stop functioning.

我可以用更少的迭代和/或更少的线程来运行我的测试,因为看起来套接字最终会退出这个 TIME_WAIT 状态.然而,这不是一个解决方案,因为它没有充分测试 Web 服务器的能力.

I can operate my test with less iterations and/or less threads, as it appears the sockets do eventually exit this TIME_WAIT state. However, this is not a solution as it doesn't adequately test the abilities of the web server.

问题:

如何在每次线程迭代后显式关闭套接字(从客户端)以防止 TIME_WAIT 状态和套接字耗尽?

How do I explicitly close a socket (from the client side) after each thread iteration in order to prevent TIME_WAIT states and socket exhaustion?

代码:

包装HttpRequest的类

Class that wraps the HttpRequest

将 WebClient 包装在 using 中,因此每次迭代都会实例化、使用和处理一个新的 WebClient.问题依旧.

Wrapped WebClient in a using, so a new one is instantiated,used and disposed for every iteration. The problem still persists.

  public sealed class HttpGetTest : ITest {
    private readonly string m_url;

    public HttpGetTest( string url ) {          
        m_url = url;
    }

    void ITest.Execute() {
        using (WebClient webClient = new WebClient()){
            using( Stream stream = webClient.OpenRead( m_url ) ) {          
            }
        }
    }
}

我的 ThreadWrapperClass 中创建新线程的部分:

The part of my ThreadWrapperClass that creates a new thread:

public void Execute() {
    Action Hammer = () => {
        for( int i = 1; i <= m_iterations; i++ ) {
            //Where m_test is an ITest injected through constructor
            m_test.Execute();
        }       
    };
    ThreadStart work = delegate {
        Hammer();
    };
    Thread thread = new Thread( work );
    thread.Start();
}

推荐答案

你了解 TIME_WAIT 的目的吗?在此期间,重用端口是不安全的,因为前一个事务中丢失的数据包(已成功重新传输)可能尚未在该时间段内传送.

Do you understand the purpose of TIME_WAIT? It's a period during which it would be unsafe to reuse the port because lost packets (that have been successfully retransmitted) from the previous transaction might yet be delivered within that time period.

您可能可以在注册表中的某个地方对其进行调整,但我怀疑下一步是否明智.

You could probably tweak it down in the registry somewhere, but I question if this is a sensible next step.

事实证明,我在测试环境中创建真实负载的经历非常令人沮丧.当然,从 localhost 运行您的负载测试器绝不是现实的,而且我使用 .net http api 进行的大多数网络测试似乎在客户端中比服务器本身需要更多的咕噜声.

My experience of creating realistic load in a test environment have proved very frustrating. Certainly running your load-tester from localhost is by no means realistic, and most network tests I have made using the .net http apis seem to require more grunt in the client than the server itself.

因此,最好移到第二台机器上以在您的服务器上产生负载……但是,国内路由设备很少能够支持接近数量的连接,这会导致任何类型的负载写得很好的服务器应用程序,所以现在你也需要升级你的路由/交换设备!

As such, it's better to move to a second machine for generating load on your server... however domestic routing equipment is rarely up to the job of supporting anywhere near the number of connections that would cause any sort of load on a well written server app, so now you need to upgrade your routing/switching equipment as well!

最后,我在 .net Http 客户端 API 方面遇到了一些非常奇怪和意外的性能问题.归根结底,他们都使用 HttpWebRequest 来完成繁重的工作.IMO 它远没有达到应有的性能.DNS 是同步的,即使在异步调用 API 时也是如此(尽管如果您只从单个主机请求,这不是问题),并且在持续使用后 CPU 使用率会逐渐上升,直到客户端变为 CPU 受限而不是 IO 受限.如果您希望生成持续且繁重的负载,那么任何依赖 HttpWebRequest 的请求密集型应用都是 IMO 虚假投资.

Lastly, I've had some really strange and unexpected performance issues around the .net Http client API. At the end of the day, they all use HttpWebRequest to do the heavy lifting. IMO it's nowhere near as performant as it could be. DNS is sychronous, even when calling the APIs asynchronously (although if you're only requesting from a single host, this isn't an issue), and after sustained usage CPU usage creeps up until the client becomes CPU constrained rather than IO constrained. If you're looking to generate sustained and heavy load, any request-heavy app reliant on HttpWebRequest is IMO a bogus investment.

总而言之,这是一项非常棘手的工作,而且最终只能在野外证明,除非您有足够的现金来购买更好的设备.

All in all, a pretty tricky job, and ultimately, something that can only be proved in the wild, unless you've got plently of cash to spend on an armada of better equipment.

[提示:我使用异步套接字 API 和第三方 DNS 客户端库编写的自己的客户端获得了更好的性能]

[Hint: I got much better perfomance from my own client written using async Socket apis and a 3rd party DNS client library]

这篇关于如何防止套接字/端口耗尽?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆