关于单线程与多线程数据库的性能


58

H2是在性能方面享有良好声誉的单线程数据库。其他数据库是多线程的。

我的问题是:多线程数据库什么时候比单线程数据库更有趣?有多少用户?多少个过程?触发因素是什么?任何人都可以分享经验吗?

摘要

  • 通常的瓶颈是磁盘访问
  • SSD速度快,但易碎(必须执行故障处理程序)
  • 在单线程系统上执行一个长查询将阻止所有其他查询
  • 配置多线程系统可能很棘手
  • 即使在单核系统上,多线程数据库也很有用

就我所知,线程就此问题而言是“线程或进程”的意思-例如,postgres不是多线程的,但问题不是试图将(H2,postgres)与(Oracle,SQL Server等)进行比较
Jack道格拉斯(Douglas)

Answers:


31

这是我的意见:

通常,数据库系统的瓶颈(或最慢的部分)是磁盘。CPU仅在算术运算,处理或CPU执行的任何其他任务期间出现峰值。使用适当的体系结构,多线程可以帮助抵消查询在CPU上的负载,而不是进行慢速的磁盘读/写操作。在某些情况下,使用CPU周期计算值要比创建计算列(以前已保存到磁盘)并从磁盘读取此列要快。

在某些RDBMS中,该实例上的所有DB都使用一个临时DB(tempdb)进行排序,散列,临时变量等。多线程和拆分此tempdb文件可用于提高tempdb的吞吐量。 ,从而提高整体服务器性能。

使用多线程(并行),可以将查询的结果集拆分为在服务器的不同内核上进行处理,而不必单独使用一个内核。此功能并不总是可以提高性能,但是在某些情况下可以提高性能,因此该功能可用。

DB可用的线程有多种用途:读/写磁盘,用户连接,后台作业,锁定/闩锁,网络IO等...根据操作系统的架构,线程被抢先馈送到CPU,并且使用等待和队列进行管理。如果CPU可以很快处理这些线程,则等待时间将很短。多线程DB将比单线程DB快,因为在单线程DB中,将仅回收一个线程而不是其他可用线程的开销。

可伸缩性也成为一个问题,因为将需要更多线程来管理和执行可伸缩的DB系统。


感谢您的见解。我听到人们赞扬固态硬盘。我想在确保查询写得很好并且应用程序合理并行之后,对这些进行投资可能是最好的选择。
杰罗姆Verstrynge

@Stan- multithreaded在这种情况下,我认为含义有所不同,即所有交易都按Luke的回答所述进行了序列化。
杰克·道格拉斯

@JVerstry〜不,不是。阅读Jeff Atwood关于SSD的想法...它们的故障率很高。最好的办法是正确索引数据并编写正确的查询。
jcolebrand

@jcolebrand好吧,他似乎只与一个强大的备份系统,倡导他们速度时,他们失败
杰罗姆Verstrynge

2
@Jverstry〜是的,如果您了解该概念并且对此表示满意,并且不介意重建整个生产环境(或等待自动故障转移开始,然后在不久的将来重建),那么去做,他们会让事情变得更快,是的。
jcolebrand

47

关于MySQL,我能说的就是InnoDB(它的事务性(符合ACID的)存储引擎)确实是多线程的。但是,它与您配置的一样多线程!即使开箱即用,InnoDB在默认设置下也可以在单个CPU环境中发挥出色的性能。要利用InnoDB多线程功能,您必须记住要激活很多选项。

innodb_thread_concurrency设置InnoDB可以保持打开状态的并发线程数的上限。为此设置的最佳轮数是(2 X CPU数量)+磁盘数量。更新:正如我从Percona NYC大会上第一手了解到的那样,您应该将其设置为0,以提醒InnoDB Storage Engine为正在运行的环境找到最佳线程数。

innodb_concurrency_tickets设置可以绕过并发检查而不受惩罚的线程数。达到该限制后,线程并发检查再次成为常态。

innodb_commit_concurrency设置可以提交的并发事务数。由于默认值为0,因此未设置此选项将允许任意数量的事务同时提交。

innodb_thread_sleep_delay设置在重新输入InnoDB队列之前InnoDB线程可以处于休眠状态的毫秒数。默认值为10000(10秒)。

innodb_read_io_threadsinnodb_write_io_threads(均自MySQL 5.1.38起)为读取和写入分配指定数量的线程。默认值为4,最大值为64。

innodb_replication_delay在达到innodb_thread_concurrency时在从属服务器上施加线程延迟。

innodb_read_ahead_threshold允许在切换到异步读取之前线性读取设置数量的扩展数据块(64页[page = 16K])。

如果我命名更多选项,时间将使我逃脱。您可以在MySQL的文档中阅读有关它们的信息

大多数人都不知道这些功能,对InnoDB仅仅进行符合ACID的事务非常满意。如果您调整这些选项中的任何一个,后果自负。

我玩过MySQL 5.5多个缓冲池实例(9个缓冲池实例中为162GB),并试图通过这种方式在内存中对数据进行自动分区。一些专家说,这应该使您的性能提高50%。我得到的是大量使InnoDB爬网的线程锁定。我切换到1个缓冲区(162GB),世界上一切都恢复了。我想您需要Percona专家来进行设置。我明天将在纽约举行的Percona MySQL大会上,将问机会是否有机会。

总而言之,鉴于InnoDB在多线程操作中的默认设置,它现在在多CPU服务器中表现良好。调整它们需要格外小心,耐心,文档和咖啡(或Red Bull,Jolt等)。

早上好,晚上好,晚上好!

更新2011-05-27 20:11

周四从纽约的Percona MySQL会议回来。真是个会议。学到了很多东西,但是我得到了一个有关InnoDB的答案。Ronald Bradford告诉我,将innodb_thread_concurrency设置为0将使InnoDB通过线程并发在内部决定最佳的操作过程。我将在MySQL 5.5中对此进行进一步试验。

更新2011-06-01 11:20

就一个长查询而言,InnoDB 符合ACID,并且使用MultiVersion Concurrency Control可以很好地运行。事务应该能够带有隔离级别(默认情况下为可重复读取),以防止阻塞其他人访问数据。

对于多核系统,InnoDB已经走了很长一段路。过去,InnoDB在多核环境中表现不佳。我记得必须在单个服务器上运行多个mysql实例来获取多个内核,以便在CPU上分布多个mysqld进程。这要归功于Percona和后来的MySQL(例如,Oracle,这仍然让我感到烦恼),这是不必要的,因为他们将InnoDB开发为更成熟的存储引擎,可以轻松地访问内核而无需进行大量调整。今天,InnoDB的当前实例可以在单个核心服务器上很好地运行。


11

一旦有多个并发用户或进程,甚至是具有多线程数据库访问权限的单个进程,拥有一个支持线程的数据库就会变得很有趣。

H2是线程安全的,但是会将所有请求序列化到数据库,这在重负载情况下可能会成为潜在的性能问题。特定项目是否真的如此取决于您的性能要求,访问数据库的线程/用户/进程的数量,这些线程执行查询的频率以及您的平均和最坏情况的性能的组合查询。

例如,如果您的性能要求是在一秒钟之内得到响应,那么您执行一次查询的并发用户不超过10个,执行一次查询需要花费0.05秒的时间,那么单线程数据库仍然可以实现这些目标(尽管多线程可能已经带来了明显的性能提升)。在相同的情况下,如果使用单个潜在查询,但在最坏情况下的性能为半秒,则序列化数据库访问将不再使您达到性能目标。

如果您当前在项目上使用H2,我建议您在负载情况下针对代码库运行事件探查器(只需使用一些典型用例启动x个线程并发命中代码)。这将为您提供有关代码库中性能和瓶颈的实际指标,而不仅仅是理论上。如果这表明您的请求花费大量时间只是在等待访问数据库,那么该是时候转移到线程化数据库了。


H2是否会序列化所有请求-还是仅序列化DML?
杰克·道格拉斯

8

据我所知,“单线程”对于H2来说有点用词不当。关键是它会序列化所有事务(即一次执行一次)。

关于您的应用程序是否可以通过的关键问题不是“有多少用户?” 甚至“多少个流程?”,但“我的交易需要多长时间?”

如果您的所有事务都在不到一秒钟的时间里,这可能很好,如果某些事务需要几个小时才能完成,那可能就不好了,因为所有其他待处理的事务都将等待它们完成。是否“精细”的决定将取决于您自己的性能要求,即,等待我的用户使用事务访问数据库多长时间。

- 编辑

似乎H2并没有真正序列化事务-只是DML。换句话说,单个长事务中的许多短更新不会阻止其他更新。但是,除非您使用实验性MVCC功能,否则表锁定意味着在实践中具有类似的效果。还有一个实验性的“多线程”功能,不能与MVCC同时使用


5

引用PostgreSQL网站上的点点滴滴……请注意,我绝对不知道这些参数的优点-它们只是不适合发表评论。

通过开发者常见问题解答(“为什么不使用线程...”):

http://wiki.postgresql.org/wiki/Developer_FAQ#Why_don.27t_you_use_threads.2C_raw_devices.2C_async-I.2FO.2C_.3Cinsert_your_favorite_wizz-bang_feature_here.3E.3F

当前不使用线程,而不是将多个进程用于后端,因为:(...)

  • 一个后端中的错误可能会破坏其他后端(如果它们是单个进程中的线程)
  • 与剩余的后端启动时间相比,使用线程的速度提高很小。
  • 共享只读可执行程序映射和使用shared_buffers意味着进程(例如线程)非常有效地利用内存
  • 定期创建和销毁进程有助于防止内存碎片,这在长时间运行的进程中可能很难管理

从“待办事项”列表中(“我们不想要的功能”):

http://wiki.postgresql.org/wiki/Todo#Features_We_Do_Not_Want

所有后端在单个进程中作为线程运行(不需要)

这消除了我们从当前设置中获得的过程保护。线程创建通常与现代系统上的进程创建是相同的开销,因此使用纯线程模型似乎是不明智的,而且MySQL和DB2已证明线程引入了解决的许多问题。(...)

所以,再次...我绝对不知道上述优点。它太长了,无法发表评论。


-3

仅当您有多个并行查询进入数据库时​​,多线程数据库才会对您有利。这取决于您拥有的用户数。如果您同时有十个以上的用户在处理该应用程序,则很可能他们将同时在数据库上产生多个查询。

而且,只有在CPU上有多核的情况下,多线程数据库才能受益。如果有单核,则多线程数据库必须将作业排队,并在单核上顺序执行它们。如果有多核,则每个核可以并行运行一个线程。从而获得更好的性能。

这会回答您的查询吗?


7
多线程数据库甚至在单核系统上也是有益的。它可以防止一个长时间运行的查询阻止所有其他数据库访问,另外,您可能让多个线程在磁盘或网络I / O上等待,而另一个线程正在积极地解析查询,处理预取的数据等

一个用户可能正在使用一个使某些操作并行化的程序。如果数据库也具有多线程/多处理功能,则该程序最有可能受益。
joanolo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.