H2 是一个单线程数据库,在性能方面享有盛誉。其他数据库是多线程的。
我的问题是:什么时候多线程数据库比单线程数据库更有趣?有多少用户?有多少进程?触发器是什么?有人有经验可以分享吗?
概括
- 通常的瓶颈是磁盘访问
- SSD 速度快,但很脆弱(必须进行故障处理)
- 单线程系统上的一个长查询将阻塞所有其他查询
- 配置多线程系统可能很棘手
- 即使在单核系统上,多线程数据库也是有益的
H2 是一个单线程数据库,在性能方面享有盛誉。其他数据库是多线程的。
我的问题是:什么时候多线程数据库比单线程数据库更有趣?有多少用户?有多少进程?触发器是什么?有人有经验可以分享吗?
概括
关于 MySQL,如果我能说一件事,那就是 InnoDB,它的事务(ACID 兼容)存储引擎,确实是多线程的。但是,它与您配置的一样多线程!!!即使是“开箱即用”,InnoDB 在默认设置下在单 CPU 环境中也表现出色。要利用 InnoDB 多线程功能,您必须记住激活很多选项。
innodb_thread_concurrency设置 InnoDB 可以保持打开的并发线程数的上限。为此设置的最佳整数是(2 X CPU 数量)+ 磁盘数量。更新:正如我从 Percona NYC 会议中了解到的那样,您应该将其设置为 0,以提醒 InnoDB 存储引擎为其运行的环境找到最佳线程数。
innodb_concurrency_tickets设置可以不受惩罚地绕过并发检查的线程数。达到该限制后,线程并发检查再次成为常态。
innodb_commit_concurrency设置可以提交的并发事务数。由于默认值为 0,因此不设置它允许同时提交任意数量的事务。
innodb_thread_sleep_delay设置 InnoDB 线程在重新进入 InnoDB 队列之前可以休眠的毫秒数。默认值为 10000(10 秒)。
innodb_read_io_threads和innodb_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 实例可以在单个核心服务器上运行良好。
以下是我的看法:
通常数据库系统的瓶颈(或最慢的部分)是磁盘。CPU 仅在算术运算、处理或 CPU 执行的任何其他任务期间出现峰值。通过适当的架构,多线程可以帮助抵消 CPU 上的查询负载,而不是进行缓慢的磁盘读/写。在某些情况下,使用 CPU 周期计算值比创建计算列(先前保存到磁盘)并从磁盘读取该列更快。
在某些 RDBMS 中有一个临时 DB (tempdb),该实例上的所有 DB 都使用它来进行排序、散列、临时变量等。多线程和拆分此 tempdb 文件可用于提高 tempdb 的吞吐量,从而提高整体服务器性能。
使用多线程(并行性),查询的结果集可以拆分为在服务器的不同内核上进行处理,而不是单独使用一个内核。此功能并不总能提高性能,但在某些情况下确实如此,因此该功能可用。
DB 可用的线程有多种用途:读/写磁盘、用户连接、后台作业、锁定/闩锁、网络 IO 等......根据操作系统架构,线程被抢先馈送到 CPU 并且是使用等待和队列进行管理。如果 CPU 可以很快地处理这些线程,那么等待时间就会很短。多线程数据库将比单线程数据库更快,因为在单线程数据库中,将只回收一个线程而不是让其他线程可用的开销。
可扩展性也成为一个问题,因为需要更多线程来管理和执行扩展的数据库系统。
只要您有多个并发用户或进程,甚至是具有多线程数据库访问的单个进程,拥有一个支持线程的数据库就会变得有趣。
H2 是线程安全的,但是对数据库的所有请求都进行了序列化,这在重负载场景下可能会成为潜在的性能问题。对于特定项目是否确实如此,取决于您的性能要求、访问数据库的线程/用户/进程的数量、这些线程执行的查询频率以及您的平均和最差情况下的性能。查询。
例如,如果你的性能要求是在一秒钟内得到响应,你有不超过 10 个并发用户执行一个需要 0.05 秒执行的查询,单线程数据库仍然可以让你达到这些目标(尽管多线程可能已经显着提升了性能)。考虑到与单个潜在查询相同的场景,但最坏情况下性能为半秒,序列化数据库访问将不再让您满足性能目标。
如果您当前在您的项目中使用 H2,我建议您在负载情况下针对您的代码库运行分析器(只需使用一些典型的用例启动 x 数量的线程同时访问您的代码)。这将为您提供有关代码库中性能和瓶颈的实际指标,而不仅仅是理论化。如果这表明您的请求大部分时间都在等待访问数据库,那么是时候转移到线程数据库了。
据我所知,“单线程”对于 H2 来说有点用词不当。关键是它序列化所有事务(即一次只做一个)。
关于您的应用程序是否“可以”的关键问题不是“有多少用户?” 甚至是“有多少进程?”,而是“我的交易需要多长时间?”
如果您的所有交易都在亚秒以下,那可能没问题,如果有些交易需要几个小时才能完成,那可能就不行了,因为所有其他待处理的交易都在等待它们完成。关于这是否“好”的决定将取决于您自己的性能要求 - 即我的用户使用事务访问数据库的可接受等待时间。
- 编辑
似乎 H2 并没有真正序列化事务 - 只是 DML。换句话说,单个长事务中的大量短更新不会阻塞其他更新。但是,除非您使用实验性 MVCC 功能,否则表锁定意味着这在实践中具有类似的效果。还有一个实验性的“多线程”功能,但不能与 MVCC 同时使用
引用 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
从待办事项列表(“我们不想要的功能”)中:
http://wiki.postgresql.org/wiki/Todo#Features_We_Do_Not_Want
所以,再次......我完全不知道上述的优点。只是太长了,无法发表评论。
只有当您有超过 1 个并行查询进入数据库时,多线程数据库才会使您受益。这取决于您拥有的用户数量。如果您有超过 10 个用户同时在应用程序上工作,他们很可能会同时在数据库上生成多个查询。
此外,多线程数据库只有在 CPU 上有多核时才能受益。如果有单核,多线程数据库必须将作业排队并在单核上顺序执行。当有多核时,每个核可以并行运行一个线程。从而获得更好的性能。
这是否回答了您的问题?