MySQL 复制
MySQL 数据库有各种形状和大小,但最常见的是部署在网站的后端。随着网站的增长,其背后的公司通常会开始关注正常运行时间,并希望转向高可用性模型。不幸的是,到这个时候,选择通常会受到之前选择的数据和数据库引擎的限制。
在转向高可用性模型时,首先要做的决定实际上是是否要这样做。这似乎是显而易见的,但人们常常认为高可用性始终是一个好的选择。选择朝这个方向发展也意味着会给整个系统增加显著的复杂性。当部署集群解决方案时,服务器的数量会增加。因此,即使集群应用程序的总体停机时间减少,单个故障的数量也会增加。此外,随着可用性的提高,成本也会增加。为故障转移添加第二台服务器会使服务器的成本翻倍,而在其他地理位置添加故障转移集群可能会使整个数据中心的运营成本翻倍(或更多)。除此之外,转向 NDB 集群本身也会增加额外的硬件。
在考虑您需要的可用性级别之前,请先考虑停机成本与运行故障转移设施的运营成本相比如何。很少有设施需要在全球灭绝事件发生时继续运行,而为这种情况做计划将需要一个大型政府的预算。为跨国经济灾难造成的故障做计划更合理,但仍然需要一家大型跨国公司的预算。当为国家和地方性灾难做计划时,成本对于大多数公司来说变得更加合理。基于这个世界末日思想实验和大多数用户的需求,MySQL 高可用性开发主要集中在单地理位置集群上。
虽然您可以通过多种方式构建集群,使用块复制和 SAN 存储的组合,但官方的 MySQL 解决方案是复制和 NDB(网络数据库)集群。每种方法都有优点和缺点,您的选择不是基于 MySQL 中较新或较旧的开发,而是基于什么最适合您的应用程序。除了选择复制类型外,MySQL 的版本也至关重要。由于持续的软件开发,至少需要 5.1 版本才能使用此处描述的许多功能。如果您的当前数据库版本较低,强烈建议在实施这些解决方案之前升级数据库软件。5.0 版本的积极开发已于 2009 年 12 月结束,而 5.1 版本的积极开发将于 2010 年 12 月结束。
MySQL 复制在一对服务器之间建立主从或主主关系。这些服务器可以链接起来以构建由许多服务器组成的环形集合,或者一个主服务器可以用于许多从服务器,但关系本身仅存在于两者之间。单个 MySQL 服务器只能有一个主服务器。在引擎和功能的类型方面,复制比 NDB 更灵活。虽然 NDB 集群仅限于 NDB 表,但复制可以与几乎任何标准 MySQL 表类型一起使用,包括 MyIASM 和 InnoDB。
多主复制示例通常仅设置两台服务器,但可以使用环形集合中的任意数量的服务器来完成。要设置一个包含三台服务器的环形集合,my.cnf 配置文件的 [mysqld] 部分应包含以下内容
server-id=1 # This must be unique per server. auto_increment_offset=1 # Must be unique per server but less # than the auto_increment_increment # value below. auto_increment_increment=3 # Set to at least the maximum # number of servers in the circle
auto_increment_offset 值确定自增列的起始点,并且每个服务器必须是唯一的,但小于 auto_increment_increment 值。auto_increment_increment 值确定特定服务器上自增值之间的间隔。为了防止冲突,请将其设置为至少是环形集合中服务器的最大数量。
现在,要确定自增列中的下一个值,服务器将计数顺序中期望的下一个值乘以 auto_increment_increment 值,再加上 auto_increment_offset 值。如果 N 是序列中下一个期望的值(例如,1、2、3、4、5 等),则自增列的下一个值变为
N x auto_increment_increment + auto_increment_offset
此外,添加以下值
log_slave_updates:这告诉服务器将其主服务器的更新记录到自己的日志中,以便该机器可以同时充当主服务器和从服务器。
slave_exec_mode=IDEMPOTENT:此功能是严格可选的。它允许从服务器跳过错误。虽然它可以用来确保从服务器复制不会因错误而停止,但它也可能是危险的,因为它可能导致从服务器与主服务器失去同步,从而导致每台服务器上的数据集不同。使用 InnoDB 表以及事务和回滚可以帮助限制这种可能性。
一旦 my.cnf 文件设置好,每台服务器都需要授予复制用户复制访问权限,并设置为指向主数据库
server A mysql> GRANT REPLICATION CLIENT, REPLICATION SLAVE, SELECT, FILE, PROCESS, SUPER RELOAD ON *.* TO 'replication'@'%s' identified by 'replpass'; server A mysql> flush privileges; server A mysql> change master to MASTER_HOST="serverB.example.com", MASTER_USER="replication", MASTER_PASSWORD='replpass'; server A mysql> start slave; server B mysql> GRANT REPLICATION CLIENT ... ; (as above) server B mysql> flush privileges; server B mysql> change master to MASTER_HOST="serverC.example.com", MASTER_USER="replication", MASTER_PASSWORD='replpass'; server B mysql> start slave; server C mysql> GRANT REPLICATION CLIENT ... ; (as above) server C mysql> flush privileges; server C mysql> change master to MASTER_HOST="serverA.example.com", MASTER_USER="replication", MASTER_PASSWORD='replpass'; server C mysql> start slave;
在这种情况下,服务器 A 从服务器 B 获取数据,服务器 B 从服务器 C 获取数据,服务器 C 又从服务器 A 循环获取数据。数据可以插入到这三台服务器中的任何一台,并将复制到其他两台服务器。这不会加快写入速度(除了可能增加额外的驱动器主轴),但如果应用程序在集群中的服务器之间轮换,它可以提高读取速度。此外,如果发生硬件故障,集群的高可用性特性包含数据的副本。删除死从服务器可以像使用“change master”语句指向祖父服务器一样简单,或者更换死服务器并简单地复制数据的快照。
与松散耦合的多主复制相比,NDB 集群可以被视为一个单一实体。事实上,它们是如此紧密耦合,以至于 NDB 集群实体可以用作多主复制场景中的单个服务器。虽然 NDB 在集群同步性和管理方面具有巨大优势,但 NDB 引擎不支持其他 MySQL 引擎的所有功能,并且 NDB 引擎是唯一可以在 NDB 集群中使用的引擎。NDB 引擎不支持 MySQL 中的保存点,因此不支持事务和回滚。因此,当一个ALTER TABLE或CREATE TABLE命令发出时,不应访问正在更改的表。虽然它会锁定当前节点上的表,但这只是一个本地锁,如果从另一个节点访问该表,可能会导致数据完整性问题甚至崩溃。
在为 NDB 集群设置软件之前,硬件是一个需要考虑的问题。由于集群可以充当同步单元,并且包中没有内置加密,因此最佳实践是采用私有网络或 VLAN。如果目的是在 Web 应用程序中使用 NDB,则数据库间链接应与用于执行查询的链接分开。
NDB 集群中的网络可以通过多种不同的方式设置,但大多数用户更喜欢标准的 TCP over Gigabit 或更高速度的网络。100Mbit 网络可以工作,但对于较大的系统来说,效率会低得多。不支持 10Mbit 网络。虽然复制配置只需要 MySQL 服务器成为设置的一部分,但 NDB 除了 MySQL 服务器之外还需要管理节点和数据节点。所有这些都应表现出尽可能低的延迟。巨型帧在千兆网络上也是一个好主意,因为尽可能多地将数据放入数据包中可以减少任何类型的错误中断 NDB 节点之间同步数据传输的可能性。
除了网络之外,增加 RAM 也是必要的,因为缓存变得更加重要,以减少网络流量。增加磁盘 IO 的最佳方法是增加主轴。添加更多、更小的磁盘将提高任何给定节点的 IO 吞吐量,但这在数据节点上尤其重要,因为这些节点是在磁盘上实际拥有数据的节点。增加数据节点的数量也会提高整个集群的读取速度,但不会显着提高写入速度。如果数据库位于 Web 服务器后面,则读写比率通常非常高,这正是对应用程序有利的性能类型。如果应用程序的大多数查询都是写入数据,则专注于单个节点的速度是最佳策略。
在为 NDB 集群设置配置之前,请确保您的 MySQL 发行版中提供了它。show engines命令应包含引擎类型NDBCLUSTER,并且Support列设置为Yes。如果这不可用,请检查您的发行版是否有外部软件包,或者从 www.mysql.com 安装或编译社区软件包。
NDB 配置有三种类型的服务器。管理服务器通过 ndb_mgmd 守护程序执行集群的配置和监控。数据节点存储运行 ndbd 守护程序的数据,而 SQL 节点运行 mysqld 服务器本身。虽然可以在同一物理服务器上运行多种类型的守护程序,但在生产环境中不建议这样做。最佳实践是将所有守护程序都分离到它们自己的硬件上。
NDB 集群由两个配置文件组成。第一个文件 my.cnf 是 MySQL 的标准配置文件。第二个文件 config.ini 仅由管理服务器读取。config.ini 文件包含数据节点的配置,并由管理服务器传递给它们。
对 my.cnf 文件的添加非常简单
[ndb_mgm] ndb-connectstring=manage.example.com:1186 # The management server [ndb_mgmd] config-file=/etc/config.ini [ndbd] ndb-connectstring=manage.example.com:1186 # The management server [mysqld] ndbcluster # This turns the cluster on ndb-force-send=1 # Sends buffers immediately ndb-index-stat-enable=1 # Optimizes queries with NDB # index statistics engine-condition-pushdown=1 [mysql_cluster] ndb-connectstring=manage.example.com:1186 # The management server
Theengine-condition-pushdown选项强制 MySQL 将查询直接发送到存储引擎,而不是在 mysql 守护程序中评估它。在 NDB 集群中,这允许 NDB 引擎将查询分散到多个数据节点。
基本的 config.ini 文件也很容易编写。它必须放置在 my.cnf 文件中 config-file 行指定的位置
# Management Node [ndb_mgmd default] DataDir=/var/lib/mysql-cluster # This is where the management # server keeps data [ndb_mgmd] HostName=manage.example.com # The machine's hostname [ndbd default] NoOfReplicas=2 # There are 2 data nodes [ndbd] HostName=datanode.example.com # The machine's hostname [mysqld] HostName=datanode.example.com # The machine's hostname DataDir=/var/lib/mysql # This is where the data # node keeps data
在这种情况下,有三台服务器,每种类型一台:一台管理服务器、一个数据节点和一个 SQL 节点。查询被发送到 SQL 服务器,然后 SQL 服务器与数据节点互操作。由于 SQL 服务器可以使用 NDB 引擎内部的优化器(通过engine-condition-push变量设置)根据需要与多个数据节点通信,因此这种类型的复制在某些 SELECT 查询上的运行速度比上面讨论的多主复制设置快得多。另一方面,NDB 使用同步复制,因此写入数据的查询(例如 INSERT 和 UPDATE)可能会花费更长的时间,因为数据必须写入集群上的每个节点。
跨越不同位置扩展系统的问题在行业内是众所周知的。对于 Web 服务器和静态内容,这是一个相当简单的情况。对于可缓存的内容,可以使用各种缓存服务来完成。
在多个地理位置处理 MySQL 充其量是复杂的。在单独的数据中心中设置 NDB 集群是不合理的。即使集群中的服务器之间有专用带宽,链接上的延迟也会导致向系统发出写入命令时出现很大的延迟。
设置多地理位置 NDB 集群的公认方法是拥有两个独立的 NDB 集群(每个数据中心一个),并在两者之间设置异步多主(或仅用于故障转移的主从)复制系统。要做到这一点,请正常设置 NDB 集群,将 auto_increment 语句添加到 my.cnf 文件,添加复制用户权限,并在 MySQL 提示符下发出“change master”语句。
地理位置之间的这种异步关系将为跨系统分配负载创造一个很好的方式,但它仍然是异步的。在某些情况下,查询会从数据尚未完成复制的不同位置返回不同的结果。如果应用程序是一个显示照片的网站,这通常不是问题。如果应用程序是一家银行,这种不一致可能会导致大问题。
构建 MySQL 集群(无论是使用复制还是 NDB 集群)是一项很难在第一次就做对的任务。匆忙完成或在系统中使用现有数据会使它更加困难。设置几个系统作为测试实验室是必要的。虽然虚拟机是设置系统配置的良好平台,但为了验证应用程序不会因数据库性能不佳而受到影响,端到端性能测试也是必要的。这需要在实际硬件上使用实际数据,如果可能的话,还需要一个包含系统上运行的实际查询的文件。多地理位置设置在预算较小的情况下更加困难,最好认真考虑运行第二个位置的运营费用与停机成本相比如何。最后,无论您的复制和集群有多好,它们都不能替代备份。尽早保存;经常保存。
Michael Nugent 花费了大量时间设计大规模解决方案以适应微薄的预算,利用 Linux 来履行通常由大型商业设备履行的角色。最近,Michael 一直在为硅谷地区不断成长的初创公司设计大型多地理位置数据库解决方案。在不构建系统时,他喜欢航海、MIG 焊接和与他的猫 MIDI 一起玩。可以通过 michael@michaelnugent.org 联系到 Michael。