作者:Morgan Tocker
Vitess对数据库的可伸缩性有自己的看法。有些观点很少有争议,比如应该如何通过复制提供持久性,但是我发现一个有趣的建议是每个MySQL服务器250GB。
https://vitess.io/docs/overview/scalability-philosophy/
这是物理的MySQL限制吗?
简而言之:不是。我说的“物理限制”是指是否存在文件格式限制,即数据库不能大于250GB?
InnoDB的物理限制是每个表空间(tablespace)64TB,在默认配置中,每个表(table)都有自己的表空间。通过表分区(table partitioning),可以进一步扩展这个限制。
这是实际的MySQL限制吗?
简而言之:不一定。所谓的“实际限制”,我的意思是当MySQL达到250GB的数据库大小时,它会立即崩溃吗?在物理极限之前达到实际极限是很常见的。
这个问题的答案,在很大程度上取决于表结构(和查询模式)。以这些场景为例:
表A:
CREATE TABLE tablea (
id INT NOT NULL PRIMARY KEY auto_increment,
b DATETIME NOT NULL,
c VARBINARY(512) NOT NULL,
INDEX(b)
);
表B:
CREATE TABLE tableb (
id INT NOT NULL PRIMARY KEY auto_increment,
b DATETIME NOT NULL,
c VARBINARY(512) NOT NULL,
UNIQUE (c)
);
..它们看起来几乎一样,对吧?让我们试着在32个并行线程中插入行,持续一个小时:
INSERT INTO {tablename} (b, c) VALUES (NOW(), RANDOM_BYTES(512)), (NOW(), RANDOM_BYTES(512)), ..;
表A:1小时的插入性能
在一个小时内,我能够插入1.13亿行数据。尽管最终的表大小(93GB)比InnoDB缓冲池(16GB)大得多,但是插入性能相当一致。我怀疑最初性能的急剧下降是因为超过了SSD写缓存。
表B:1小时的插入性能
插入性能随着表变大而下降。16GB的缓冲池不足以容纳所有重要的页,iostat显示了大量的读/秒,因为需要读取-修改-写入页。最后插入的行数为2900万,表大小为50GB。
为什么这两个表的表现如此不同呢?
c上的索引更宽(512字节vs.6字节),但是随机插入加上惟一性是真正的性能杀手。
对于表A,性能是稳定和一致的,因为插入在表的末尾,所需的页在内存中。我用一个128MB的缓冲池重复了这个基准测试,结果只发现性能下降了13%:
表A:1小时的插入性能(128M缓冲池)
1小时后的总行数为1亿。这与使用16GB缓冲池的测试只相差13%(下表作比较)。
表A:128M vs. 16M缓冲池
在表B中,插入性能在基准测试的运行期间是不可持续的。因为惟一索引上的插入模式是随机的,所以不能保证所需的索引页在内存中。但是必须加载这些页以确保没有违反约束检查(c列必须是惟一的)。
因此,可以公平地说,表B上的工作负载需要比表A上的工作负载更高的内存适合度。我们还可以通过将RANDOM_BYTES(512)转换为插入效率更高但仍然是512字节的内容来提高性能:
SELECT LENGTH(CONCAT(current_timestamp(6), RANDOM_BYTES(486)));
+---------------------------------------------------------+
| LENGTH(CONCAT(current_timestamp(6), RANDOM_BYTES(486))) |
+---------------------------------------------------------+
| 512 |
+---------------------------------------------------------+
1 row in set (0.00 sec)
转换为有效率地插入
通过在随机字节前面加上26字节的时间戳,该值就变成了有效率地插入。使用我们的16GB缓冲池,我们现在的读-修改-写速率非常低,并且可以随着表的增长保持性能。
比较“有效率地插入”和c的随机值之间每秒插入的性能。越高越好。注意,当表变大时,有效率地插入如何维持性能。
有效的插入可以扩展到多远?
当缓冲池从16GB降低到128MB时,表A只损失了13%的插入性能。为了证明没有明确的“最大行数”限制,现在让我们将测试运行时间延长到5小时。在插入了近4.63亿行之后,我们可以看到我们的376GB表仍然保留了大部分的插入性能:
插入运行5小时,性能保持不变。在4.63亿行中,与1小时内插入的1.13亿行相比,只减少了18%。InnoDB内部使用页来存储,缓冲池缓存是面向页的。没有直接的证据表明表大小有行数限制。
插入性能不受数据大小或行数的限制。它取决于表+索引结构以及如何插入行。在这里很难给出一个一般化的答案。你可以有一个256GB的数据库,它可以很好地与1GB的RAM一起工作,而另一个256GB的数据库需要128GB的RAM。
这样,为什么设极限呢?
前一节中的示例描述了插入性能,以说明一点。但是性能并不局限于插入性能:-)具体来说,一些管理任务在较大的数据库中变得更加困难:
让我们以4TB分片故障为例:
Vitess并没有将250GB作为硬性限制。它甚至鼓励你在同一主机上运行多个MySQL实例(多个tablet)。
总结
通过指定推荐的大小,Vitess的作者还可以对某些操作需要多长时间进行假设,并简化系统的设计。或者换句话说:Vitess的作者们决定不采用一种放之四海而皆宜的方法来实现可伸缩性,于是我又回到了开头的那句话:Vitess对数据库的可伸缩性有自己的看法。
Vitess建议使用250G作为分片大小,用于管理和可预测的恢复时间。出于性能方面的原因,这可能是正确的,但这在很大程度上取决于你的使用情况。
测试信息披露