如何限制 Jetty 接受的连接数量?

问题描述 投票:0回答:6

我正在运行 Jetty 7.2.2,并且想要限制它将处理的连接数量,这样当它达到限制(例如 5000)时,它将开始拒绝连接。

不幸的是,所有

Connectors
似乎只是继续并尽快接受传入连接并将它们分派到配置的线程池。

我的问题是我在受限环境中运行,并且只能访问 8K 文件描述符。如果我收到大量连接,我可能会很快用完文件描述符并进入不一致的状态。

我的一个选择是返回 HTTP

503 Service Unavailable
,但这仍然需要我接受并响应连接 - 并且我可能会通过编写 servlet 过滤器来跟踪某处传入连接的数量。

有更好的解决办法吗?

java jetty embedded-jetty
6个回答
11
投票

线程池有一个与之关联的队列。默认情况下,它是无界的。但是,在创建线程池时,您可以提供一个有界队列作为其基础。例如:

Server server = new Server();
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(maxQueueSize);
ExecutorThreadPool pool = new ExecutorThreadPool(minThreads, maxThreads, maxIdleTime, TimeUnit.MILLISECONDS, queue);
server.setThreadPool(pool);

这似乎解决了我的问题。否则,由于无界队列,服务器在重负载下启动时会耗尽文件句柄。


11
投票

我最终采用了一个解决方案,该解决方案可以跟踪请求数量并在负载过高时发送 503。这并不理想,正如您所看到的,我必须添加一种方法来始终让延续请求通过,这样它们就不会挨饿。非常适合我的需求:

public class MaxRequestsFilter implements Filter {

    private static Logger cat   = Logger.getLogger(MaxRequestsFilter.class.getName());

    private static final int DEFAULT_MAX_REQUESTS = 7000;
    private Semaphore requestPasses;

    @Override
    public void destroy() {
        cat.info("Destroying MaxRequestsFilter");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        long start = System.currentTimeMillis();
        cat.debug("Filtering with MaxRequestsFilter, current passes are: " + requestPasses.availablePermits());
        boolean gotPass = requestPasses.tryAcquire();
        boolean resumed = ContinuationSupport.getContinuation(request).isResumed();
        try {
            if (gotPass || resumed ) {
                chain.doFilter(request, response);
            } else {
                ((HttpServletResponse) response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
            }
        } finally {
            if (gotPass) {
                requestPasses.release();
            }
        }
        cat.debug("Filter duration: " + (System.currentTimeMillis() - start) + " resumed is: " + resumed);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        cat.info("Creating MaxRequestsFilter");

        int maxRequests = DEFAULT_MAX_REQUESTS;
        requestPasses = new Semaphore(maxRequests, true);
    }

}

5
投票

我还没有为我的应用程序部署 Jetty。然而,使用 Jetty 与其他一些开源项目进行部署。根据该经验: 连接器的配置如下:

acceptors:专用于接受传入连接的线程数量。

acceptQueueSize :在操作系统开始发送拒绝之前可以排队的连接请求数。

http://wiki.eclipse.org/Jetty/Howto/Configure_Connectors

您需要将它们添加到配置中的以下块中

<Call name="addConnector">
  <Arg>
      <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="Acceptors">20</Set>
        <Set name="confidentialPort">8443</Set>
      </New>
  </Arg>
</Call>

5
投票

接受队列大小

如果我理解正确,这是一个较低级别的 TCP 设置,它控制当服务器应用程序以比传入连接的速率更慢的速率进行 Accept() 时将跟踪的传入连接数。请参阅 http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html#ServerSocket(int,%20int)

的第二个参数

这与 Jetty QueuedThreadPool 中排队的请求数量完全不同。排队的请求已经完全连接,并且正在等待池中的线程变得可用,之后可以开始处理。

我也有类似的问题。我有一个受 CPU 限制的 servlet(几乎没有 I/O 或等待,因此异步无济于事)。我可以轻松限制 Jetty 池中的最大线程数,从而避免线程切换开销。但是,我似乎无法限制排队请求的长度。这意味着随着负载的增长,响应时间也会相应增长,这不是我想要的。

我希望如果所有线程都很忙并且排队的请求数量达到 N,则为所有进一步的请求返回 503 或其他一些错误代码,而不是永远增加队列。

我知道我可以通过使用负载均衡器(例如 haproxy)来限制对 jetty 服务器的并发请求数量,但是可以单独使用 Jetty 来完成吗?

附注 写完这篇文章后,我发现了 Jetty DoS 过滤器,并且似乎可以将其配置为在超出预配置的并发级别时拒绝 503 传入请求:-)


3
投票
<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Set name="ThreadPool">
      <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <!-- specify a bounded queue -->
        <Arg>
           <New class="java.util.concurrent.ArrayBlockingQueue">
              <Arg type="int">6000</Arg>
           </New>
      </Arg>
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>
    </Set>
</Configure>

0
投票

限制输入连接的更现代的方法是

ConnectionLimit
类。如果您想在连接到达应用程序/servlet 级别之前对其进行限制,它会很有用。

引自JavaDoc

此侦听器对连接数施加限制,超出时会调用 AbstractConnector.setAccepting(boolean) 以防止接收更多连接。

代码示例:

   Server server = new Server();
   server.addBean(new Connection Limit(5000,server));
   ...
   server.start();
© www.soinside.com 2019 - 2024. All rights reserved.