在本文中,我们讨论了Manticore Search中当前实现的工作线程以及如何调整工作线程的参数。
在Manticore Search中,目前有两种多处理模式,由指令 workers 控制。默认的多进程模式目前是 thread_pool,可选的模式是 threads。
线程
在多处理模式 ‘ threads ’ 中,为 每个 进入的网络 连接 创建一个新的专用线程。该线程在客户端断开连接之前处于活动状态 - 即,只要连接处于活动状态。在此期间,线程将执行来自该连接的传入查询。
默认情况下,发动机会生成无限数量的线程 - 如果操作系统允许的话。虽然这看起来不错,但实际上,允许创建无限线程是有代价的。首先,创建/销毁线程会消耗CPU资源。尽管与fork相比,这个成本较低,但仍然存在。
每秒生成数百或数千个线程会影响系统性能,这取决于可用的CPU核心。拥有比可用核心数量大得多的线程会导致这些线程争夺资源 - 一个是CPU核心,第二个可能是存储。
例如,如果我们有一个16核系统,但我们让它创建160个搜索线程,这意味着每个CPU核心有10个线程。线程不会同时运行,而是必须排队等待CPU核心分配周期给它们。在存储方面,我们可能有160个潜在的请求者来读取数据。如果存储不能在没有延迟(延迟)的情况下继续为线程提供服务,则延迟可能会影响CPU核心的分配,因为一个线程可能已经获得了执行其在CPU核心上计算的授权,但仍然需要等待数据。
max_children 设置允许限制可以同时处于活动状态的线程数量。当达到此限制时,发动机会开始拒绝传入连接,并返回 ‘maxed out’ 错误。在配置max_children时,需要记住,当客户端关闭连接时,线程会被终止。如果连接处于 空闲状态,线程将保持活动并被计算在max_children中。max_children可以增加到一个根据服务器处理活动查询数量的能力而定的限制。这包括处理能力(CPU)和IO操作(存储)。一个常见的错误是将max_children提高到非常高的值。根据系统能力,有一个临界点,当生成过多线程时,只会导致查询速度变慢。如果在优化索引和查询方面没有其他措施,则应考虑新的搜索服务器以分担负载。
线程池
在上一节中,我们讨论了线程有成本,并且连接可以保持线程活动,即使它们未被使用。
管理线程的另一种策略是,不为每个连接创建一个线程,而是使用一个线程池来处理工作。在这种情况下,工作线程与传入连接没有直接关联,因为连接是由另一类线程处理的。当守护进程启动时,它会创建一定数量的线程。传入的网络连接由所谓的网络线程处理,它们负责接收来自连接的查询并将其路由到线程池中的线程。
如果线程池过于繁忙(所有工作线程都在处理查询),新的查询将被发送到一个 待处理队列。如果待处理队列被填满,服务器将 ‘max out’。默认情况下,未设置限制,但等待时间过长并不会带来好处,处理时间更长的查询会让事情变得糟糕。最好对队列设置限制,以表明服务器接收的查询超过了它能处理的数量。这可以通过指令 queue_max_length 设置。与threads模型中的max_children相比,在达到一定数量的打开连接后max_children将开始满负荷工作,在线程池的情况下,当活跃查询超过max_children(池中的线程数)+ queue_max_length时,守护进程将开始 ‘max out’。
在 thread_pool 的情况下, max_children 指令定义了在守护进程启动时创建的线程池中的线程数量。默认情况下,使用 1.5x 的CPU核心数值。将max_children设置为较高值并不会提高服务器的性能或容量。由于这些线程只是处理,它们需要尽快访问CPU。
设置较高值只会导致,正如前一节所说的那样,CPU争用和性能下降,同时还会导致守护进程启动速度变慢。与线程模式相比,在该模式中,max_children可以设置为CPU核心数的几倍,甚至几个几百的值也可能有意义,而在线程池的情况中,设置为核心数量的2-3倍几乎没有意义。
默认情况下,处理网络连接使用一个专用线程。该线程的工作一般较为简单,因为它仅作为线程池的代理,通常可以承受良好的流量。通过**
net_workers
**指令可以增加网络线程的数量。增加网络线程在每秒查询率极高的设置中表现出了增益。
网络线程也有几个微调设置。网络线程并不总是忙碌,因为可能有时(以亚秒为单位)它没有接收到查询。线程会进入睡眠状态并失去对CPU的优先权。唤醒或重新获得CPU位置所花费的时间很少,但对于高性能而言,每毫秒都至关重要。
为了解决这个问题,可以通过** net_wait_tm **指令激活忙循环。如果net_wait_tm的值为正,则线程会每10*net_wait_tm“滴答”一次CPU(其中net_wait_tm值代表毫秒)。如果net_wait_tm为零,则忙循环将持续运行 - 需要注意的是,即使网络线程没有接收到太多流量,这也会产生额外的CPU使用率。要禁用忙循环,应使用负值-1。默认情况下,net_wait_tm的值为1,这意味着忙循环每10毫秒滴答一次。
网络线程还可以进行限制。选项** net_throttle_accept 强制限制网络线程同时接受的客户端数量, net_throttle_action **明确每次迭代处理的请求数量。默认情况下,不强制限制。在高负载场景下,限制网络线程是合理的。
一个常被误解的方面是max_children与 dist_threads 之间的关系。dist_threads负责某些操作的多线程处理,比如本地 分布式 索引、与load_files的 片段 或 调用PQ 命令。然而,这些是子处理线程,并不计入仅计算主要查询线程的 max_children 指令。