2.5 并发如何影响性能
我们刚刚讨论了当并发线程或事务产生冲突从而导致性能问题或者甚至查询中止的情况。你已经了解了SQL语句或者存储引擎设置的锁是如何影响并发线程的。这些锁是对用户可见的,尽管它们并非始终容易调试,但是很容易追踪。当应用程序可能产生并发的MySQL连接的时候,你需要了解可能的并行竞争的线程。这在Web服务器上尤为常见,Web服务器会打开与MySQL服务器的并行连接,因为会有很多用户打开由Web服务器提供的网页。我们也讨论了在应用程序处理错误时难以避免的结果错误或者显著变慢问题。当我为本书搜集示例的时候,我把所有这样的示例都放在1.2节中。我把这些问题区别于性能问题,因为你可以立即看到它们的结果,而性能问题通常情况下是先隐蔽起来的,并且你一般是在检查了慢查询日志或者接到关于应用缓慢的用户投诉之后才会注意到它们。下面处理更为隐蔽的性能问题。如果一个查询突然开始执行缓慢,第一步应该确认它是否是合理优化过的。最简单的确认方式就是在一个隔离的、单线程的环境里去执行该查询。如果该查询仍然执行缓慢,那么它或者需要优化,或者最近的大量更新操作导致索引统计数据过期了(第1章包含基本的优化技巧)。如果一个查询在单线程环境中很快完成但是在多线程环境中执行缓慢,这基本可以确定你遇到了并发问题。本书介绍过的所有应对错误结果的技术也适用于这种情况。慢查询只是相对略微复杂的问题,因为要调试这些问题,你需要重再现你遇到问题时候的情况,而当你想要重现的时候却又很难遇到。
提示
我经常强调重现问题,而不是仅仅移除有问题的查询。对于并发问题来说,这很重要,因为有问题的查询可能仅仅是深层次问题的一个表象。如果你仅是停止执行查询而不是解决掉真正的问题,你很可能会在应用程序的其他部分遭遇同样的问题。
2.5.1 为并发问题监控InnoDB事务
如果你正在调试由InnoDB事务引起的锁问题,InnoDB监控器会减轻你的工作。你仅需要打开监控器,然后它便会定期将消息转储到错误日志文件中,这与你使用SHOW ENGINE INNODB STATUS命令看到的输出类似。要打开InnoDB监控器,需要在任何数据库中创建一个叫做innodb_monitor的表: MySQL客户端命令中的-A选项在你尝试调试与并发有关的问题时非常有用。正常情况下,客户端会请求可用表列表。然后,客户端会被其他连接持有的锁阻塞,这会阻塞客户端调试。选项-A会阻止表列表请求。如果你这么做了,InnoDB引擎会识别出该表并且开始向错误日志文件中输出信息。所以,如果你检查在慢查询运行时记录的事务信息,你可以找出谁持有了阻塞查询的锁。关于InnoDB监控器的更多信息可在第6章以及2.8.2节中看到。
2.5.2 为并发问题监控其他资源
如果你调试的查询没有使用InnoDB存储引擎或者你怀疑问题是由于其他不同类型的锁引起的,那么我们仍然有许多选择。可以使用SHOW PROCESSLIST命令,不过更好的选择是定时重复地执行SELECT… FROM INFORMATION_SCHEMA.PROCESSLIST命令并且将其输出以及其他信息一起保存到文件或表中。后者的输出信息比SHOW PROCESSLIST的输出更好理解和掌握。当通过慢查询找到阻塞查询问题的线索的时候,可以检同时查进程列表信息。并发查询对性能的影响不总是停留在SQL或者存储引擎层。MySQL服务器中的多个线程也会共享如内存(RAM)和CPU等硬件资源。把这些资源中的一部分分配给每个线程,把其他(如临时表等)资源分配给指定类型的操作并且只在必要的时候分配。一些资源被所有线程共享。你在设计应用程序时也需要考虑到操作系统的限制。本节将会介绍这些资源影响性能的一些概念,然后第3章将会详细介绍控制资源使用的选项。从每个线程的内存分配开始。MySQL服务器有许多选项让你可以设置特定于线程的缓冲区大小。简单来说,分配的内存越多,线程运行得越快。然而这些缓冲区是分配给每个运行的单独线程的,所以给每个线程分配的资源越多,能同时运行的线程数就越少。所以,人们总是寻求能提升性能的值和实际物理内存间的平衡。分配给指定操作类型的资源也是有限制的。除非需要,不要设置得过大,当然也不要设置得过小。一个好的做法是仅给一小部分需要大缓冲区的会话(连接)设置一个较高的值,而其他的设置为默认值。
这种级别的控制可以基于每个会话动态地进行设置:
第三类资源是被所有线程共享的资源,最常见的是内部缓存。有了这些配置选项,你一般不用担心增加更多的连接会增加内存使用。不过有一个潜在的问题,那就是修改数据会使缓存失效从而导致随后的语句消耗更长的时间。通常这是一个很快的操作,不过如果缓存过大,失效时间可能会很长,从而在线程等待缓存恢复访问的时候会影响用户使用。最后,性能问题可能会由于操作系统的资源引起,如文件描述符和CPU。系统上文件描述符的数量会限制服务器可以创建的连接数量,可以同时打开的表的数量,甚至同一个表分区的数量。如果表的分区数大于可用文件操作符的数量,你会发现连打开一个表都不可能。第4章会讨论操作系统如何影响MySQL服务器。