19.2. 连接器配置

19.2.1.  为 JBoss EAP 6 里的 HTTP 连接器定义线程池

概述

JBoss EAP 6 里的线程池可以通过 Executor 模型在不同组件间共享。这些池不仅可以由不同的 HTTP 连接器共享,也可以被JBoss EAP 6 里支持 Executor 模型的其他组件共享。通过 HTTP 连接器线程池来满足当前的 Web 性能要求是件难办的事,它要求密切监控当前的线程池以及于其的负载需求。在本节里,您会学习如何通过 Executor 模型为 HTTP 连接器设立线程池。您也会学习通过命令行界面或编辑 XML 配置文件来进行设置。

过程 19.1. 为 HTTP 连接器设立线程池

  1. 定义线程工厂

    打开配置文件 standalone.xml(独立服务器)或 domain.xml(受管域)。这个文件位于 EAP_HOME/standalone/configurationEAP_HOME/domain/configuration 目录。
    添加下列子系统条目,按照您的服务器的需要修改相关的值。
    <subsystem xmlns="urn:jboss:domain:threads:1.0">
        <thread-factory name="http-connector-factory" thread-name-pattern="HTTP-%t" priority="9" group-name="uq-thread-pool"/>
    </subsystem>	
    
    
    如果您想用 CLI 来完成这个任务,请在 CLI 命令行提示下执行下列命令:
    [standalone@localhost:9999 /] ./subsystem=threads/thread-factory=http-connector-factory:add(thread-name-pattern="HTTP-%t", priority="9", group-name="uq-thread-pool")
  2. 创建执行器(Executor)

    您可以使用六种内置的 Executor 类来充当这个工厂的执行器。这六种执行器是:
    • unbounded-queue-thread-pool:这种类型的线程池总是接受任务。如果少于线程最大数目的线程在运行,新的线程将启动以运行提交的任务;否则,任务将放入非绑定的 FIFO 队列,等待有可用的线程再被执行。

      注意

      Executors.singleThreadExecutor() 提供的 single-thread executor 类型基本上是一个具有单个线程限制 unbounded-queue 执行器。这个类型的执行器是用 unbounded-queue-thread-pool-executor 元素进行部署的。
    • bounded-queue-thread-pool:这个类型的执行器维护了一个固定长度的队列及两个池大小参数:coremaximum。当接受任务时,如果运行的池线程小于 core,新的线程将启动以执行这个任务。如果大于 Core 且队列里有空位,任务将放入队列。如果队列没有空位且运行的池线程小于 maximum,新的线程将启动以执行这个任务。如果执行器启用了阻塞模式,调用线程将阻塞至队列里出现空位。如果配置了 handoff 执行器,任务将委托给 handoff 执行器。否则,任务将被拒绝。
    • blocking-bounded-queue-thread-pool:带有绑定队列的线程池执行器,队列里提交任务的线程可能会阻塞。这样的线程池也有 Core 和 Maximum 参数及指定的队列长度。当任务被提交时,如果运行线程的数目小于 Core 参数,那么新的线程将被创建。如果大于 Core 且队列里还有空位,任务将进行排队。而如果队列里没有空位且运行线程的数目小于 Maximum 参数,新的线程将被创建。
    • queueless-thread-pool:有时我们需要简单的线程池在单独的线程里执行任务,当它们完成任务后还可以重用而无需中介队列。既然任务总是在接受后立即执行而不是先接受任务然后延迟执行至其他运行的任务已完成,处理长期运行的任务时这种类型的池比较合适,如利用阻塞的 I/O。这种类型的执行器是通过 queueless-thread-pool-executor 元素声明的。
    • blocking-queueless-thread-pool:没有队列的线程池执行器,队列里的提交任务的线程可能阻塞。当任务被提交时,如果运行的线程数小于 Maximum 参数,新的线程将被创建。否则,调用将阻塞直至另外一个线程完成它的任务并接受新任务。
    • scheduled-thread-pool:这是一个特殊类型的执行器,它的目的是基于 java.util.concurrent.ScheduledThreadPoolExecutor 类在专门的时间和时间间隔执行任务。这种类型的执行器是用 scheduled-thread-pool-executor 元素来配置的:
    在这个例子里,我们将使用 unbounded-queue-thread-pool 来充当执行器。修改 max-threadskeepalive-time 参数的值来满足您的服务器的需要。
    <unbounded-queue-thread-pool name="uq-thread-pool">
      <thread-factory name="http-connector-factory" />
      <max-threads count="10" />
      <keepalive-time time="30" unit="seconds" />
    </unbounded-queue-thread-pool>			
    
    
    或者您更愿意使用 CLI:
    [standalone@localhost:9999 /] ./subsystem=threads/unbounded-queue-thread-pool=uq-thread-pool:add(thread-factory="http-connector-factory", keepalive-time={time=30, unit="seconds"}, max-threads=30)
  3. 让 HTTP 连接器使用这个线程池

    在相同的配置文件里,找到 web 子系统下的 HTTP 连接器元素并进行修改,让它使用之前步骤里定义的线程池。
    <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http" executor="uq-thread-pool" />
    
    或者您更愿意使用 CLI:
    [standalone@localhost:9999 /] ./subsystem=web/connector=http:write-attribute(name=executor, value="uq-thread-pool")
  4. 重启服务器

    重启服务器(独立服务器或受管域)让修改可以生效。请用下列 CLI 命令来确认上面步骤里的修改已经生效:
    [standalone@localhost:9999 /] ./subsystem=threads:read-resource(recursive=true)
    {                  
        "outcome" => "success",
        "result" => {
            "blocking-bounded-queue-thread-pool" => undefined,
            "blocking-queueless-thread-pool" => undefined,
            "bounded-queue-thread-pool" => undefined,
            "queueless-thread-pool" => undefined,
            "scheduled-thread-pool" => undefined,
            "thread-factory" => {"http-connector-factory" => {
                "group-name" => "uq-thread-pool",
                "name" => "http-connector-factory",
                "priority" => 9,
                "thread-name-pattern" => "HTTP-%t"
            }},
            "unbounded-queue-thread-pool" => {"uq-thread-pool" => {
                "keepalive-time" => {
                    "time" => 30L,
                    "unit" => "SECONDS"
                },
                "max-threads" => 30,
                "name" => "uq-thread-pool",
                "thread-factory" => "http-connector-factory"
            }}
        }
    }
    [standalone@localhost:9999 /] ./subsystem=web/connector=http:read-resource(recursive=true)
    {
        "outcome" => "success",
        "result" => {
            "configuration" => undefined,
            "enable-lookups" => false,
            "enabled" => true,
            "executor" => "uq-thread-pool",
            "max-connections" => undefined,
            "max-post-size" => 2097152,
            "max-save-post-size" => 4096,
            "name" => "http",
            "protocol" => "HTTP/1.1",
            "proxy-name" => undefined,
            "proxy-port" => undefined,
            "redirect-port" => 443,
            "scheme" => "http",
            "secure" => false,
            "socket-binding" => "http",
            "ssl" => undefined,
            "virtual-server" => undefined
        }
    }
    
结果

您已经创建一个线程工厂和执行器,而且修改了 HTTP 连接器来使用这个线程池。