块更改:InnoDB缓冲池大小调整
自MySQL 5.7.5以来,我们已经能够动态调整InnoDB缓冲池的大小。这个新功能还引入了一个新变量 - innodb_buffer_pool_chunk_size - 它定义了缓冲池被放大或缩小的块大小。此变量不是动态的,如果配置不正确,可能会导致不希望出现的情况。
先来看看innodb_buffer_pool_size,innodb_buffer_pool_instances和innodb_buffer_pool_chunk_size如何交互:
缓冲池可以容纳多个实例,每个实例被分成块。我们需要考虑一些信息:实例数量从1到64,总块数不应超过1000。
因此,对于具有3GB RAM的服务器,具有8个实例的2GB缓冲池和默认值(128MB)的块,我们将获得每个实例2个块:
这意味着将会有16块。
我不打算解释拥有多个实例的好处,我将专注于调整操作大小。你为什么要调整缓冲池的大小?那么,有几个原因,比如:
在虚拟服务器上,您可以动态添加更多内存
对于物理服务器,您可能希望减少数据库内存使用量以让其他进程取而代之
在数据库大小小于可用RAM的系统上
如果您预计会有巨大的增长并希望按需增加缓冲池
减少缓冲池
我们开始减少缓冲池
| innodb_buffer_pool_size | 2147483648 |
| innodb_buffer_pool_instances | 8 |
| innodb_buffer_pool_chunk_size | 134217728 |
mysql> set global innodb_buffer_pool_size=1073741824;
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 1073741824 |
+-------------------------+------------+
1 row in set (0.00 sec)
如果我们试图将其降低到1.5GB,那么缓冲池不会改变,并会显示警告:
mysql> set global innodb_buffer_pool_size=1610612736;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------------------------+
| Warning | 1210 | InnoDB: Cannot resize buffer pool to lesser than chunk size of 134217728 bytes. |
+---------+------+---------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show global variables like 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 2147483648 |
+-------------------------+------------+
1 row in set (0.01 sec)
增加缓冲池
当我们尝试将值从1GB增加到1.5GB时,将调整缓冲池的大小,但请求的innodb_buffer_pool_size被认为是不正确的并被截断:
mysql> set global innodb_buffer_pool_size=1610612736;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect innodb_buffer_pool_size value: '1610612736' |
+---------+------+-----------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show global variables like 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name | Value |
+-------------------------+------------+
| innodb_buffer_pool_size | 2147483648 |
+-------------------------+------------+
1 row in set (0.01 sec)
最终的大小是2GB。是! 您打算将该值设置为1.5GB,并成功将其设置为2GB。即使你设置了更高的1个字节,比如设置:1073741825,你最终将得到一个2GB的缓冲池。
mysql> set global innodb_buffer_pool_size=1073741825;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show global variables like 'innodb_buffer_pool_%size' ;
+-------------------------------+------------+
| Variable_name | Value |
+-------------------------------+------------+
| innodb_buffer_pool_chunk_size | 134217728 |
| innodb_buffer_pool_size | 2147483648 |
+-------------------------------+------------+
2 rows in set (0.01 sec)
有趣的场景
增加配置文件的大小
假设有一天你起床时愿意更改或调整服务器中的某些变量,并且您决定在有空闲内存时增加缓冲池。在这个例子中,我们将使用一个 innodb_buffer_pool_instances = 16 和2GB缓冲池大小的服务器,它将增加到2.5GB
所以,我们在配置文件中设置:
innodb_buffer_pool_size = 2684354560
但重启后,我们发现:
mysql> show global variables like 'innodb_buffer_pool_%size' ;
+-------------------------------+------------+
| Variable_name | Value |
+-------------------------------+------------+
| innodb_buffer_pool_chunk_size | 134217728 |
| innodb_buffer_pool_size | 4294967296 |
+-------------------------------+------------+
2 rows in set (0.00 sec)
错误日志说:
2018-05-02T21:52:43.568054Z 0 [Note] InnoDB: Initializing buffer pool, total size = 4G, instances = 16, chunk size = 128M
因此,在将配置文件中的innodb_buffer_pool_size设置为2.5GB后,由于实例的数量和块大小,数据库为我们提供了4GB的缓冲池。信息没有告诉我们的是块的数量,这将有助于理解这种巨大差异的原因。
我们来看看如何计算。
增加实例和块大小
更改实例数或块大小将需要重新启动,并将考虑缓冲池大小作为设置块大小的上限。例如,使用这种配置:
innodb_buffer_pool_size = 2147483648
innodb_buffer_pool_instances = 32
innodb_buffer_pool_chunk_size = 134217728
我们得到这个块大小:
mysql> show global variables like 'innodb_buffer_pool_%size' ;
+-------------------------------+------------+
| Variable_name | Value |
+-------------------------------+------------+
| innodb_buffer_pool_chunk_size | 67108864 |
| innodb_buffer_pool_size | 2147483648 |
+-------------------------------+------------+
2 rows in set (0.00 sec)
但是,我们需要了解这是如何工作的。要获得innodb_buffer_pool_chunk_size,它将进行如下计算:innodb_buffer_pool_size / innodb_buffer_pool_instances,其结果取整为1MB的倍数。
在我们的例子中,计算将是2147483648/32 = 67108864,其中67108864%1048576 = 0,不需要舍入。块的数量将是每个实例的一个块。
它什么时候认为它需要每个实例使用更多的块?当所需大小与文件中配置的innodb_buffer_pool_size之间的差异大于或等于1MB时。
这就是为什么,例如,如果您尝试将innodb_buffer_pool_size设置为1GB + 1MB - 1B,您将获得1GB的缓冲池:
innodb_buffer_pool_size = 1074790399
innodb_buffer_pool_instances = 16
innodb_buffer_pool_chunk_size = 67141632
2018-05-07T09:26:43.328313Z 0 [Note] InnoDB: Initializing buffer pool, total size = 1G, instances = 16, chunk size = 64M
但是,如果您将innodb_buffer_pool_size设置为1GB + 1MB,您将获得2GB的缓冲池:
innodb_buffer_pool_size = 1074790400
innodb_buffer_pool_instances = 16
innodb_buffer_pool_chunk_size = 67141632
2018-05-07T09:25:48.204032Z 0 [Note] InnoDB: Initializing buffer pool, total size = 2G, instances = 16, chunk size = 64M
这是因为它认为两个块将适合。我们可以说这就是InnoDB缓冲池大小的计算方式:
determine_best_chunk_size{
if innodb_buffer_pool_size / innodb_buffer_pool_instances < innodb_buffer_pool_chunk_size
then
innodb_buffer_pool_chunk_size = roundDownMB(innodb_buffer_pool_size / innodb_buffer_pool_instances)
fi
}
determine_amount_of_chunks{
innodb_buffer_amount_chunks_per_instance = roundDown(innodb_buffer_pool_size / innodb_buffer_pool_instances / innodb_buffer_pool_chunk_size)
if innodb_buffer_amount_chunks_per_instance * innodb_buffer_pool_instances * innodb_buffer_pool_chunk_size - innodb_buffer_pool_size > 1024*1024
then
innodb_buffer_amount_chunks_per_instance++
fi
}
determine_best_chunk_size
determine_amount_of_chunks
innodb_buffer_pool_size = innodb_buffer_pool_instances * innodb_buffer_pool_chunk_size * innodb_buffer_amount_chunks_per_instance
什么是最好的设置?
为了分析最佳设置,您需要知道1000块的上限。在我们的例子中,有16个实例,每个实例的块数不能超过62个。
需要考虑的另一件事是每个块以百分比表示。继续举例说明,每个实例的每个块代表1.61%,这意味着我们可以增加或减少完整的缓冲池大小(以此倍数为单位)。
从管理角度来看,我认为您可能需要考虑至少2%到5%的范围来增加或减少缓冲区。我进行了一些测试,看看有小块的影响,我发现没有问题,但这是需要彻底测试的。