alf*_*ish 217 mysql innodb database-recommendation
我有一个繁忙的数据库,只有 InnoDB 表,大小约为 5GB。数据库在使用 SSD 磁盘的 Debian 服务器上运行,我设置了最大连接数 = 800,这有时会饱和并使服务器停止运行。平均每秒查询约 2.5K。所以我需要优化内存使用,为最大可能的连接腾出空间。
我已经看到建议 innodb_buffer_pool_size 应该高达总内存的 %80。另一方面,我从调整引物脚本中收到此警告:
Max Memory Ever Allocated : 91.97 G
Configured Max Per-thread Buffers : 72.02 G
Configured Max Global Buffers : 19.86 G
Configured Max Memory Limit : 91.88 G
Physical Memory : 94.58 G
Run Code Online (Sandbox Code Playgroud)
这是我当前的 innodb 变量:
| innodb_adaptive_flushing | ON |
| innodb_adaptive_hash_index | ON |
| innodb_additional_mem_pool_size | 20971520 |
| innodb_autoextend_increment | 8 |
| innodb_autoinc_lock_mode | 1 |
| innodb_buffer_pool_instances | 1 |
| innodb_buffer_pool_size | 20971520000 |
| innodb_change_buffering | all |
| innodb_checksums | ON |
| innodb_commit_concurrency | 0 |
| innodb_concurrency_tickets | 500 |
| innodb_data_file_path | ibdata1:10M:autoextend |
| innodb_data_home_dir | |
| innodb_doublewrite | ON |
| innodb_fast_shutdown | 1 |
| innodb_file_format | Antelope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antelope |
| innodb_file_per_table | ON |
| innodb_flush_log_at_trx_commit | 2 |
| innodb_flush_method | O_DIRECT |
| innodb_force_load_corrupted | OFF |
| innodb_force_recovery | 0 |
| innodb_io_capacity | 200 |
| innodb_large_prefix | OFF |
| innodb_lock_wait_timeout | 50 |
| innodb_locks_unsafe_for_binlog | OFF |
| innodb_log_buffer_size | 4194304 |
| innodb_log_file_size | 524288000 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
| innodb_max_dirty_pages_pct | 75 |
| innodb_max_purge_lag | 0 |
| innodb_mirrored_log_groups | 1 |
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 0 |
| innodb_open_files | 300 |
| innodb_purge_batch_size | 20 |
| innodb_purge_threads | 0 |
| innodb_random_read_ahead | OFF |
| innodb_read_ahead_threshold | 56 |
| innodb_read_io_threads | 4 |
| innodb_replication_delay | 0 |
| innodb_rollback_on_timeout | OFF |
| innodb_rollback_segments | 128 |
| innodb_spin_wait_delay | 6 |
| innodb_stats_method | nulls_equal |
| innodb_stats_on_metadata | ON |
| innodb_stats_sample_pages | 8 |
| innodb_strict_mode | OFF |
| innodb_support_xa | ON |
| innodb_sync_spin_loops | 30 |
| innodb_table_locks | ON |
| innodb_thread_concurrency | 4 |
| innodb_thread_sleep_delay | 10000 |
| innodb_use_native_aio | ON |
| innodb_use_sys_malloc | ON |
| innodb_version | 1.1.8 |
| innodb_write_io_threads | 4 |
Run Code Online (Sandbox Code Playgroud)
一个可能相关的旁注:我看到当我尝试从 Drupal(位于单独的 Web 服务器上)向数据库插入一个大帖子(比如超过 10KB)时,它会永远持续并且页面没有正确返回。
关于这些,我想知道什么应该是我的 innodb_buffer_pool_size 以获得最佳性能。我感谢您为这种情况设置最佳参数和其他参数的建议。
Rol*_*DBA 324
你的innodb_buffer_pool_size是巨大的。您已将其设置为20971520000。那是 19.5135 GB。如果您只有 5GB 的 InnoDB 数据和索引,那么您应该只有大约 8GB。即使这可能太高了。
这是你应该做的。首先运行这个查询
SELECT CEILING(Total_InnoDB_Bytes*1.6/POWER(1024,3)) RIBPS FROM
(SELECT SUM(data_length+index_length) Total_InnoDB_Bytes
FROM information_schema.tables WHERE engine='InnoDB') A;
Run Code Online (Sandbox Code Playgroud)
这将为您提供 RIBPS,即推荐的 InnoDB 缓冲池大小,基于所有 InnoDB 数据和索引,额外增加 60%。
例如
mysql> SELECT CEILING(Total_InnoDB_Bytes*1.6/POWER(1024,3)) RIBPS FROM
-> (SELECT SUM(data_length+index_length) Total_InnoDB_Bytes
-> FROM information_schema.tables WHERE engine='InnoDB') A;
+-------+
| RIBPS |
+-------+
| 8 |
+-------+
1 row in set (4.31 sec)
mysql>
Run Code Online (Sandbox Code Playgroud)
使用此输出,您将在 /etc/my.cnf 中设置以下内容
[mysqld]
innodb_buffer_pool_size=8G
Run Code Online (Sandbox Code Playgroud)
下一个, service mysql restart
重启后,运行 MySQL 一两周。然后,运行此查询:
SELECT (PagesData*PageSize)/POWER(1024,3) DataGB FROM
(SELECT variable_value PagesData
FROM information_schema.global_status
WHERE variable_name='Innodb_buffer_pool_pages_data') A,
(SELECT variable_value PageSize
FROM information_schema.global_status
WHERE variable_name='Innodb_page_size') B;
Run Code Online (Sandbox Code Playgroud)
这将告诉您此时 InnoDB 缓冲池中的 InnoDB 数据实际使用了多少 GB 内存。
我以前写过这个:什么设置 innodb_buffer_pool 以及为什么..?
您可以立即运行此DataGB查询,而不是重新配置、重新启动并等待一周。
这个值DataGB更接近于 InnoDB 缓冲池应该有多大 +(innodb_change_buffer_max_size 中指定的百分比)。我相信这将远远少于您现在保留的20000M。RAM 中的节省可用于调整其他内容,例如
需要注意这一点非常重要:有时,InnoDB 可能需要比innodb_buffer_pool_size的值多 10% 。以下是MySQL 文档对此的说明:
将此值设置得越大,访问表中的数据所需的磁盘 I/O 就越少。在专用数据库服务器上,您最多可以将其设置为机器物理内存大小的 80%。如果出现以下其他问题,请准备好缩减此值:
物理内存的竞争可能会导致操作系统中的分页。
InnoDB 为缓冲区和控制结构保留了额外的内存,因此分配的总空间比指定的大小大约大 10%。
地址空间必须是连续的,这在具有在特定地址加载的 DLL 的 Windows 系统上可能是一个问题。
初始化缓冲池的时间大致与其大小成正比。在大型安装中,此初始化时间可能很长。例如,在现代 Linux x86_64 服务器上,10GB 缓冲池的初始化大约需要 6 秒。请参阅第 8.9.1 节,“InnoDB 缓冲池”。
我看到您的以下值 my.cnf
| innodb_io_capacity | 200 |
| innodb_read_io_threads | 4 |
| innodb_thread_concurrency | 4 |
| innodb_write_io_threads | 4 |
Run Code Online (Sandbox Code Playgroud)
这些数字将阻碍 InnoDB 访问多个内核
请设置以下内容:
[mysqld]
innodb_io_capacity = 2000
innodb_read_io_threads = 64
innodb_thread_concurrency = 0
innodb_write_io_threads = 64
Run Code Online (Sandbox Code Playgroud)
我之前在 DBA StackExchange 中写过这个
我刚刚在 Server Fault 中使用更简洁的公式回答了这样的问题:
SELECT CONCAT(CEILING(RIBPS/POWER(1024,pw)),SUBSTR(' KMGT',pw+1,1))
Recommended_InnoDB_Buffer_Pool_Size FROM
(
SELECT RIBPS,FLOOR(LOG(RIBPS)/LOG(1024)) pw
FROM
(
SELECT SUM(data_length+index_length)*1.1*growth RIBPS
FROM information_schema.tables AAA,
(SELECT 1.25 growth) BBB
WHERE ENGINE='InnoDB'
) AA
) A;
Run Code Online (Sandbox Code Playgroud)
Ric*_*mes 19
像这样的东西?使用SHOW VARIABLES和SHOW GLOBAL STATUS:
表达式: innodb_buffer_pool_size / _ram
含义: 用于 InnoDB buffer_pool 的 RAM 百分比
推荐范围: 60~80%
表达式: Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests
含义: 必须命中磁盘的读取请求
推荐范围: 0-2%
如果超出范围怎么办: 如果您有足够的内存,请增加 innodb_buffer_pool_size内存。
表达式: Innodb_pages_read / Innodb_buffer_pool_read_requests
含义: 必须命中磁盘的读取请求
推荐范围: 0-2%
如果超出范围怎么办: 如果您有足够的 RAM,请增加 innodb_buffer_pool_size。
表达式: Innodb_pages_written / Innodb_buffer_pool_write_requests
含义: 必须命中磁盘的写入请求
推荐范围: 0-15%
如果超出范围怎么办: 检查 innodb_buffer_pool_size
表达式: Innodb_buffer_pool_reads / Uptime
含义: 读取次数
推荐范围: 0-100/秒。
超出范围怎么办: 增加innodb_buffer_pool_size?
表达式: (Innodb_buffer_pool_reads + Innodb_buffer_pool_pages_flushed) / Uptime
含义: InnoDB I/O
推荐范围: 0-100/秒。
超出范围怎么办: 增加innodb_buffer_pool_size?
表达式: Innodb_buffer_pool_pages_flushed / Uptime
含义: 写入(刷新)
推荐范围: 0-100/秒。
超出范围怎么办: 增加innodb_buffer_pool_size?
表达式: Innodb_buffer_pool_wait_free / Uptime
含义: buffer_pool 中没有空闲页面时的计数器。也就是说,所有页面都是脏的。
推荐范围: 0-1/秒。
超出范围怎么办: 首先确定innodb_buffer_pool_size设置合理;如果仍然有问题,请减少 innodb_max_dirty_pages_pct
您的标题询问了 innodb_buffer_pool_size,但我怀疑这不是真正的问题。(罗兰多评论了为什么你把它设置得足够大,甚至太大。)
我设置了最大连接数 = 800,它有时会饱和并使服务器停止运行。
这是不清楚的。800 个处于“睡眠”模式的用户对系统的影响几乎为零。800 个活动线程将是一场灾难。有多少线程在“运行”?
线程是否相互阻塞?有关死锁等的一些线索,请参阅 SHOW ENGINE INNODB STATUS。
是否有任何查询出现在慢日志中?让我们优化它们。
你用的是什么版本?XtraDB(InnoDB 的替代品)在使用多核方面做得更好。5.6.7 做得更好。
innodb_buffer_pool_instances -- 将其更改为 8(假设有 20G 的 buffer_pool);它会稍微减少互斥量的争用。
您是 I/O 限制还是 CPU 限制?根据您的答案,解决方案完全不同。
SSD -- 如果所有日志文件都在非 SSD 驱动器上可能会更好。
小智 6
更多的内存总是更好,但根据我的经验,大多数时候缓冲池大小不适合您的数据大小。许多表大部分时间都处于非活动状态,例如备用表,因此 innodb 缓冲池大小应该适合您的活动数据大小。
您为活动页面指定的时间范围会影响性能,但存在一个最佳点,即对于更大的缓冲区大小,您不会获得更高的性能。您可以通过以下方式估计/计算/测量show engine innodb status
小智 5
@RickJames 用 sql 回答:
SELECT
'Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests' AS Expression,
'Read requests that had to hit disk' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_reads'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) * 100, 2) AS Val,
'0-2%' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'Innodb_pages_read / Innodb_buffer_pool_read_requests' AS Expression,
'Read requests that had to hit disk' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_pages_read'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) * 100, 2) AS Val,
'0-2%' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'Innodb_pages_written / Innodb_buffer_pool_write_requests' AS Expression,
'Write requests that had to hit disk' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_pages_written'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_write_requests'
) * 100, 2) AS Val,
'0-15%' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'Innodb_buffer_pool_reads / Uptime' AS Expression,
'Reads' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_reads'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Uptime'
)) AS Val,
'0-100/sec' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'(Innodb_buffer_pool_reads + Innodb_buffer_pool_pages_flushed) / Uptime' AS Expression,
'InnoDB I/O' AS Meaning,
ROUND(((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_reads'
)
+
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_pages_flushed'
))
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Uptime'
)) AS Val,
'0-100/sec' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'Innodb_buffer_pool_pages_flushed / Uptime' AS Expression,
'Writes (flushes)' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_pages_flushed'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Uptime'
)) AS Val,
'0-100/sec' AS Recommend,
'Increase innodb_buffer_pool_size if you have enough RAM.' AS WhatToDoIfOutOfRange
UNION
SELECT
'Innodb_buffer_pool_wait_free / Uptime' AS Expression,
'Counter for when there are no free pages in buffer_pool. That is, all pages are dirty.' AS Meaning,
ROUND((SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Innodb_buffer_pool_wait_free'
)
/
(SELECT
VARIABLE_VALUE
FROM
information_schema.GLOBAL_STATUS
WHERE
VARIABLE_NAME = 'Uptime'
)) AS Val,
'0-1/sec' AS Recommend,
'First be sure innodb_buffer_pool_size is set reasonably; if still trouble, decrease innodb_max_dirty_pages_pct' AS WhatToDoIfOutOfRange
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
365753 次 |
| 最近记录: |