⚠️ 此页面为自动翻译,翻译可能不完美。

Threads in Manticore Search

本文将讨论 Manticore Search 当前实现的工作者以及如何调整工作者的参数。

在 Manticore Search 中,目前有两种多进程模式,由 workers 指令控制。当前默认的 MPM 是 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 设置为非常高的值。在系统能力范围内,存在一个临界点,当生成过多线程时只会导致查询变慢。如果在优化索引和查询方面没有更多可做的,应考虑使用新的搜索服务器来分担负载。

thread_pool

在上一节中,我们讨论了线程的开销以及连接即使未使用也会保持线程活跃。

管理线程的另一种策略是不为每个连接创建线程,而是使用一个 线程池 来处理工作。在这种情况下,工作线程不与传入的连接相关联,因为连接由另一类线程处理。当守护进程启动时,它会创建一定数量的线程。传入的网络连接由所谓的网络线程处理,它们的任务是从连接接收查询并将它们路由到线程池中的线程。

如果线程池太忙(所有工作者都在处理查询),新查询将被发送到 待处理队列。如果待处理队列被填满,服务器将 'max out'。默认情况下没有设置限制,但排队时间过长对获取长时间查询没有帮助。为队列设置一个限制是个好主意,以表明服务器接收到的查询多于其处理能力。这可以通过 queue_max_length 指令设置。与线程模型中的 max_children 相比,其中在一定数量的打开连接后开始达到上限,在 thread_pool 的情况下,守护进程在活动查询多于 max_children(线程池中的线程数)+ queue_max_length 时开始 'max out'。

thread_pool 情况下, max_children 指令定义了线程池中创建的线程数量,这些线程在守护进程启动时创建。默认情况下,使用 1.5x CPU 核心数的值。将 max_children 设置为高值不会增加服务器的性能或容量。因为这些线程仅处理任务,它们需要尽快访问 CPU。

设置高值只会导致与上一节相同的问题,即 CPU 争用和性能下降,还会导致守护进程启动变慢。与线程模式相比,其中 max_children 可以设置为 CPU 核心数的数倍,甚至数百的值是有意义的,在 thread_pool 的情况下,将值设置为 2-3 倍的 CPU 核心数几乎没有意义。

默认情况下,为了处理网络连接,会使用一个专用线程。该线程的工作通常很简单,因为它仅作为线程池的代理,通常可以承受大量流量。可以通过 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 负责某些操作的多线程处理,例如本地 distributed 索引、使用 load_files 的 snippetsCALL PQ 命令。然而,这些是子进程线程,它们不计入 max_children 指令,该指令仅计算主查询线程。

安装Manticore Search

安装Manticore Search