暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 并发线程的理解

原创 CuiHulong 2020-06-06
2892

这几天碰到5.7低版本,并发量提升就会触发bug,导致服务器重新启动现象。

在资源有限的情况下,怎样去有效的进行控制并发,MySQL到底能支持多少并发。

并发实现方式

先分析一下官方对于这方面的建议:

InnoDB使用操作系统线程来处理来自用户事务的请求。(事务在提交或回滚之前可能会向InnoDB发出很多请求。)在具有多核处理器的现代操作系统和服务器上,上下文切换非常有效,大多数工作负载运行良好,并发线程的数量没有任何限制。
在有助于减少线程之间的上下文切换的情况下,InnoDB可以使用许多技术来限制并发执行的操作系统线程的数量.当InnoDB从一个用户会话接收到一个新的请求时,如果并发执行的线程数量达到了预先定义的限制,那么这个新请求会在再次尝试之前休眠一段时间。在休眠后无法重新调度的请求被放入先入/先出队列并最终被处理。等待锁的线程不会计算在并发执行的线程数中。

具体实现通过以下图解:
image.png
Mysql里可通过设置参数,来限制并发线程的数量。从mysql 服务端接收到相应的请求之后,分配到线程,这时线程数量达到限制之后,分配的线程放入一个队列 并同时休眠几微秒,但进入的时候对应的拿到票据,并执行对应的事务,当票据用完之后还需要重新排队。

并发控制参数

image.png

这个变量的范围是0到1000。值0(默认值)被解释为无限并发性(没有并发性检查)。
禁用线程并发性检查使InnoDB能够创建它需要的线程。
0的值也会禁用InnoDB内部的查询和显示InnoDB状态输出的行操作部分的队列计数器中的查询。

如果MySQL实例与其他应用程序共享CPU资源,或者工作负载或并发用户数量不断增加,就需要考虑设置此变量。
正确的设置取决于工作负载、计算环境和运行的MySQL版本。需要测试一系列值,以确定提供最佳性能的设置。innodb_thread_concurrency是一个动态变量,它允许在一个实时测试系统上试验不同的设置。如果某个特定设置执行得很差,可以快速将innodb_thread_concurrency设置回0。

如果工作负载的并发用户线程数小于64,则设置innodb_thread_concurrency=0。

如果工作负载一直很重,或者偶尔会出现峰值,可以从设置innodb_thread_concurrency=128开始,然后将其值降低到96、80、64等等,直到找到能够提供最佳性能的线程数为止。假设系统通常有40到50个用户,但是这个数字会周期性地增加到60、70甚至200。会发现,在80个并发用户时,性能是稳定的,但在这个数字之上,性能开始出现回归。在这种情况下,应该设置innodb_thread_concurrency=80以避免影响性能。

如果你不想让InnoDB为用户线程使用超过一定数量的虚拟cpu(例如,20个虚拟cpu),可以将innodb_thread_concurrency设置为这个数(或者更低,取决于性能结果)。如果目标是将MySQL与其他应用程序隔离开来,那么可以考虑将mysqld进程专门绑定到虚拟cpu。

innodb_thread_concurrency值过高会导致系统内部和资源争用增加,从而导致性能下降。

image.png
定义InnoDB线程在加入InnoDB队列之前睡眠的时间,以微秒为单位。默认值是10000。值为0将禁用睡眠。可以设置innodb_adaptive_max_sleep_delay为innodb_thread_sleep_delay的最大值,而InnoDB会根据当前的线程调度活动自动调整innodb_thread_sleep_delay的上下调整。这种动态调整有助于线程调度机制在系统轻负载或接近满负荷运行时顺利工作。

image.png
当一个线程尝试进入InnoDB时,如果线程的数量已经达到并发限制,那么它将被放置在一个队列中。当一个线程被允许进入InnoDB时,它会得到一个等于innodb_concurrency_tickets值的“票据”,这个线程可以自由地进入和离开InnoDB,直到它的票据用完。在这之后,当线程下一次尝试进入InnoDB时,它再次受到并发性检查(和可能的排队)的影响。

使用一个较小值:只需要处理几行的小事务与处理多行的大事务公平竞争。较小的innodb_concurrency_tickets值的缺点是,大型事务在完成之前必须通过队列多次循环,这就延长了完成任务所需的时间。

使用较大的值:大事务等待队列末端位置(由innodb_thread_concurrency控制)的时间更少,获取行所需的时间更多。大型事务还需要更少的队列访问来完成它们的任务。较大的innodb_concurrency_tickets值的缺点是,太多同时运行的大事务会让较小的事务等待更长的时间,从而饿死。

对于一个非零的innodb_thread_concurrency值,可能需要向上或向下调整innodb_concurrency_tickets值,以在较大和较小的事务之间找到最佳平衡。显示引擎INNODB状态报告显示当前通过队列的执行事务的剩余票数。还可以从INFORMATION_SCHEMA的TRX_CONCURRENCY_TICKETS列获得该数据。INNODB_TRX表。

image.png
允许InnoDB根据当前的工作负载自动调整innodb_thread_sleep_delay的值。任何非零值都可以自动动态调整innodb_thread_sleep_delay值,直到innodb_adaptive_max_sleep_delay选项中指定的最大值。该值表示微秒数。这个选项对于大于16个InnoDB线程的繁忙系统非常有用。(在实践中,它对于同时有数百或数千个连接的MySQL系统最有价值。)

image.png
同时可以提交的线程数。值0(默认值)允许同时提交任意数量的事务。
innodb_commit_concurrency的值不能在运行时从0更改为非0,反之亦然。该值可以从一个非零值更改为另一个非零值。

总结

1.从上述参数上看到并发范围应该在0~1000以内,超过范围应该存在很大问题。
2.实际场景下,基本innodb_thread_concurrency采用默认值0,交给MySQL系统自行管理。

3.那问题来了,什么情况下进行调整。

  • 如果一个工作负载中,并发用户线程的数量小于64,建议设置innodb_thread_concurrency=0;
  • 如果工作负载一直较为严重甚至偶尔达到顶峰,建议先设置innodb_thread_concurrency=80
  • MySQL与其他应用隔离,可以考虑绑定mysqld进程到专有的虚拟CPU
  • 高并发下机器性能已经无法支撑的时候,特别是一些低配置的虚拟机环境
  • 定期检测和分析系统,负载量、用户数,有效的对参数进行调整
  • 多个实例部署在一个服务器上,某个实例性能占比比较高
  • 主从延迟的一种控制手段
最后修改时间:2023-05-05 18:20:22
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论