本节提供有关设置线程池系统变量以获得最佳性能的指南,使用每秒事务数等指标进行测量。
thread_pool_size
是控制线程池性能的最重要参数。它只能在服务器启动时设置。我们测试线程池的经验表明:
如果主存储引擎是
InnoDB
,则最佳thread_pool_size
设置可能在 16 到 36 之间,最常见的最佳值往往是从 24 到 36。我们还没有看到任何设置超过 36 的情况。可能有是小于 16 的值最佳的特殊情况。对于 DBT2 和 Sysbench 等
InnoDB
工作负载,最佳设置似乎通常在 36 左右。对于写入密集型工作负载,最佳设置有时可能更低。如果主存储引擎是
MyISAM
,则thread_pool_size
设置应该相当低。使用 4 到 8 的值通常可以看到最佳性能。较高的值往往会对性能产生轻微的负面影响,但不会产生显着影响。
另一个系统变量 ,
thread_pool_stall_limit
对于处理阻塞和长时间运行的语句很重要。如果所有阻塞 MySQL 服务器的调用都报告给线程池,它就会始终知道执行线程何时被阻塞。然而,这可能并不总是正确的。例如,块可能出现在尚未使用线程池回调进行检测的代码中。对于这种情况,线程池必须能够识别似乎被阻塞的线程。这是通过可以使用
thread_pool_stall_limit
系统变量调整的超时来完成的,其值以 10 毫秒为单位测量。此参数确保服务器不会完全阻塞。的价值
thread_pool_stall_limit
有 6 秒的上限,以防止服务器死锁的风险。
thread_pool_stall_limit
还使线程池能够处理长时间运行的语句。如果允许长时间运行的语句阻塞线程组,则分配给该组的所有其他连接都将被阻塞,并且在长时间运行的语句完成之前无法开始执行。在最坏的情况下,这可能需要数小时甚至数天。
thread_pool_stall_limit
应选择
的值,
以便将执行时间超过其值的语句视为停滞。停滞的语句会产生大量额外的开销,因为它们涉及额外的上下文切换,在某些情况下甚至需要额外的线程创建。另一方面,将
thread_pool_stall_limit
参数设置得太高意味着长时间运行的语句会阻塞一些短时间运行的语句,时间超过必要的时间。短等待值允许线程更快地启动。短值也能更好地避免死锁情况。长时间等待值对于包含长时间运行的语句的工作负载很有用,以避免在当前语句执行时启动太多新语句。
假设服务器执行一个工作负载,其中 99.9% 的语句即使在服务器加载时也能在 100 毫秒内完成,而其余的语句则平均分布在 100 毫秒到 2 小时之间。thread_pool_stall_limit
在这种情况下,设置为 10 (10 × 10ms = 100ms)是有意义的
。默认值 6(60 毫秒)适用于主要执行非常简单语句的服务器。
可以在运行时更改该thread_pool_stall_limit
参数,使您能够针对服务器工作负载取得适当的平衡。假设该
TP_THREAD_GROUP_STATS
表已启用,您可以使用以下查询来确定停滞的已执行语句的比例:
SELECT SUM(STALLED_QUERIES_EXECUTED) / SUM(QUERIES_EXECUTED)
FROM INFORMATION_SCHEMA.TP_THREAD_GROUP_STATS;
这个数字应该尽可能低。要降低语句停顿的可能性,请增加 的值
thread_pool_stall_limit
。
当一条语句到达时,它在真正开始执行之前最多可以延迟多少时间?假设以下条件适用:
低优先级队列中有 200 条语句在排队。
高优先级队列中有 10 个语句在排队。
thread_pool_prio_kickup_timer
设置为 10000(10 秒)。thread_pool_stall_limit
设置为 100(1 秒)。
在最坏的情况下,这 10 个高优先级语句代表 10 个持续执行很长时间的事务。因此,在最坏的情况下,没有语句被移动到高优先级队列,因为它已经包含等待执行的语句。10 秒后,新语句有资格被移动到高优先级队列。但是,在移动它之前,它之前的所有语句也必须移动。这可能还需要 2 秒,因为每秒最多有 100 个语句被移动到高优先级队列。现在,当语句到达高优先级队列时,前面可能有许多长时间运行的语句。在最坏的情况下,这些中的每一个都会停止,并且在从高优先级队列中检索下一条语句之前,每个语句需要 1 秒。因此,在这种情况下,新语句开始执行需要 222 秒。
此示例显示了应用程序的最坏情况。如何处理取决于应用程序。如果应用程序对响应时间有很高的要求,它很可能应该在更高级别自身限制用户。否则,它可以使用线程池配置参数来设置某种最长等待时间。