在本文中,我们讨论了Manticore Search中实现的当前工作线程以及如何调整工作线程的参数。
在Manticore Search中,目前有两种由指令 workers 控制的多进程模式。默认的MPM目前是thread_pool,可选的模式是threads。
线程
在多进程模式' threads '中,为每个传入的网络连接创建一个新的专用线程。该线程在客户端断开连接之前处于活动状态——也就是说,只要连接仍然存在。在此期间,线程将执行来自该连接的传入查询。
默认情况下,引擎将生成无限数量的线程——如果操作系统允许的话。虽然这看起来不错,但实际上允许创建无限线程会带来一些成本。首先,创建/销毁线程会消耗CPU资源。虽然与fork相比,这个成本较低,但仍然存在。
每秒生成数百或数千个线程可能会影响系统的性能,具体取决于可用的CPU核心数量。线程数量远大于可用核心时,会导致这些线程争夺资源——一个是CPU核心,另一个可能是存储。
例如,如果我们有一个16核系统,但我们允许生成160个搜索线程,这意味着每个CPU核心有10个线程。线程不会同时运行,而是必须排队等待CPU核心分配周期给它们。在存储方面,我们可能有160个潜在的请求者来读取数据。如果存储无法在没有延迟(延迟)的情况下继续为线程服务,延迟可能会影响CPU核心的分配,因为线程可能会收到执行其计算的绿灯,但必须等待数据。
max_children
设置允许对同时活动的线程数量进行限制。当达到限制时,引擎将开始拒绝传入连接,并返回'maxed out'错误。在设置max_children时,您需要记住,当客户端关闭连接时,线程会被杀死。如果连接处于空闲**状态,线程将保持活动状态并被max_children计数。max_children可以增加到一个限制,这个限制取决于服务器处理活动查询的能力。这包括处理能力(CPU)和IO操作(存储)。一个常见的错误是将max_children提高到非常高的值。根据系统能力,有一个点,当生成过多线程时只会导致查询的减速。如果在优化索引和查询方面没有更多的内容,则应考虑新的搜索服务器以分担负载。
线程池
在上一节中,我们讨论了线程的成本,以及连接可以保持线程活跃,即使它们没有被使用。
管理线程的另一种策略是,不为每个连接创建一个线程,而是使用一个线程池来处理工作。在这种情况下,工作线程与传入连接无关,因为连接由另一类线程处理。当守护进程启动时,它会创建一定数量的线程。传入的网络连接由所谓的网络线程处理,它们的工作是接收来自连接的查询并将其路由到线程池中的线程。
如果线程池过于繁忙(所有工作线程都在处理查询),新的查询将被发送到待处理队列。如果待处理队列被填满,服务器将会'max out'。默认情况下,没有设置限制,然而,排队时间过长只会导致处理时间较长的查询。对队列设置限制是个好主意,以便发出服务器接收的查询超过其处理能力的信号。这可以通过指令** queue_max_length **来设置。与线程模型中的max_children相比,在打开连接数量达到一定数量后开始maxing out,而在线程池的情况下,守护进程将在活动查询超过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(其中 net_wait_tm 值表示毫秒)"滴答"CPU。如果 net_wait_tm 为零,忙等待循环将持续运行 - 需要注意的是,即使网络线程没有收到太多流量,这也会产生额外的CPU使用率。要禁用忙等待循环,应使用 -1 的负值。默认情况下,net_wait_tm 的值为 1,表示忙等待循环每 10 毫秒滴答一次。
网络线程还可以进行限流。 net_throttle_accept 选项对网络线程一次可以接受的客户端数量强制执行限制,而 net_throttle_action 明确了每次迭代要处理的请求数。默认情况下,不强制执行任何限制。在高负载场景中,限流网络线程是有意义的。
一个经常被误解的方面是 max_children 和 dist_threads 之间的关系。dist_threads 负责对某些操作进行多线程处理,如本地 分布式 索引、带有 load_files 的 snippets 或 CALL PQ 命令。然而,这些是子处理线程,它们不计入 max_children 指令,后者仅计算主查询线程。