InnoDB-集群入门指南-一-

128 阅读1小时+

InnoDB 集群入门指南(一)

原文:Introducing InnoDB Cluster

协议:CC BY-NC-SA 4.0

一、高可用性简介

管理基础设施的数据库管理员和系统架构师了解在尽量减少维护工作量的同时构建冗余的必要性。用于实现这一点的工具之一是一类使服务器或服务尽可能可用的特性。我们称之为高可用性

高可用性不仅是建立健壮的、始终就绪的基础设施的关键因素,也是健壮的、企业级数据库系统的质量的关键因素。Oracle 一直在开发和改进 MySQL 中的高可用性特性。事实上,这些功能已经成熟,包括详细的管理和配置、状态报告,甚至主服务器的自动故障转移,以确保即使主服务器出现故障,您的数据仍然可用。最重要的是,Oracle 在 MySQL 的社区版中包含了这些特性,因此全世界都可以使用它们。

通过新的 InnoDB 集群特性实现的 MySQL 高可用性是建立在 MySQL 复制的长期稳定性基础上的组件集合。这些组件包括对服务器的修改和新组件,如组复制、用于路由连接的路由以及用于简化设置和配置的 MySQL Shell。这些组件共同构成了 MySQL 高可用性的新范例。

在本章中,您将了解什么是高可用性,以及如何通过使用 MySQL 高可用性功能组合的第一个构建块来实现高可用性。您还将看到一个关于如何使用 MySQL 复制的简短教程。了解如何通过使用 InnoDB Cluster 之前的可用特性在 MySQL 中实现高可用性,将有助于阐明 InnoDB Cluster 如何改进这些特性。

让我们从一个关于高可用性的简短教程开始。

MYSQL——这意味着什么?

名称 MySQL 是一个专有名称和一个缩写的组合。 SQL 代表结构化查询语言。我的部分不是所有格形式——它是一个名字。在这种情况下,我的是创始人女儿的名字。至于发音,MySQL 专家发音为“My-S-Q-L”而不是“my sequel”

什么是高可用性?

高可用性是最容易理解的,如果你认为它是可靠性的松散同义词——使解决方案尽可能易于使用,并在商定的时间内容忍计划内或计划外的故障。也就是说,这是用户对系统可操作性的期望值。系统越可靠,运行时间越长,就相当于可用性水平越高。

高可用性可以通过多种方式实现,从而产生不同级别的可用性。这些级别可以表示为达到某种更高可靠性状态的目标。本质上,您使用技术和工具来提高可靠性,并使解决方案尽可能长时间地保持运行和数据可用(也称为正常运行时间)。正常运行时间表示为解决方案运行时间的比率或百分比。

您可以通过实践以下工程原则来实现高可用性:

  • 消除单点故障:设计您的解决方案时,尽可能减少组件数量,以免在组件出现故障时导致解决方案无法使用。

  • 通过冗余增加恢复能力:设计您的解决方案,允许多个活动冗余机制,以便从故障中快速恢复。

  • 实施容错:设计您的解决方案,通过切换到冗余或替代机制,主动检测故障并自动恢复。

这些原则是实现更高级别的可靠性和高可用性的基础或步骤。即使您不需要实现最大的高可用性(解决方案几乎一直处于运行状态),通过实施这些原则,您至少会使您的解决方案更加可靠,这是一个很好的目标。

既然您已经理解了高可用性可以解决的目标或需求,那么让我们讨论一下在 MySQL 解决方案中实现高可用性的一些选项。以下部分讨论了实现高可用性目标的四个选项。通过实现所有这些,您将获得一定程度的高可用性。您的成就不仅取决于您如何实现这些选项,还取决于您满足可靠性目标的程度。

可靠性与高可用性:区别是什么?

可靠性是对解决方案随时间推移的可操作性的度量,涵盖了高可用性的主要目标之一。事实上,你可以说最终的可靠性水平——解决方案总是可操作的——是高可用性的定义。要使您的解决方案成为高可用性解决方案,您应该专注于提高可靠性。

恢复

最容易实现的可靠性是从故障中恢复的能力。这可能是组件、应用服务器、数据库服务器或解决方案的任何其他部分的故障。恢复因此,就是如何在尽可能短的时间内以尽可能低的成本让解决方案恢复运行。

但是,可能无法从所有类型的故障中恢复。例如,如果您的一台或多台服务器发生灾难性磁盘故障,恢复可能需要更换硬件,并且在停机期间会丢失数据。对于其他类型的故障,恢复选项可能允许更快地恢复运行。此外,有些组件更重要,必须是可恢复的,所以您应该努力保护那些更重要的组件,其中数据库是主要的。

例如,如果您的数据由于硬件故障而损坏或丢失,您需要一种尽可能少丢失数据的方法来恢复数据。实现这一点的一种方法是保留数据的频繁备份副本,以后可以恢复这些副本以防止数据丢失。

已经有许多关于备份和恢复数据的各种策略的书籍问世。我没有试图解释每一个细微差别、技术和最佳实践,而是向您推荐了许多可用的文本。对于本书和 MySQL 可用的解决方案,理解有两种类型的备份方法(逻辑和物理)就足够了,每种方法都有自己的优点。

逻辑备份

逻辑备份通过遍历数据、逐行复制数据以及通常将数据从二进制形式转换为 SQL 语句来复制数据。逻辑备份的优点是数据是可读的,甚至可以在恢复数据之前对其进行修改或更正。缺点是,对于大量数据,逻辑备份往往很慢,并且可能需要比实际数据更多的存储空间(取决于数据类型、索引数量等)。

物理备份

物理备份从磁盘存储层制作数据的二进制副本。备份通常是特定于应用的;您必须使用制作备份的同一应用来恢复它。这样做的好处是,备份速度更快,大小更小。此外,执行物理备份的应用具有一些高级功能,如增量备份(仅备份自上次备份以来发生变化的数据)和其他高级功能。对于小型解决方案,逻辑备份可能已经足够了,但是随着您的解决方案(您的数据)的增长,您将需要使用物理备份解决方案。

裁员

可靠性更具挑战性的实现之一是冗余——让两个或更多组件在系统中扮演相同的角色。冗余的目标可能只是在需要替换主要组件的情况下准备一个组件。这可能是一个热备用:该组件主动与主组件并行工作,当检测到故障时,您的系统会自动切换到冗余组件。冗余最常见的目标是数据库服务器。MySQL 在这方面有几个突出的特性。MySQL 中最古老的冗余特性之一叫做复制

对于最基本的用例,即热备用和备份,MySQL 复制并不难设置。为此,您设置了第二个数据库服务器,它可以获得在原始服务器上所做的所有更改的副本。原来的服务器叫做,或,第二个服务器叫做,或。MySQL 复制是一个非常大的主题,在本章的后面我将专门用一节来讨论它。

等等,为什么我们要讨论 MYSQL 复制?

您可能想知道为什么我们在讨论 MySQL 复制,而这本书是关于 InnoDB 集群的。理解 MySQL 复制非常重要,因为它是构建 InnoDB 集群的基础组件之一。尽管 MySQL 复制版本较旧,功能较少,并且需要手动管理,但是理解 MySQL 复制会让您更好地了解 InnoDB Cluster 的工作方式。它还将帮助您了解 InnoDB Cluster 与它所基于的组件相比有多复杂。

冗余也可以通过使用额外的专用硬件来实现。您可以实现冗余电源选项(例如,第二个电源或替代电源,如太阳能或备用电池),使用多个应用服务器,使用多个数据采集节点,等等。没有任何理由不能在您的解决方案中构建冗余。但是,只有您,即设计者或管理员,知道哪些节点是最关键的,因此知道在出现故障时您希望复制哪些节点。

冗余机制的复杂程度是你可以控制的,取决于你想投入多少。事实上,冗余的复杂程度与实现的工作量或费用有关。

例如,您可以使用一个备用的离线组件,当原始组件出现故障时,可以手动激活该组件,这是一个缓慢的过程,需要手动干预。或者,您可以使用备用的在线组件来代替主组件,主组件仍然需要手动干预,但恢复速度更快。或者您可以编写应用代码来自动检测故障,并切换到第二个,这是最好的(最快的),但需要更多的编程,因此需要更多的工作(可能要多得多)。

您可以调整冗余以满足您的需求或能力。您可以从简单的离线备件开始,并随着解决方案的发展增加更多的复杂性。

那么,五个九是多少?

你可能听说过或读过一个叫做“五个九”的概念,即一年 99.999%的正常运行时间。因此,五个九的解决方案每年最多只允许 5.26 分钟的停机时间。但是“五个九”只是可靠性的一个等级,还包括其他类别,每个类别都与正常运行时间或可靠性的百分比有关。有关可用类的更多信息,请参见 https://en.wikipedia.org/wiki/High_availability#Percentage_calculation

缩放比例

另一个可靠性实现与性能有关。在这种情况下,您希望最大限度地减少存储和检索数据的时间。MySQL 复制是实现可伸缩性的一种很好的方式。您可以通过设计解决方案将数据写入(保存)到主设备(主设备)并从从设备(辅助设备)读取数据来实现这一点。随着应用的增长,您可以添加从属服务器来帮助最小化读取数据的时间。拥有额外的从属服务器允许您的应用同时运行多个实例甚至多个连接(每个从属服务器至少一个)。因此,可伸缩性建立在 MySQL 的冗余特性之上。

通过拆分写和读,可以减轻主机执行许多语句的负担。考虑到大多数应用的读操作比写操作多得多,使用不同的服务器(或几个服务器)来提供读操作的数据并将写操作留给一个主服务器是有意义的。

理解横向扩展有两种形式很重要:读取和写入。您可以通过使用像 MySQL 复制中看到的冗余读取器来实现读取扩展,但是实现写入扩展需要一个可以在两台或更多服务器上协商和处理更新的解决方案。幸运的是,MySQL InnoDB Cluster 通过使用一种称为 MySQL 组复制的高级复制形式实现了这一点。您将在后面的章节中看到更多关于这个特性的内容。

当然,还有其他不需要实现 MySQL 复制就能提高性能的方法,但是从长远来看,您可能不会获得太多好处。

容错

可靠性的最后一个实现,实际上也是大多数高可用性解决方案在正常运行时间方面的区别在于容错,即检测故障并从事件中恢复的能力。容错是通过利用恢复和冗余以及添加检测机制和主动切换来实现的。

例如,您可以在数据库中实现容错。我们再次利用 MySQL 复制来实现切换。当主服务器关闭时,我们使用 MySQL 中的复制命令将主服务器的角色切换到一个从服务器。使用 MySQL 时,有两种类型的主角色改变:切换,即当主服务器仍在运行时,将主服务器的角色切换到从服务器,以及故障转移,即当主服务器不再运行时,选择从服务器来承担主服务器的角色。切换是有意的,而故障转移是被动的。

Oracle 提供了一些工具来帮助您设置自动故障转移。您可以使用 MySQL 实用程序(mysqlfailover)来监控您的主服务器,并在主服务器离线时切换到从服务器。对于包含许多服务器的大型解决方案,可能还需要写入扩展,您可以使用 MySQL 组复制,自动执行故障转移以及其他更复杂的高可用性操作。还有 MySQL 路由,它是 MySQL 的连接路由,允许您设置路由使用的一组特定服务器,以便路由在当前服务器离线(变得不可访问)时自动切换到另一台服务器。幸运的是,组复制和路由都是 InnoDB 集群的一部分。

您还可以在您的应用中实现某种形式的容错,但是像冗余一样,这需要专门的代码,构建和维护这些代码的成本可能会更高。甚至使用路由也可能需要修改您的应用,以使用某些端口和其他连接信息。然而,与在应用中编写自己的容错能力相比,这些都是小变化。

MYSQL 真的能达到高可用性吗?

您不仅可以使用 MySQL 实现高可用性,还可以使用 MySQL 实现高可用性,有些来自第三方供应商,还有 Oracle 的一些工具。甚至 MySQL 本身也是用高可用性的基本构件设计的。然而,MySQL 的特性以及用于高可用性的工具和解决方案允许您定制 MySQL 来提供您所需要的可靠性。

现在,您对什么是高可用性以及如何实现高可用性原则有了更广泛的理解,让我们来看看 MySQL 的高可用性特性。

MySQL 高可用性特性概述

MySQL 拥有高可用性特性已经有一段时间了。事实上,MySQL 复制在很多年前的 3.23.15 版本中首次引入,并经历了许多层的改进和完善。从那时起,MySQL 高可用性特性的组合已经扩展到涵盖许多用例,从简单的冗余(热备用),到横向扩展,再到高度可靠的系统。

以下是 MySQL 中主要高可用性特性的列表。包括与高可用性相关的每个功能的简要概述。在服务器和外部工具中,有许多小的改进、工具和增强来补充这些特性。例如,您可以使用 MySQL Enterprise Monitor(https://dev.mysql.com/doc/mysql-monitor/4.0/en/)来监控这些特性。

  • MySQL 复制:第一个高可用性特性,允许将数据从一个实例(服务器)复制到一个或多个额外的实例(服务器)。MySQL 复制中实现的主要高可用性特性包括冗余、热备用(恢复)、备份和读取可伸缩性。

  • MySQL 组复制:组复制建立在 MySQL 复制的基础上,提供了高级的服务器交互,允许更好的冗余,具有更好的同步、自动故障转移和写入可扩展性。因此,组复制比 MySQL 复制提供了更好的恢复和可靠性。

  • MySQL InnoDB Cluster:InnoDB Cluster 建立在 MySQL Group Replication 的基础上,通过应用编程接口(API)、应用故障转移和路由以及简化的配置,增加了额外的管理功能,便于利用新的客户端进行管理。因此,InnoDB 集群提供了比组复制更高的可用性。

  • MySQL NDB 集群:经常与 InnoDB 集群混淆,NDB 集群是一款独立于 Oracle 的产品,它提供了一个适用于分布式计算环境的高可用性、高冗余版本的 MySQL,使用内存中的 NDB 存储引擎(也称为 NDB Cluster)在一个集群中运行多台装有 MySQL 服务器和其他软件的计算机。

如您所见,MySQL 中的高可用性特性令人印象深刻。虽然这个清单并不长,但这些特性的重要性是不可低估的。许多组织已经使用 MySQL 复制和 NDB 集群很多年了。组复制和后来的 InnoDB 集群的加入证明了 Oracle 对 MySQL 服务器中企业级高可用性的承诺。

注意

NDB 集群仅作为 MySQL NDB 集群分发版的一部分提供。有关 MySQL NDB 集群的更多信息,请参见 https://dev.mysql.com/doc/refman/5.7/en/mysql-cluster.html

为了充分理解使用 InnoDB Cluster 的重要性和改进收益,我们从 MySQL 复制入门开始。您将在第 2 章了解更多关于 InnoDB 集群的信息,并在第 3 章了解组复制。

MySQL 复制入门

MySQL 复制是一个易于使用的特性,也是 MySQL 服务器的一个复杂和主要的组件。本节提供了复制的鸟瞰图,以解释它是如何工作的以及如何设置一个简单的复制拓扑。 1 虽然本节讨论的是 8.0 版本下的 MySQL 复制,但是在 MySQL 的早期版本中,MySQL 复制的配置方式是相同的。本节中显示的设置和配置复制的步骤可以用于 MySQL 的旧版本。如前所述,了解 MySQL 复制的工作原理将让您更好地了解 InnoDB 集群的工作原理。

复制需要两台或更多服务器。一台服务器必须被指定为源服务器或主服务器(称为主服务器)。主角色意味着对数据的所有数据更改(写入)都发送到主服务器,并且只发送到主服务器。拓扑中的所有其他服务器维护主数据的副本,并且根据设计和要求是只读服务器(称为从服务器)。因此,当你的应用存储或更新数据时,它们会将数据发送给主程序。您编写的使用数据的应用可以从从属服务器读取数据。

注意

术语专门用于 MySQL 复制,代表只有一个服务器可以被写入,因此拥有副本。其余的服务器是只读的,包含数据的副本。在后来的高可用性特性中,这些术语被更改为辅助,以便更好地描述新特性中的角色。

MySQL 复制支持两种复制方法。最初的(有时称为 MySQL 5.7 复制经典复制二进制日志文件复制,或日志文件和位置复制)方法涉及使用二进制日志文件名称和位置来执行事件或应用更改,以在主服务器和从服务器之间同步数据。使用全局事务标识符(GTIDs)的新方法是事务性的,因此不需要处理日志文件或这些文件中的位置,这大大简化了许多常见的复制任务。使用 GTIDs 的复制保证了主设备和从设备之间的一致性。

什么是 GTID?

GTIDs 使服务器能够为每个事件集或组分配一个唯一的标识符,从而可以知道每个从服务器上应用了哪些事件。要使用 GTIDs 执行故障转移,您可以选择最好的从设备(丢失事件最少且硬件与主设备最匹配的设备),并使其成为所有其他从设备的从设备。我们称这个从设备为候选从设备。GTID 机制将确保只应用那些没有在候选从设备上执行的事件。通过这种方式,候选从模块成为最新的,因此成为主模块的替代。

复制机制通过使用一种称为二进制日志的技术来工作,该技术以一种特殊的格式存储更改,从而保留所有更改的记录。然后,这些更改被复制到从属服务器,并在那里重新执行。在从机重新执行更改(称为事件)后,从机拥有数据的精确副本。我们将在后面的章节中看到更多关于二进制日志的内容。

主设备维护一个二进制日志,从设备维护该二进制日志的副本,称为中继日志,其格式与二进制日志相同。当从设备向主设备请求数据更改时,它从主设备读取事件并将它们写入其中继日志;然后,从属线程中的另一个线程执行中继日志中的那些事件。

在最低级别,主设备和从设备之间的二进制日志交换支持三种格式:

  • 基于语句的复制(SBR) :复制整个 SQL 语句

  • 基于行的复制(RBR) :仅复制已更改的行

  • 基于混合的复制(MBR):RBR 的混合体,使用 SQL 语句记录一些事件

可以想象,从主服务器上发生更改到从服务器上发生更改之间会有一点延迟。幸运的是,除了在高流量(大量变化)的拓扑中,这种延迟几乎是不明显的。出于您的目的,当您从从属服务器读取数据时,它可能是最新的。您可以使用命令SHOW SLAVE STATUS来检查从设备的进度;在许多其他事情中,它向你展示了奴隶已经落后于主人有多远。在后面的部分中,您将看到这个命令的运行。

MySQL 复制还支持两种类型的同步。最初的类型异步是单向的:在主服务器上执行的事件被传输到从服务器,并在它们到达时执行(或应用),没有检查来确保从服务器与主服务器都处于相同的同步点(当有许多事务时,从服务器的更新可能会延迟)。另一种类型是半同步:在主设备上执行的提交在返回到执行事务的会话之前被阻塞,直到至少一个从设备确认它已经接收并记录了事务的事件。

MySQL NDB 集群支持同步复制,在这种情况下,所有节点在全有或全无的提交场景中保证拥有相同的数据。有关同步复制的信息,请参见在线参考手册中的 MySQL NDB 集群部分。

小费

有关 MySQL 复制的更多信息,请参见在线参考手册中的“复制”部分( https://dev.mysql.com/doc/refman/8.0/en/replication.html )。

现在您已经对复制及其工作原理有了一些了解,让我们来看看如何设置它。下一节讨论如何设置复制,将一台服务器作为主服务器,另一台作为从服务器。您将看到两种类型的复制都被使用。正如您将看到的,在配置服务器和启动复制的方式上只有一些差异。

MySQL 复制教程

本节演示如何设置从一台服务器(主服务器)到另一台服务器(从服务器)的复制。这些步骤包括通过启用二进制日志记录和创建用于读取二进制日志的用户帐户来准备主服务器,通过将从服务器连接到主服务器来准备从服务器,以及启动从服务器进程。这一部分以对复制系统的测试结束。

如果您想自己体验本教程,您应该准备两台服务器——两台物理机或两台虚拟机。然而,试验 MySQL 复制最简单的方法是在一个测试系统上设置两个 MySQL 实例。更具体地说,您将看到如何在同一台机器上运行多个 MySQL 服务器。为此,您应该已经在系统上安装了 MySQL。如果您的系统上没有安装 MySQL,您可以按照在线参考手册( https://dev.mysql.com/doc/refman/8.0/en/installing.html )中的说明进行操作。在下一章中,你会看到关于安装 MySQL 8.0 的更深入的演示。

注意

使用二进制日志文件和位置设置复制的步骤与使用 GTIDs 的步骤相同,但是在某些步骤中命令略有不同。本教程展示了这两种方法。

设置和配置 MySQL 复制的步骤包括:

  1. 初始化数据目录。

  2. 配置主服务器。

  3. 配置从机。

  4. 启动 MySQL 实例。

  5. 创建复制用户帐户。

  6. 将从设备连接到主设备。

  7. 开始复制。

  8. 验证复制状态。

可能还有其他同样可行的步骤来设置复制,但是前面的步骤可以在任何机器上完成,并且不会影响 MySQL 的任何现有安装。也就是说,建议在开发机器上执行这些步骤,以消除中断生产系统的风险。

以下部分将更详细地演示这些步骤。虽然本教程使用多个本地实例来演示如何使用复制,但是在生产环境中设置复制的过程是相同的。使用特定主机、驱动器、文件夹、端口等的各个命令的详细信息是在生产中使用该过程时唯一需要更改的内容。

注意

本教程中的步骤是在 Ubuntu 16.04 平台上运行的。尽管有特定于平台的命令和一些特定于平台的选项,但本教程只需稍加修改就可以在 macOS 和 Windows 平台上运行。

初始化数据目录

第一步是为使用的每台机器初始化一个数据目录。在这种情况下,我们将在本地计算机上创建一个文件夹来包含所有数据目录。我们将使用 MySQL 的两个实例来表示一个主服务器和一个从服务器。下面演示了如何创建所需的文件夹。请注意,我在我使用的用户帐户可以访问的本地文件夹中创建这些文件,而不是系统或管理帐户。这是因为我们将在本地运行实例,不需要额外的权限或访问此类帐户的许可。

$ mkdir rpl
$ cd rpl
$ mkdir data

现在我们有了一个文件夹<user_home>/rpl/data,我们可以使用 MySQL 服务器的初始化选项来设置我们的数据目录。 3 我们通过使用服务器可执行文件的特殊--initialize-insecure--datadir选项来做到这一点。--initialize-insecure选项告诉服务器创建数据目录并用系统数据填充它,但是跳过任何身份验证的使用。这是安全的,因为还没有创建用户(没有数据目录!).

--datadir选项指定数据目录主文件夹的位置。因为我们是作为本地用户运行的,所以我们需要--user选项。我们还需要知道安装在本地机器上的 MySQL 服务器的基目录(名为basedir)。您可以从服务器配置文件中获取这些信息,或者使用 MySQL 客户端(名为mysql)并向其传递一个 show 命令。下面演示了如何做到这一点。在这里,我们看到的基本目录是/usr/。我们将使用这个值,这样mysqld可执行文件就可以找到它所依赖的库和文件。

$ mysql -uroot -proot -e "SHOW VARIABLES LIKE 'basedir'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| basedir
       | /usr/ |
+---------------+-------+

最后,我们使用--no-defaults选项(它必须首先出现在参数列表中)跳过对 MySQL 配置文件的读取。如果我们已经在机器上运行了一个 MySQL 实例,或者机器上已经安装了 MySQL,那么这是必要的。

下面显示了初始化主机和从机的数据目录所需的命令。注意,我用slave1来表示奴隶。这样,如果您想尝试添加额外的从属对象,就可以将教程扩展到多个从属对象。

mysqld --no-default --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/rpl/data/master
mysqld --no-default --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/rpl/data/slave1

注意

您可以很容易地扩展本教程,使用两个或更多的奴隶。只需对从机重复这些命令,替换正确的端口。

当您运行这些命令时,您将看到如下几条消息。您可以放心地忽略这些警告,但是请注意,最后一个警告告诉我们没有为 root 用户分配密码。这对于我们的教程来说是可以的,但是对于生产安装来说,您绝对不希望这样做。幸运的是,在启动实例后,我们可以很容易地修复这个问题。

$ mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/usr/ --datadir=/home/cbell/rpl/data/master
2018-03-05T16:44:44.746906Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2018-03-05T16:44:44.948910Z 0 [Warning] InnoDB: New log files created, LSN=45790
2018-03-05T16:44:45.027466Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2018-03-05T16:44:45.096708Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 82783ccc-2094-11e8-b3e3-10bf4850c554.
2018-03-05T16:44:45.100255Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2018-03-05T16:44:45.101415Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.

现在我们已经创建并填充了数据目录,我们可以配置主服务器和从服务器了。

配置主服务器

复制要求主服务器启用二进制日志记录。在 MySQL 8.0.11 中它是默认打开的,但是如果您有一个旧版本,您必须在配置文件中添加这个选项。事实上,我们需要为每个想要启动的实例配置一个配置文件。在这一节中,我们集中讨论主设备,在下一节中,我们将看到从设备的配置文件。

我们还需要为实例选择端口。对于本教程,我们将使用从 13001 开始的主端口号和 13002+开始的从端口号。此外,我们需要选择唯一的服务器标识号。我们将用 1 代表主设备,用 2+代表从设备。

我们还需要做一些其他的设置。与其列出它们,不如让我们来看一个典型的主服务器的基本配置文件,它使用带有二进制日志和文件位置的复制。清单 1-1 显示了我们将在本教程中用于主服务器的配置文件。

[mysqld]
datadir="/home/cbell/rpl/data/master"
basedir="/usr/"
port=13001
socket="/home/cbell/rpl/master.sock"

server_id=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=master_binlog
binlog_format=row

Listing 1-1Master Configuration File (Log File and Position)

注意,配置文件有一个名为mysqld的部分,它只适用于 MySQL 服务器可执行文件。只有mysqld和相关的可执行文件会读取这个部分的值。这些值包括datadirbasedirportsocket(适用于*nix 风格平台)的常用必需设置。请注意,这些值与我们之前讨论过的设置相匹配。

下一节设置服务器 ID,打开用于存储复制信息的TABLE选项,这使得复制可以从崩溃中恢复,并打开二进制日志并设置其位置。最后,我们对二进制日志使用ROW格式,这是一种二进制格式,是 MySQL 复制最新版本的默认格式。

如果我们想使用基于 GTID 的复制,必须设置附加选项。对于主服务器,只有三个:打开 GTIDs、设置一致性强制和记录从服务器更新。清单 1-2 中显示了启用 GTID 的主服务器的配置文件。请注意,文件的第一部分与前面的示例相同。只添加最后几行来启用 GTIDs。

[mysqld]
datadir="/home/cbell/rpl/data/master"
basedir="/usr/"
port=13001
socket="/home/cbell/rpl/master.sock"

server_id=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=master_binlog
binlog_format=row

# GTID VARIABLES
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=on

Listing 1-2Master Configuration File (GTIDs)

对于本教程,我们将使用支持 GTID 的复制,所以您应该在我们之前创建的文件夹中创建一个名为master.cnf的文件;比如/home/cbell/rpl/master.cnf。在后面的步骤中,我们将使用该文件启动主服务器的实例。

小费

如果配置文件是全球可读的,一些平台可能无法启动 MySQL。如果您的服务器没有启动,请检查日志中有关文件权限的消息。

现在,让我们来看看从属服务器的配置文件。

配置从机

日志文件和位置复制要求主服务器启用二进制日志记录,而从服务器则不需要。但是,如果您想使用从属服务器来生成备份或进行崩溃恢复,那么打开从属服务器的二进制日志是一个好主意。如果您想使用支持 GTID 的复制,也需要二进制日志记录。在本节中,我们将在从属服务器上使用二进制日志记录。

正如我们为 master 所做的那样,我们需要设置几个变量,包括datadirbasedirportsocket(对于*nix 风格的平台)。清单 1-3 显示了第一个从机(名为slave1)的配置文件。

[mysqld]
datadir="/home/cbell/rpl/data/slave1"
basedir="/usr/"
port=13002
socket="/home/cbell/rpl/slave1.sock"

server_id=2
master_info_repository=TABLE
relay_log_info_repository=TABLE

log_bin=slave1_binlog
binlog_format=row
report-port=13002
report-host=localhost

Listing 1-3Slave Configuration File (Log File and Position)

注意,设置了两个额外的变量:report-portreport-host。这些对于确保像SHOW SLAVE HOSTS这样的命令报告正确的信息是必要的;该视图的信息来自这些变量。因此,正确设置它们总是一个好主意。

还要注意,我们将数据目录设置为一个为这个从服务器留出的目录,服务器 ID 也发生了变化。最后,我们还更改了二进制日志的名称,以确保我们知道日志来自哪个服务器(如果将来需要的话)。

如果我们想要使用基于 GTID 的复制,我们将添加与主服务器相同的一组变量,如清单 1-4 所示。

[mysqld]
datadir="/home/cbell/rpl/data/slave1"
basedir="/usr/"
port=13002
socket="/home/cbell/rpl/slave1.sock"

server_id=2
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=slave1_binlog
binlog_format=row
report-port=13002
report-host=localhost

# GTID VARIABLES
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=on

Listing 1-4Slave Configuration File (GTIDs)

对于本教程,我们将使用支持 GTID 的复制,所以您应该在我们之前创建的文件夹中创建一个名为slave1.cnf的文件;比如/home/cbell/rpl/slave1.cnf。如果您想添加更多的从服务器,可以使用相同的数据创建额外的配置文件,只需更改数据目录、套接字、端口、服务器 ID 和二进制日志文件。

启动 MySQL 实例

现在我们已经准备好启动 MySQL 实例了。这很容易做到,因为我们已经用我们需要的所有参数创建了配置文件。我们需要提供只带有--defaults-file选项的配置文件。下面显示了启动两个服务器实例的命令:

mysqld --defaults-file=master.cnf
mysqld --defaults-file=slave1.cnf

运行这些命令时,应该从包含配置文件的文件夹中运行它们。否则,您必须提供配置文件的完整路径。使用单独的终端窗口启动每个实例或者将输出(消息记录)重定向到一个文件也是一个好主意,如清单 1-5 所示。但是,您可能希望在第一次启动服务器时使用单独的终端,以确保不会出现错误。清单 1-5 显示了启动主程序时打印的信息摘录。

$ mysqld --defaults-file=master.cnf
2018-03-05T18:45:18.544588Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2018-03-05T18:45:18.545466Z 0 [Note] mysqld (mysqld 5.7.21-0ubuntu0.16.04.1-log) starting as process 8477 ...
...
2018-03-05T18:45:18.697423Z 0 [Note] Server hostname (bind-address): '*'; port: 13001
2018-03-05T18:45:18.697500Z 0 [Note] IPv6 is available.
2018-03-05T18:45:18.697523Z 0 [Note]   - '::' resolves to '::';
2018-03-05T18:45:18.697569Z 0 [Note] Server socket created on IP: '::'.
2018-03-05T18:45:18.735880Z 0 [Note] Event Scheduler: Loaded 0 events
2018-03-05T18:45:18.736092Z 0 [Note] mysqld: ready for connections.
Version: '5.7.21-0ubuntu0.16.04.1-log'  socket: '/home/cbell/rpl/master.sock'port: 13001  (Ubuntu)

Listing 1-5Starting the Master Instance

如果您计划使用单个终端,建议将输出重定向到名为master_log.txt的文件,并使用选项在另一个进程中启动应用(例如,&符号)。服务器生成消息时会更新日志文件,因此如果遇到问题,您可以参考这些日志文件。这也有助于保持您的终端会话清除额外的消息。下面显示了如何构建上述命令,使其作为单独的进程启动,并将消息记录到文件中:

$ mysqld --defaults-file=master.cnf > master_output.txt 2>&1 &

如果您还没有这样做,请继续启动从属服务器。以下是我用来启动从机的命令(slave1):

$ mysqld --defaults-file=slave1.cnf > slave1_output.txt 2>&1 &

创建复制用户帐户

MySQL 实例启动后,您必须创建一个用户,供从属服务器连接到主服务器并读取二进制日志,然后才能设置复制。这个有一个特殊的特权叫做REPLICATION SLAVE。下面显示了创建用户和添加权限的正确的GRANT语句。记住您在这里使用的用户名和密码,因为您将需要它来连接从设备。

下面显示了创建复制用户所需的命令。在所有服务器上执行这些命令。尽管从属服务器不需要用户,但现在创建用户将允许您使用从属服务器进行恢复、切换或故障转移,而无需创建用户。事实上,这一步是允许自动故障转移所必需的。

SET SQL_LOG_BIN=0;
CREATE USER rpl_user@'localhost' IDENTIFIED BY 'rpl_pass';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'localhost';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;

请注意第一个和最后一个命令。这些命令告诉服务器暂时禁止记录二进制日志的更改。每当我们不想在拓扑中的其他机器上复制命令时,我们就这样做。具体来说,不应复制维护和管理命令,如创建用户。关闭二进制日志是确保您不会意外发出无法在其他机器上执行的事务的好方法。

执行这些命令的最佳方式是将它们保存到名为create_rpl_user.sql的文件中,并使用mysql客户端的源命令从文件中读取命令并执行它们。您可以使用以下命令在所有实例上快速创建复制用户:

mysql -uroot -h 127.0.0.1 -e "source /home/cbell/rpl/create_rpl_user.sql" --port=13001
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/rpl/create_rpl_user.sql" --port=13002

现在,我们准备将从设备连接到主设备,并开始复制数据。

将从设备连接到主设备

下一步是将从设备连接到主设备。根据您使用的复制形式,有多种方法可以做到这一点。具体来说,与 GTID 复制相比,使用日志文件和位置时,将从设备连接到主设备的命令是不同的。还有两个步骤:配置从机进行连接和开始复制。让我们先来看看用日志文件和位置配置从属服务器。

连接日志文件并定位

要使用日志文件和位置将从设备连接到主设备,我们需要一些信息。完成指示从机与主机建立连接的CHANGE MASTER命令需要这些信息。表 1-1 显示了所需信息的完整列表。该表包括信息的来源之一,以及本教程中使用的值的示例。

表 1-1

连接从属设备所需的信息(日志文件和位置)

|

主文件中的项目

|

来源

|

例子

| | --- | --- | --- | | IP 地址或主机名 | master.cnf | 本地主机 | | 港口 | master.cnf | Thirteen thousand and one | | 二进制日志文件 | 显示主状态 | master_binlog.000002 | | 二进制日志文件位置 | 显示主状态 | One hundred and fifty-four | | 复制用户 ID | 创建一个用户 | rpl _ 用户 | | 复制用户密码 | 创建一个用户 | rpl_pass |

主二进制日志文件的信息可以通过SHOW MASTER STATUS命令找到。下面展示了如何使用mysql客户端执行命令并返回:

$ mysql -uroot -h 127.0.0.1 --port=13001 -e "SHOW MASTER STATUS\G"
*************************** 1\. row ***************************
             File: master_binlog.000002
         Position: 154
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:

请注意,该命令还显示任何活动的过滤器以及最新执行的 GTID 集的特定于 GTID 的值。在本教程中我们不需要它,但是如果您需要恢复启用了 GTID 的拓扑,将它归档是一个好主意。

小费

对于宽结果,使用\G选项将列视为行(称为垂直格式)。

现在您已经有了主服务器的二进制日志文件名和位置以及复制用户和密码,您可以访问您的从服务器并使用CHANGE MASTER命令将其连接到主服务器。该命令可以由表 1-1 中的信息构成,如下所示(格式化以使其更容易阅读——如果你按照本教程进行,请删除\):

CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="rpl_pass", \
    MASTER_HOST='localhost', MASTER_PORT=13001, \
    MASTER_LOG_FILE='master_binlog.000002', MASTER_LOG_POS=154;

您必须在所有从属服务器上运行该命令。将它保存到一个文件并使用mysql客户机执行它可能更容易,就像我们对复制用户所做的那样。例如,将它保存到一个名为change_master.sql的文件中,并如下所示执行它:

mysql -uroot -h 127.0.0.1 -e "source /home/cbell/rpl/change_master.sql" --port=13002

启动从服务器还需要一个步骤,但是让我们首先看看如何为启用 GTID 的复制配置CHANGE MASTER命令。

用 GTIDs 连接

要使用 GTIDs 将从设备连接到主设备,我们需要一些信息。完成指示从机与主机建立连接的CHANGE MASTER命令需要这些信息。表 1-2 显示了所需信息的完整列表。该表包括信息的来源之一,以及本教程中使用的值的示例。

表 1-2

连接从机所需的信息(GTIDs)

|

主文件中的项目

|

来源

|

例子

| | --- | --- | --- | | IP 地址或主机名 | master.cnf | 本地主机 | | 港口 | master.cnf | Thirteen thousand and one | | 复制用户 ID | 创建一个用户 | rpl _ 用户 | | 复制用户密码 | 创建一个用户 | rpl_pass |

请注意,我们需要的信息比日志文件和位置复制少。我们不需要知道主二进制日志文件或位置,因为 GTID 握手过程将为我们解析该信息。我们需要的只是主服务器和复制用户的主机连接信息和密码。对于启用 GTID 的复制,我们使用一个特殊的参数MASTER_AUTO_POSITION,来指示复制自动协商连接信息。可以从表 1-2 中的信息构造CHANGE MASTER命令,如下所示(格式化以使其更容易阅读——如果您跟随本教程,请删除\):

CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="rpl_pass", \
    MASTER_HOST='localhost', MASTER_PORT=13001, MASTER_AUTO_POSITION = 1;

您必须在所有从属服务器上运行该命令。将它保存到一个文件并使用mysql客户机执行它可能更容易,就像我们对复制用户所做的那样。例如,将它保存到一个名为change_master.sql的文件中,并如下所示执行它:

mysql -uroot -h 127.0.0.1 -e "source /home/cbell/rpl/change_master.sql" --port=13002

如果您希望能够将该文件用于任何一种形式的复制,您可以简单地将这两个命令放在文件中,并注释掉一个您不需要的命令。例如,下面显示了带有两个CHANGE MASTER命令的示例文件。请注意,GTID 变体是用#符号注释掉的:

CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="rpl_pass", MASTER_HOST="localhost", MASTER_PORT=13001, MASTER_LOG_FILE='master_binlog.000001', MASTER_LOG_POS=150;
# GTID option:
# CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="rpl_pass", MASTER_HOST="localhost", MASTER_PORT=13001, MASTER_AUTO_POSITION = 1;

既然我们已经配置了从属设备进行连接,我们必须通过告诉从属设备启动连接并开始复制来完成这个过程。

开始复制

下一步是启动从属进程。这个命令简单来说就是START SLAVE。我们将在所有从机上运行这个命令,就像我们对CHANGE MASTER命令所做的那样。下面显示了启动从机的命令:

mysql -uroot -h 127.0.0.1 -e "START SLAVE" --port=13002

START SLAVE命令通常不报告任何错误;您必须使用SHOW SLAVE STATUS才能看到它们。清单 1-6 展示了该命令的实际应用。为了安全和放心,您可能希望在您启动的任何从属服务器上运行这个命令。

$ mysql -uroot -h 127.0.0.1 -e "SHOW SLAVE STATUS \G" --port=13002
*************************** 1\. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: localhost
                  Master_User: rpl_user
                  Master_Port: 13001
                Connect_Retry: 60
              Master_Log_File: master_binlog.000002
          Read_Master_Log_Pos: 154
               Relay_Log_File: oracle-pc-relay-bin.000002
                Relay_Log_Pos: 375
        Relay_Master_Log_File: master_binlog.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 586
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0

               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: 82783ccc-2094-11e8-b3e3-10bf4850c554
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:

Listing 1-6Checking SLAVE STATUS

花点时间费力地读完所有这些行。你需要注意几个关键领域。这些包括名称中带有error的任何内容,以及 state 列。例如,第一行(Slave_IO_State)显示了指示从机 I/O 线程状态的文本消息。I/O 线程负责从主服务器的二进制日志中读取事件。还有一个 SQL 线程负责从中继日志中读取事件并执行它们。

对于这个例子,您只需要确保两个线程都在运行(YES)并且没有错误。关于SHOW SLAVE STATUS命令中所有字段的详细解释,请参见在线 MySQL 参考手册“用于控制从服务器的 SQL 语句”( https://dev.mysql.com/doc/refman/5.7/en/replication-slave-sql.html )一节。

既然从服务器已经连接并正在运行,让我们通过检查主服务器并创建一些数据来检查复制。

验证复制状态

使用SHOW SLAVE STATUS命令检查从属状态是验证复制健康的第一步。下一步是使用SHOW SLAVE HOSTS命令检查主机。清单 1-7 显示了本教程中拓扑设置的SHOW SLAVE HOSTS的输出。该命令显示连接到主设备的从设备及其 UUIDs。需要注意的是,这些信息是一个视图,不是实时的。从属连接可能会失败,但仍会显示在报告中,直到进程超时,服务器终止它们。因此,这个命令最好用作健全性检查。

$ mysql -uroot -h 127.0.0.1 -e "SHOW SLAVE HOSTS \G" --port=13001
*************************** 1\. row ***************************
 Server_id: 2
      Host: localhost
      Port: 13002
 Master_id: 1
Slave_UUID: 7e71cad7-20a6-11e8-a12b-10bf4850c554

Listing 1-7SHOW SLAVE HOSTS Command (Master)

这里我们看到从机已连接,从上一部分我们知道从机状态良好。

接下来,让我们在主服务器上创建一些简单的数据,然后看看这些数据是否被复制到从服务器上。在这种情况下,我们将创建一个数据库、一个表和一个单独的行,然后在主服务器上运行。清单 1-8 显示了在主机上执行的样本数据。

$ mysql -uroot -h 127.0.0.1 --port=13001
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 8.0.11 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.01 sec)

mysql> USE test;
Database changed
mysql> CREATE TABLE test.t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO test.t1 VALUES (1, 'Chuck');
Query OK, 1 row affected (0.03 sec)

Listing 1-8Creating Sample Data for Testing Replication (Master)

为了验证数据是否被复制,我们需要做的就是在一个从服务器(或者所有从服务器,如果您愿意的话)的表上发出一个SELECT SQL 命令。下面显示了我们期望在每个从机上看到的示例:

$ mysql -uroot -h 127.0.0.1 --port=13002 -e "SELECT * FROM test.t1"
+----+-------+
| c1 | c2    |
+----+-------+
|  1 | Chuck |
+----+-------+

关于设置 MySQL 复制的简短教程到此结束。本节用最简洁的术语简要介绍了 MySQL 复制。现在,让我们看看如何编写 MySQL 复制的示例设置。

MySQL 复制脚本示例

如果您从事系统工作已经有一段时间了,那么几乎可以肯定的是,您将任何重复的操作视为编写脚本的机会,以使该过程更容易、更快地重复。正如我们在教程中所做的,在测试环境中设置 MySQL 复制是自动化成为可能的一个很好的例子。我们将在本节中探索一个示例脚本。

虽然有许多方法可以编写脚本来自动化复制环境,但让我们保持简单,将所有配置文件和数据目录放在用户帐户的单个文件夹中。例如,如果我们使用 Linux,我们可以创建一个名为rpl的文件夹,并在该文件夹中创建一个名为data的文件夹,其中包含实例的数据目录。下面显示了这可能是什么样子:

/home/cbell/rpl
                |
                +---/data
                      |
                      +---/master
                      |
                      +---/slave1
                      |
                      +---/slave2
                      |
                      +---/slave3

我们还放置配置文件、自动化脚本和任何包含用于命令的数据的附加文件,等等。例如,我们的文件夹内容可能如下所示(在开始复制之前):

/home/<user>/rpl $ ls
change_master.sql  create_rpl_user.sql  sample_data.sql  shutdown.sh  slave2.cnf
check_rpl.sql      master.cnf           setup.sh         slave1.cnf   slave3.cnf

清单 1-9 展示了一个可以用来在典型的 Linux 平台上启动复制的脚本。正如您将看到的,该脚本使用了几个附加文件,如教程中提到的.sql文件。要使用这个脚本,只需按照前面教程中的说明创建这些文件。您还需要更改路径以匹配您的系统。脚本文件被命名为setup.sh,但是您可以随意命名。

#
#!/bin/bash
#
# Introducing MySQL InnoDB Cluster - Chapter 1 : Setup Replication (Linux)
#
...
#
# Dr. Charles Bell, 2018
#
BIN='/usr/sbin'
BASEDIR='/usr/'
DATADIR='/home/<user>/rpl'
echo
echo Introduction to MySQL InnoDB Cluster - Ch01 : Setup MySQL Replication
echo
echo ====== Step 1 of 6: INITIALIZE DATA DIRECTORIES ======
echo "> Creating data directory root ..."
cd "$DATADIR"
rm -rf "$DATADIR/data"
mkdir "$DATADIR/data"
echo "> Initializing the master ..."
echo
$BIN/mysqld --no-defaults --user=<user> --initialize-insecure --basedir=$BASEDIR --datadir="$DATADIR/data/master"

echo
echo "> Initializing slave1 ..."
echo
$BIN/mysqld --no-defaults --user=<user> --initialize-insecure --basedir=$BASEDIR --datadir="$DATADIR/data/slave1"
echo
echo "> Initializing slave2 ..."
echo
$BIN/mysqld --no-defaults --user=<user> --initialize-insecure --basedir=$BASEDIR --datadir="$DATADIR/data/slave2"
echo
echo "> Initializing slave3 ..."
echo
$BIN/mysqld --no-defaults --user=<user> --initialize-insecure --basedir=$BASEDIR --datadir="$DATADIR/data/slave3"
echo
echo ====== Step 2 of 6: START ALL INSTANCES ======
echo "> Removing old socket file ..."
cd $DATADIR
rm *.sock*
echo "> Starting master ..."
$BIN/mysqld --defaults-file="$DATADIR/master.cnf" > master_output.txt 2>&1 &
echo "> Starting slave1 ..."
$BIN/mysqld --defaults-file="$DATADIR/slave1.cnf" > slave1_output.txt 2>&1 &
echo "> Starting slave2 ..."
$BIN/mysqld --defaults-file="$DATADIR/slave2.cnf" > slave2_output.txt 2>&1 &
echo "> Starting slave3 ..."
$BIN/mysqld --defaults-file="$DATADIR/slave3.cnf" > slave3_output.txt 2>&1 &
sleep 5
echo
echo ====== Step 3 of 6: CREATE THE REPLICATION USER ======
echo "> Creating replication user on the master ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/create_rpl_user.sql" --port=13001
echo "> Creating replication user on slave1 ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/create_rpl_user.sql" --port=13002
echo "> Creating replication user on slave2 ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/create_rpl_user.sql" --port=13003
echo "> Creating replication user on slave3 ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/create_rpl_user.sql" --port=13004
echo
echo ====== Step 4 of 6: START RPL ======
echo "> Executing CHANGE MASTER on slave1 ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/change_master.sql" --port=13002
echo "> Executing START SLAVE on slave1 ..."
mysql -uroot -h 127.0.0.1 -e "START SLAVE" --port=13002
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/change_master.sql" --port=13003
echo "> Executing START SLAVE on slave2 ..."
mysql -uroot -h 127.0.0.1 -e "START SLAVE" --port=13003
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/change_master.sql" --port=13004
echo "> Executing START SLAVE on slave3 ..."

mysql -uroot -h 127.0.0.1 -e "START SLAVE" --port=13004

echo
echo ====== Step 5 of 6: CHECK RPL ======
echo "> Checking replication setup ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/check_rpl.sql" --port=13001
echo
echo ====== Step 6 of 6: CREATE SOME DATA ======
echo "> Creating data ..."
mysql -uroot -h 127.0.0.1 -e "source /home/<user>/rpl/sample_data.sql" --port=13001
sleep 3
mysql -uroot -h 127.0.0.1 -e "SELECT * FROM test.t1" --port=13003
echo Done.
echo

Listing 1-9Example Replication Startup Script

清单 1-10 是这个脚本运行时的输出示例。服务器启动步骤中的一些消息已被删除。在您的系统上的执行可能会有所不同,但是清单显示了您应该看到的语句的正确顺序。

$ ./setup.sh
Introduction to MySQL InnoDB Cluster - Ch01 : Setup MySQL Replication
====== Step 1 of 6: INITIALIZE DATA DIRECTORIES ======
> Creating data directory root ...
> Initializing the master ...
> Initializing slave1 ...
> Initializing slave2 ...
> Initializing slave3 ...
====== Step 2 of 6: START ALL INSTANCES ======
> Removing old socket file ...
> Starting master ...
> Starting slave1 ...
> Starting slave2 ...
> Starting slave3 ...
====== Step 3 of 6: CREATE THE REPLICATION USER ======
> Creating replication user on the master ...
> Creating replication user on slave1 ...
> Creating replication user on slave2 ...
> Creating replication user on slave3 ...
====== Step 4 of 6: START RPL ======
> Executing CHANGE MASTER on slave1 ...
> Executing START SLAVE on slave1 ...
> Executing CHANGE MASTER on slave2 ...
> Executing START SLAVE on slave2 ...
> Executing CHANGE MASTER on slave3 ...
> Executing START SLAVE on slave3 ...
====== Step 5 of 6: CHECK RPL ======

> Checking replication setup ...
+-----------+-----------+-------+-----------+-----------------------------+
| Server_id | Host      | Port  | Master_id | Slave_UUID                  |
+-----------+-----------+-------+-----------+-----------------------------+
|         2 | localhost | 13002 |         1 | d2a4b096-254f-11e8-8694-                                              8086f28ecc6d                |
|         4 | localhost | 13004 |         1 | d774c619-254f-11e8-894f-                                              8086f28ecc6d                |
|         3 | localhost | 13003 |         1 | d507b376-254f-11e8-8882-                                              8086f28ecc6d                |
+-----------+-----------+-------+-----------+-----------------------------+
====== Step 6 of 6: CREATE SOME DATA ======
> Creating data ...
+----+-------+
| c1 | c2    |
+----+-------+
|  1 | Chuck |
+----+-------+
Done.

Listing 1-10Example Replication Script Output

注意,在脚本的最后,我们看到了SHOW SLAVE HOSTS的输出,显示了所有连接的从机(您应该看到所有三个从机)。我们还看到了在一个从机上执行的测试数据的SELECT查询的结果。

如果您尝试这个脚本并遇到错误,请确保检查脚本中的路径,以确保您已经正确地更改了它们。此外,一定要检查*_output.txt日志文件,因为服务器可能会发出错误消息,帮助您修复导致错误的原因。

您可能还对一种快速简单的关闭复制的方法感兴趣。清单 1-11 显示了一个示例脚本,您可以使用该脚本来关闭您的示例复制拓扑。请注意,我们按照精确的顺序关闭,首先停止从属线程,然后关闭 MySQL 实例,最后删除数据目录。

#!/bin/bash
#
# Introducing MySQL InnoDB Cluster - Chapter 1 : Shutdown Replication
#
...
#
# Dr. Charles Bell, 2018
#
DATADIR='/home/<user>/rpl'
echo
echo Introduction to MySQL InnoDB Cluster - Ch01 : Shutdown MySQL Replication
echo
echo ====== Step 1 of 3: STOP REPLICATION ON SLAVES ======
echo "> Stopping the slave threads on slave1 ..."
mysql -uroot -h 127.0.0.1 --port=13002 -e "STOP SLAVE"
echo "> Stopping the slave threads on slave2 ..."

mysql -uroot -h 127.0.0.1 --port=13003 -e "STOP SLAVE"

echo "> Stopping the slave threads on slave3 ..."
mysql -uroot -h 127.0.0.1 --port=13004 -e "STOP SLAVE"
echo
echo ====== Step 2 of 3: SHUTDOWN mysqld INSTANCES ======
echo "> Stopping the MySQL instance for slave1 ..."
mysql -uroot -h 127.0.0.1 --port=13002 -e "SHUTDOWN"
echo "> Stopping the MySQL instance for slave2 ..."
mysql -uroot -h 127.0.0.1 --port=13003 -e "SHUTDOWN"
echo "> Stopping the MySQL instance for slave3 ..."
mysql -uroot -h 127.0.0.1 --port=13004 -e "SHUTDOWN"
echo "> Stopping the MySQL instance for the master ..."
mysql -uroot -h 127.0.0.1 --port=13001 -e "SHUTDOWN"
echo
echo ====== Step 3 of 3: DESTROY THE DATA DIRECTORIES ======
echo "> Removing data directories and the root ..."
cd "$DATADIR"
rm -rf "$DATADIR/data"
echo Done.

Listing 1-11Example Replication Shutdown Script

如果您试图诊断示例复制拓扑的问题,您可能希望注释掉最后一步,以防从属线程或查询中出现问题。删除数据目录也将删除任何有助于诊断问题的日志文件。清单 1-12 显示了运行这个脚本的输出示例。

$ ./shutdown.sh

Introduction to MySQL InnoDB Cluster - Ch01 : Shutdown MySQL Replication
====== Step 1 of 3: STOP REPLICATION ON SLAVES ======
> Stopping the slave threads on slave1 ...
> Stopping the slave threads on slave2 ...
> Stopping the slave threads on slave3 ...
====== Step 2 of 3: SHUTDOWN mysqld INSTANCES ======
> Stopping the MySQL instance for slave1 ...
> Stopping the MySQL instance for slave2 ...
> Stopping the MySQL instance for slave3 ...
> Stopping the MySQL instance for the master ...
====== Step 3 of 3: DESTROY THE DATA DIRECTORIES ======
> Removing data directories and the root ...
Done.

Listing 1-12Example Replication Shutdown Script Output

小费

您可能需要对这些脚本进行更改,以匹配您的平台和帐户设置。一些变化可能需要一些工作。然而,本书的示例代码包括了这个适用于 Linux、macOS 和 Windows 10 的脚本。

既然您对 MySQL 复制和组复制有了更多的了解,让我们回顾一下数据库管理员在管理这些特性时面临的一些挑战。

MySQL 数据库管理员面临的挑战

从这些关于 MySQL 复制和组复制的简短讨论中,您可能已经了解了一些事情。其中之一可能是当你意识到设置过程是严格的并且需要神秘的命令时典型的压倒性的感觉。当然,这同样适用于任何系统或主要特性,比如高可用性。幸运的是,像这本书和其他的参考资料可以帮助缓解一些学习曲线。

然而,众所周知,MySQL 中的这些高可用性特性给管理员带来了挑战——包括系统和数据库。下面给出了几类挑战的概述,目的是让您做好准备,了解 InnoDB Cluster 如何简化其中的许多挑战。

设置

此类别包括基于复制的高可用性解决方案的规划和安装。考虑对现有数据、服务器、应用、用户和管理员的需求。

  • 为复制设置变量:了解如何调整复制和服务器以获得最佳操作。

  • 安装的推广:在整个基础架构中可能有数百台服务器上安装和设置复制,并以自动化方式完成。

  • 集成应用和第三方解决方案:找出如何将其他高可用性组件与复制和 MySQL 集成。

  • 读取扩展:为更快的应用读取构建拓扑;从多个从设备/辅助设备读取数据。

  • 写入扩展:为更快的应用写入构建拓扑;将数据写入多个主服务器。

解决纷争

此类别包括与检测和纠正错误、停机、计划维护等异常相关的任务。

  • 数据未复制:当数据未到达一台或多台服务器时发现并纠正。

  • 辅助服务器因错误(或意外)而停止:对停止复制的服务器进行故障排除和修复。

  • 复制过程中的错误:从错误中恢复,包括恢复服务器、同步数据、重新建立复制等任务。

  • 二级更新滞后:确定为什么一些服务器更新数据不如其他服务器快。

保持

此类别包括与保持高可用性解决方案以最高效率运行相关的预防性任务,有时还包括纠正性任务。这一类别经常被缺乏经验的管理员忽略,并且在大型安装中经常需要高级的付费工具。

  • 检查服务器性能:确保所有服务器都以最高效率运行。

  • 监控拓扑中的服务器:及早发现问题,如性能、错误和负载。

  • 升级数据库、MySQL 或平台:了解如何升级拓扑结构中的服务器(在大型组织中通常是一项主要工作)。

  • 检查数据一致性:检查给定服务器的数据不一致性。

  • 同步数据:确保所有服务器与主服务器拥有相同的数据。

管理

此类别涵盖作为高可用性解决方案的一部分而出现的典型或预期任务。这些可能包括管理服务器、复制和数据,以应对计划或预期的条件或事件。

  • 进行切换:手动将主要角色转换为次要角色。

  • 自动故障转移:主(写)角色切换到候选辅助角色,自动确保数据访问不中断。

  • 恢复拓扑中的服务器:恢复发生故障或数据损坏的服务器。

  • 备份和恢复:利用辅助节点卸载备份,使用辅助节点恢复数据。

  • Provisioning :向拓扑中添加更多的辅助节点,目标是最大限度地减少复制更改的时间。通常使用另一个辅助节点的备份来完成。

MySQL 高可用性参考资料

如果您仔细阅读了在 InnoDB Cluster 之前关于 MySQL 高可用性的一些较长的作品,您可能会发现一些针对特定用例的额外的、更复杂的挑战。如果您想在使用 InnoDB Cluster 之前了解有关 MySQL 复制和 MySQL 高可用性特性的更多信息,以下是一些优秀的资源:

  • 查尔斯·贝尔等人的《MySQL 高可用性:构建强大数据中心的工具》第二版(奥赖利,2014 年)

  • MySQL 复制简化版:Sribatsa Das (Business Compass,2014)提供的建立、故障排除和监控复制的简单分步示例

  • 高性能 MySQL:优化、备份、复制等Baron Schwartz 等人(O'Reilly,2012 年)

  • 亚历克斯·戴维斯的《高可用性 MySQL 食谱》( Packt,2010)

对于想了解二进制日志及其格式的更多细节的人来说,有一些相当晦涩的资源是他们感兴趣的。当然,在线参考手册有大量的文档,应该是您的主要来源。但是,以下包含其他来源中没有的关键信息:

小费

本书的源代码包含脚本,您可以使用这些脚本来设置 MySQL 复制和 MySQL 组复制,并根据您的需要对它们进行修改。你可以在该书的网站上找到这些( www.apress.com/9781484238844 )。

摘要

使用 MySQL 复制可以在 MySQL 中实现高可用性。事实上,您可以通过复制创建健壮的数据中心。更好的是,复制已经存在了很长时间,并且被认为是稳定的。许多组织已经并将继续成功地在生产中使用复制—从小规模安装到大规模安装。

即便如此,使用 MySQL 复制也有一些限制,例如,如果主服务器出现故障,如何将主服务器角色切换到另一台机器(从服务器),如何自动执行这一操作,如何处理多个写入场景,以及一般的故障排除和维护。其中许多在组复制中得到了改进。然而,正如您所看到的,复制的设置需要努力和维护,这可能是规划者(例如,架构师)和管理员都关心的问题。

对于那些不熟悉类似高可用性解决方案的人来说,启动和运行复制并随着时间的推移对其进行管理是一个巨大的挑战。事实上,对 MySQL 复制知识的需求非常高,因为这是一个独特的技能组合,很难找到。

因此,Oracle 对 MySQL 复制进行了改进,在其功能集和成功的基础上,结合了其他几个功能,以提供一个更易于学习和维护的高可用性解决方案。组复制和后来 InnoDB 集群就是答案,且已经证明它是 MySQL 高可用性的首选解决方案。

在下一章中,您将了解关于 InnoDB 集群的更多信息,以及如何使用它来实现高可用性。

Footnotes [1](#Fn1_source)

从这个意义上来说,拓扑是参与复制的一组服务器。复制拓扑也可以用于描述服务器如何连接,例如单个主服务器和一个或多个从服务器,分层的(主服务器可以是其他从服务器的从服务器),甚至是循环的(主-从连接形成一个循环)。

  2

这些术语仅代表服务器在复制数据中扮演的角色。它们与使用类似术语的卑鄙和可悲的做法毫无关系。

  3

<user_home>是当前用户个人文件夹的占位符。比如/home/cbell

 

二、什么是 MySQL InnoDB 集群?

现在,您已经了解了什么是高可用性以及如何通过 MySQL 复制实现高可用性,让我们看看 MySQL 中高可用性特性的最新发展:InnoDB Cluster。

这是对 Oracle MySQL 工程师(以及 Oracle 本身)奉献精神的证明,MySQL 将继续通过新功能进行改进。MySQL 工程部门的动力是继续为互联网开发颠覆性的数据库技术。甲骨文不仅培养了这种进取精神,还继续兑现其投资和发展 MySQL 业务的承诺。这个最新版本 MySQL 8 最终证明了 Oracle 已经实现了它的承诺,确保 MySQL 仍然是世界上最受欢迎的开源数据库系统。

MySQL 的这个新版本打破了以前版本的许多模式,增加了新的、革命性的功能,改变了一些人使用 MySQL 的方式。事实上,仅版本号就从 5。x 到 8.0,标志着技术复杂性的飞跃,最终脱离了 5 的持续发展。持续了超过 13 年的 x 代码库。

8 . 0 . 5–8 . 0 . 10 版本发生了什么变化?

您可能已经注意到 8.0 版本系列不是连续的,并且已经跳过了一些临时编号的版本。这在很大程度上是为了稳定和协调单一产品发布口号,以便用户可以一眼就知道哪些组件的哪些版本可以协同工作。很明显,知道你所有的 MySQL 组件都有 8.0.11 版本,可以确保它们能一起工作。我们需要路线图和夏尔巴人指南来发现哪个组件的哪个版本可以一起工作的日子已经一去不复返了!

最令人兴奋的新特性之一是 InnoDB 集群。这代表了 MySQL 在高可用性方面的巨大飞跃。最重要的是,它是 MySQL 8.0 所有版本的标准配置。让我们看看是什么让 InnoDB 集群成为大大小小的企业的重要功能。

概观

InnoDB 集群的核心组件是 InnoDB 存储引擎。自 MySQL 5.6 以来,InnoDB 一直是 MySQL 的旗舰存储引擎(也是默认引擎)。Oracle 已经慢慢地脱离了多存储引擎模型,专注于现代数据库服务器应该做的事情:支持事务存储机制。InnoDB 是满足这一需求的答案。

为了更好地理解我们是如何实现 InnoDB 集群的,让我们简短地浏览一下 MySQL 8.0 和早期版本中的其他存储引擎。

什么是存储引擎?

存储引擎是一种以各种方式存储数据的机制。例如,有一种存储引擎允许您与逗号分隔值(文本)文件(CSV)进行交互,另一种为写日志文件(归档)进行了优化,一种只在内存中存储数据(内存),甚至还有一种根本不存储任何东西(黑洞)。除了 InnoDB,MySQL 服务器还附带了几个存储引擎。以下部分描述了一些更常用的替代存储引擎。请注意,随着 MySQL 的发展,一些存储引擎已经不再受支持,包括 Berkeley Database (BDB)存储引擎。

小费

如果您想查看 MySQL 服务器上有哪些可用的存储引擎,可以使用SHOW ENGINES命令。请参见( https://dev.mysql.com/doc/refman/8.0/en/create-table.html )了解有关使用CREATE TABLE命令指定存储引擎的更多信息。

我的天

MyISAM 存储引擎最初是 MySQL 中的默认引擎,被大多数 LAMP 堆栈、数据仓库、电子商务和企业应用使用。MyISAM 文件是索引顺序访问方法(ISAM)的扩展,具有额外的优化,如高级缓存和索引机制。这些表是使用压缩特性和索引优化来提高速度的。

此外,MyISAM 存储引擎通过提供表级锁定来支持并发操作。MyISAM 存储机制为各种应用提供可靠的存储,同时提供快速的数据检索。当考虑读取性能时,MyISAM 是首选的存储引擎。

记忆

内存存储引擎(有时称为堆表)是一个内存中的表,它使用哈希机制来快速检索经常使用的数据。这些表比那些从磁盘存储和引用的表要快得多。它们的访问方式与其他存储引擎相同,但是数据存储在内存中,只有在 MySQL 重新启动后才有效。数据在关机(或崩溃)时被刷新和删除。

内存存储引擎通常用于静态数据被频繁访问且很少被更改的情况。这种情况的例子包括邮政编码、州、县、类别和其他查找表。堆表也可以用于利用快照技术进行分布式或历史数据访问的数据库中。

合并

合并存储引擎(有时称为MRG_MYISAM)是使用一组具有相同结构(元组布局或模式)的 MyISAM 表构建的,这些表可以作为单个表引用。这些表是根据各个表的位置进行分区的,但是没有使用额外的分区机制。所有表必须驻留在同一台机器上(由同一台服务器访问)。使用单个操作或语句来访问数据,例如SELECTUPDATEINSERTDELETE。幸运的是,当在合并表上发出一个DROP时,只有合并规范被删除。原始表格没有改变。

这种表类型最大的好处就是速度。可以将一个大表分割成不同磁盘上的几个小表,使用合并表规范将它们组合起来,并同时访问它们。搜索和排序将执行得更快,因为每个表中需要操作的数据更少。例如,如果按谓词划分数据,则可以只搜索包含要搜索的类别的特定部分。同样,对表的修复更有效,因为修复几个较小的单个文件比修复单个大表更快更容易。据推测,大多数错误将局限于一个或两个文件内的区域,因此不需要重建和修复所有数据。不幸的是,这种配置有几个缺点:

  • 您只能使用相同的 MyISAM 表或架构来形成一个合并表。这限制了合并存储引擎在 MyISAM 表中的应用。如果合并存储引擎接受任何存储引擎,合并存储引擎将更加通用。

  • 不允许替换操作。

  • 已经证明索引访问比单个表的效率低。

合并存储机制最适用于大型数据库(VLDB)应用,例如数据驻留在一个或多个数据库的多个表中的数据仓库。

档案馆

档案存储引擎设计用于以压缩格式存储大量数据。存档存储机制最适合用于存储和检索大量很少访问的存档或历史数据。这些数据包括安全访问数据日志。虽然这不是您想要搜索甚至日常使用的东西,但是如果发生安全事故,关心安全的数据库专业人员会希望拥有它。没有为归档存储机制提供索引,唯一的访问方法是通过表扫描。归档存储引擎不应用于正常的数据库存储和检索。

联邦的

联邦存储引擎被设计为从多个 MySQL 数据库系统创建单个表引用。因此,联邦存储引擎的工作方式类似于合并存储引擎,但是它允许您跨数据库服务器将数据(表)链接在一起。这种机制在目的上类似于其他数据库系统中可用的链接数据表。联邦存储机制最适合在分布式或数据集市环境中使用。

联邦存储引擎最有趣的方面是它不移动数据,也不要求远程表是同一个存储引擎。这说明了可插拔存储引擎层的真正威力。数据在存储和检索过程中被转换。

战斗支援车

CSV 存储引擎被设计为以表格形式创建、读取和写入逗号分隔值(CSV)文件。虽然 CSV 存储引擎不会将数据复制为另一种格式,但图纸布局或元数据会与服务器上指定的文件名一起存储在数据库文件夹中。这允许数据库专业人员快速导出存储在电子表格中的结构化业务数据。CSV 存储引擎不提供任何索引机制,因此对于大量数据来说不切实际。它旨在用作存储数据和在电子表格应用中可视化数据之间的链接。

黑洞

黑洞存储引擎,一个具有惊人效用的有趣特性,被设计成允许系统写入数据,但数据永远不会被保存。但是,如果启用了二进制日志记录,SQL 语句将被写入日志。这允许数据库管理员和开发者通过切换表类型来临时禁用数据库中的数据接收。当您想要测试一个应用以确保它正在写入您不想存储的数据时,例如当创建一个用于过滤复制的中继从属时,这可能会很方便。

InnoDB

InnoDB 是一个通用存储引擎,平衡了高可靠性和高性能。InnoDB 成为 MySQL 5.7 中的默认存储引擎,这意味着所有没有使用ENGINE子句创建的表都作为 InnoDB 表空间中的 InnoDB 表创建。使用 InnoDB 存储引擎的决定是在多次尝试为 MySQL 构建一个健壮、高性能的存储引擎之后做出的。考虑到 InnoDB 的成熟性和复杂性,使用已经存在的东西更有意义。另外,甲骨文同时拥有 MySQL 和 InnoDB。

为什么叫 InnoDB?

在早期,InnoDB 存储引擎是由一家名为芬兰 InfoBase Oy 的独立公司构建和拥有的,该公司将其数据库引擎命名为 InnoDB。这是一个独立的产品,不属于 MySQL,也不归 MySQL AB 所有(MySQL 的原所有者现在完全归 Oracle 所有)。最终,甲骨文在 2005 年拥有了 InnoDB,在 2010 年拥有了 MySQL,将两者结合起来是有意义的,因为它们有相互包容的目标。尽管独立的 InnoDB 工程团队仍然存在,但他们已经与核心服务器开发团队完全集成。

当您需要使用事务时,可以使用 InnoDB 存储引擎。InnoDB 支持传统的 ACID 事务(参见附带的侧栏)和外键约束。InnoDB 中的所有索引都是 B 树,索引记录存储在树的叶页中。InnoDB 是高可靠性和事务处理环境的首选存储引擎。

酸是什么?

代表原子数稠度隔离度耐久性。也许是数据库理论中最重要的概念之一,它定义了数据库系统必须表现出的行为,才能被认为是可靠的事务处理。

原子性意味着对于包含多个命令的事务,数据库必须允许在“全有或全无”的基础上修改数据。每个事务都是原子的。如果命令失败,则整个事务失败,并且事务中到该点为止的所有更改都将被丢弃。这对于在高事务环境(如金融市场)中运行的系统尤其重要。考虑一下资金转移的后果。通常,借记一个账户和贷记另一个账户需要多个步骤。如果在借记步骤后事务失败,并且没有将钱贷记回第一个帐户,该帐户的所有者将会生气。在这种情况下,从借方到贷方的整个事务必须成功,否则都不会成功。

一致性意味着只有有效的数据才会存储在数据库中。如果事务中的命令违反了一致性规则之一,则整个事务将被丢弃,数据将返回到事务开始前的状态。相反,如果事务成功完成,它将以遵守数据库一致性规则的方式更改数据。

隔离意味着同时执行的多个事务不会相互干扰。这是并发性的真正挑战最明显的地方。数据库系统必须处理事务不能违反另一个事务正在使用的数据(更改、删除等)的情况。有很多方法可以解决这个问题。大多数系统使用一种叫做锁定的机制,在第一个事务完成之前防止数据被另一个事务使用。虽然隔离属性没有规定先执行哪个事务,但它确实确保了它们不会相互干扰。

持久性意味着事务不会导致数据丢失,也不会丢失事务期间创建或更改的任何数据。耐用性通常由强大的备份和恢复维护功能提供。一些数据库系统使用日志记录来确保任何未提交的数据可以在重启时恢复。

与 MySQL 中的旧存储引擎相比,InnoDB 提供了几个关键优势,包括:

  • 数据操作语言(DML)操作遵循 ACID 模型,事务具有提交、回滚和崩溃恢复功能来保护用户数据。

  • 行级锁定和 Oracle 风格的一致读取提高了多用户并发性和性能。

  • InnoDB 表在磁盘上排列您的数据,以优化基于主键的查询。每个 InnoDB 表都有一个名为聚簇索引的主键索引,它组织数据以最小化主键查找的 I/O。

  • 为了保持数据的完整性,InnoDB 支持外键约束。使用外键时,会检查插入、更新和删除,以确保它们不会导致不同表之间的不一致。

对 InnoDB 进行了许多改进,包括许多性能增强,甚至支持微调等等。InnoDB 在 MySQL 的每个版本中不断改进,这一点显而易见。事实上,自 5.6 版本以来,改进的列表已经增长了很长时间。虽然大多数改进都很细微,从某种意义上说,你不会注意到它们(除了通过更好的性能和可靠性,这是不可轻视的),但大多数都显示出致力于使 InnoDB 成为最好的事务存储机制,并通过扩展,MySQL 成为强大的事务数据库系统。

下面列出了 MySQL 8 中对 InnoDB 的一些更有趣的改进。其中一些可能看起来非常深奥,但是那些已经优化或调整了 InnoDB 安装的人在计划迁移到 MySQL 8 时可能需要注意这些。这里没有列出的是几十个小缺陷修复和可靠性、性能的提升。

  • 改进的表空间支持:包括使用新数据字典、重新定位表空间等增强功能。

  • 新的 innodb_dedicated_server 配置选项:(默认禁用)用于让 InnoDB 根据服务器上检测到的内存量自动配置以下选项。

    • innodb_buffer_pool_size

    • innodb_log_file_size

    • innodb_flush_method

  • 崩溃恢复:如果索引树损坏,InnoDB 会将损坏标志写入重做日志。这使得损坏标志崩溃安全(它不会在强制重启时丢失)。类似地,InnoDB 还会在每个检查点上写一个内存损坏标志。当启动崩溃恢复时,InnoDB 可以读取这些标志,并使用它们来调整恢复操作。

  • InnoDB memcached 插件:通过允许在单个 memcached 查询中提取多个键/值对而得到改进。

  • 死锁检测:有几个新选项,但是最有前途的包括一个动态配置死锁检测的选项(innodb_deadlock_detect)。这可以为高使用率系统提供额外的调优控制,因为死锁检测会降低系统的性能。

  • INFORMATION_SCHEMA 视图:InnoDB 有新的视图。

  • AUTO_INCREMENT:自动递增字段有几处小的改进,包括以下内容:

    • 当前最大自动增量值现在在服务器重新启动后保持不变。

    • 重启不再取消AUTO_INCREMENT = N工作台选项的效果。

    • 紧随ROLLBACK操作之后的服务器重启不再导致分配给回滚事务的自动增量值的重用。

    • 将一个AUTO_INCREMENT列值设置为大于当前最大值的值是持久的,并且以后的新值(比如,在重启之后)以新的、更大的值开始。

  • 临时表:默认情况下,所有临时表都创建在名为ibtmp1的共享临时表空间中。

虽然这个列表似乎只关注一些小的改进,但是其中一些对于寻求帮助来调整和规划数据库服务器安装的系统管理员来说是非常重要的。如果您想了解更多关于这些改进的信息或查看所有最新变化的列表,请参阅在线 MySQL 8.0 参考手册( http://downloads.mysql.com/docs/refman-8.0-en.pdf )。

也许 InnoDB 区别于 MySQL 早期存储引擎的最重要的特性是它的可配置性。尽管一些早期的存储引擎是可配置的,但没有一个能达到配置 InnoDB 的规模。您可以使用几十个参数来调整 InnoDB,以满足您独特的存储需求。

警告

修改 InnoDB 参数时要小心。有可能会使您的系统降级到损害性能的程度。与任何调优练习一样,总是先查阅文档(和专家),然后计划针对特定的参数。确保一次调优一个参数,并在继续之前进行测试、确认或恢复。

尽管 InnoDB 使用精心选择的缺省值,开箱即可正常工作,并且对大多数人来说可能不需要太多的调优,但是那些需要调优 MySQL 的人会发现他们需要的一切,甚至更多,以便让他们的数据库系统以最高效率运行。参见 https://dev.mysql.com/doc/refman/8.0/en/innodb-introduction.html 了解有关 InnoDB 存储引擎的更多信息,包括其众多的配置和调优选项。

小费

另一个关于配置 MySQL 和 InnoDB 的技巧和建议的极好来源是 Baron Schwartz 等人的High Performance MySQL:Optimization,Backups,Replication and More(O ' Reilly,2012)。

现在,您已经对 InnoDB 的谱系和发展有了更好的了解,让我们来看看 InnoDB Cluster 提供了什么。

InnoDB 集群简介

MySQL 8.0 1 中最令人兴奋的新特性之一是 InnoDB Cluster。它旨在使高可用性更易于设置、使用和维护。InnoDB Cluster 通过 MySQL Shell 和 AdminAPI、组复制和 MySQL 路由与 X DevAPI 一起工作,将高可用性和读取可伸缩性提升到一个新的水平。InnoDB Cluster 将 InnoDB 中用于克隆数据的新功能与组复制和 MySQL 路由相结合,提供了一种设置和管理高可用性的新方法。下面的列表描述了构成 InnoDB 集群的组件。在下一节中,您将了解到关于这些的更多信息,并且在后面的章节中,当您通过教程探索 InnoDB 时,您将看到如何配置和使用这些信息的细节。

  • 组复制:一种新的复制形式,建立在 MySQL 复制的基础上,增加了一个活动的通信协议(组成员),允许更高级别的可用性,包括自动故障转移的容错。

  • MySQL Shell :一个新的 MySQL 客户端,允许几种接口模式,包括传统的 SQL 以及 JavaScript 和 Python 脚本语言。

  • X DevAPI :一个特殊的应用编程接口,供应用以编程方式与数据进行交互。

  • AdminAPI :通过 MySQL Shell 提供的特殊 API,用于配置 InnoDB 集群并与之交互。AdminAPI 具有旨在简化 InnoDB 集群工作的特性。

  • MySQL 路由:轻量级的中间件,在你的应用和后端 MySQL 服务器之间提供透明的路由。

你可能想知道所有的大惊小怪是什么。从表面上看,InnoDB Cluster 是 MySQL 中现有特性的捆绑包。虽然这可能是一个有效的结论,但事实是,该产品不仅仅是简单地用一个新名字将东西捆绑在一起。在这种情况下,Oracle 在 InnoDB Cluster 中添加了专门的管理层和内部特性,以改进这些产品。正如您将看到的,使用 InnoDB Cluster 通常隐藏了单独使用组件的许多细节(和繁琐)。

让我们看一个概念性的配置,以了解组件是如何交互的。图 2-1 显示了这些组件如何在概念上排列以形成 InnoDB 集群。

img/460910_1_En_2_Fig1_HTML.jpg

图 2-1

InnoDB 集群的典型配置(由 Oracle 提供)

在这个用例中,一个包含三个服务器的集群设置有一个主服务器(按照标准复制的说法,认为是主服务器),它是所有写入(更新)的目标。多个辅助服务器(从属服务器)维护数据的副本,可以从这些副本中读取数据;这些服务器支持读取数据,而不会加重主服务器的负担,因此支持读取可伸缩性(但所有服务器都参与协商和协调)。组复制的引入意味着集群是容错的,并且组成员是自动管理的。MySQL 路由缓存 InnoDB 集群的元数据,并执行到 MySQL 服务器实例的高可用性路由,从而更容易编写应用来与集群进行交互。

您可能想知道这与标准复制的读取可伸缩性(有时称为读出可伸缩性)设置有何不同。从高层次来看,这些解决方案似乎正在解决同一个用例。但是,使用 InnoDB Cluster,您可以从 MySQL Shell 创建、部署和配置集群中的服务器,从而提供一个易于管理的完整的高可用性解决方案。您可以通过 shell 使用 X AdminAPI(也称为 AdminAPI)使用 JavaScript 或 Python 以编程方式创建和管理 InnoDB 集群。

要了解有关 InnoDB 集群的更多信息,包括最新的特性、使用案例等,请参阅位于 https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-userguide.html 的在线文档。

InnoDB 集群和 MySQL 文档库

如果没有讨论 InnoDB Cluster 如何与 MySQL 的其他新特性很好地协同工作,关于 InnoDB Cluster 的书将是不完整的。MySQL 文档存储就是这样一个特性。MySQL 文档存储是 MySQL 的一个新动态,它允许通过应用编程接口(实际上是 X DevAPI)存储和检索 JSON 数据(称为文档)。文档存储允许您创建处理非结构化数据的 NoSQL 应用。

如果您使用过关系数据库系统,那么您肯定熟悉结构化查询语言(SQL ),它使用特殊的语句(命令)与数据进行交互。事实上,大多数数据库系统都有自己的 SQL 版本,包括操作数据的命令(DML)以及定义存储数据的对象的命令(DDL),甚至还有管理服务器的管理命令。

要在 SQL 接口中检索数据,您必须使用特殊的命令来搜索数据,然后将结果转换为内部编程结构,使数据看起来像是一个辅助组件,而不是解决方案的一个组成部分。NoSQL 接口打破了这种模式,它允许您使用 API 来处理数据。更具体地说,您使用编程接口,而不是基于命令的接口。

为什么叫“NoSQL”?

遗憾的是,根据你的观点,NoSQL 可以有几种意思,包括非 SQL不仅仅是 SQL ,或者非关系。但是它们都表明你正在使用的机制不是基于命令的接口,这个术语的大多数用法表明你正在使用编程接口。

在 MySQL 8 中,可以使用 X 协议通过 SQL 或 NoSQL 访问 JSON 文档,通过 X 插件访问 X DevAPI。因此,尽管 InnoDB Cluster 将增强为传统 SQL 数据库编写的高可用性应用,但 InnoDB Cluster 也可以与 NoSQL 应用无缝协作。

小费

要了解更多关于 MySQL 文档存储的信息,请参阅我的书,介绍 MySQL 8 文档存储(2018 年出版)。

InnoDB 集群和 NDB 集群

如果您仔细阅读 MySQL 网站,您会发现另一个名称中带有 cluster 的产品。它被诱人地命名为 NDB 集群。NDB 集群是一个独立于 MySQL 服务器的产品,它采用了一种技术,能够在一个无共享的系统中实现内存数据库的集群。无共享架构使系统能够与廉价的硬件一起工作,并且对硬件或软件的特定要求最小。

NDB 集群的设计不存在任何单点故障。在无共享系统中,每个组件都有自己的内存和磁盘,不建议或不支持使用共享存储机制,如网络共享、网络文件系统和存储区域网络(San)。参见https: https://dev.mysql.com/doc/refman/5.7/en/mysql-cluster-compared.html 了解更多关于 NDB 集群及其与 InnoDB 的关系。

小费

要了解更多关于 NDB 集群的信息,请参阅 Jesper Krogh 和 Mikiya Okuno 撰写的优秀的 Pro MySQL NDB 集群(a press,2017)。这本书涵盖了 NDB 集群的各个方面,是任何对部署和管理 NDB 集群感兴趣的人的必读之作。

成分

现在,您已经对 InnoDB 集群有了更好的了解,包括它是如何发展的以及它对高可用性的好处,让我们了解更多关于组成 InnoDB 集群的组件。以下部分从较高的层面描述了每个组件。同样,在后面的章节中,你会发现更多关于它们的内容。我将只介绍每个组件的基础知识,让您了解它的复杂性和好处。

组复制

如果您使用过 MySQL 复制,那么您无疑熟悉如何在构建高可用性解决方案时利用它。事实上,您很可能已经发现了许多使用 MySQL 复制来提高应用可用性的方法。

什么是复制,它是如何工作的?

MySQL 复制是一个易于使用的特性,也是 MySQL Server 的一个复杂和主要的组件。本节提供了复制的鸟瞰图,目的是解释它是如何工作的以及如何设置一个简单的复制拓扑。有关复制及其众多特性和命令的更多信息,请参见在线 MySQL 参考手册( http://dev.mysql.com/doc/refman/8.0/en/replication.html )。

复制需要两台或更多服务器。必须将一台服务器指定为源服务器或主服务器。主角色意味着对数据的所有数据更改(写入)都发送到主服务器,并且只发送到主服务器。拓扑中的所有其他服务器维护主数据的副本,并且根据设计和要求是只读服务器。因此,当您的应用发送数据进行存储时,它们会将数据发送到主服务器。您编写的使用传感器数据的应用可以从从属服务器读取这些数据。

复制机制通过使用一种称为二进制日志的技术来工作,该技术以一种特殊的格式存储更改,从而保留所有更改的记录。然后,这些更改被复制到从属服务器并在那里执行。在从机执行更改(称为事件)后,从机拥有数据的精确副本。

主设备维护一个二进制日志,从设备维护该二进制日志的副本,称为中继日志。当从设备向主设备请求数据更改时,它从主设备读取事件并将它们写入其中继日志;然后,从属线程中的另一个线程执行中继日志中的那些事件。可以想象,从主服务器上发生更改到从服务器上发生更改之间会有一点延迟。幸运的是,除了在高流量(大量变化)的拓扑中,这种延迟几乎是不明显的。

很可能您的高可用性需求越大,您的解决方案扩展得越多(复杂性增加),您就越需要采用更好的方法来管理节点丢失、数据完整性和集群的一般维护(复制数据的服务器组—有时称为副本集)。事实上,大多数高可用性解决方案已经超越了基本的主-从拓扑结构,演变成由服务器集群组成的层;有些复制一部分数据以获得更快的吞吐量,甚至用于分区存储。

所有这些导致许多人发现他们需要更多的 MySQL 复制。Oracle 通过组复制满足了这些需求以及更多需求。组复制允许您的 MySQL 高可用性解决方案远远超出原始 MySQL 复制功能的限制,从而使 MySQL 8 成为高可用性数据库解决方案的重要组成部分。

组复制于 2016 年 12 月作为 GA 发布(从 5.7.17 版本开始),以插件的形式与 MySQL 服务器捆绑。因为组复制是作为服务器插件实现的,所以您可以安装插件并开始使用组复制,而不必重新安装服务器,这使得试验新功能变得容易。

组复制也使得同步复制(在属于同一个组的节点之间)成为现实,而现有的 MySQL 复制特性是异步的(或者最多是半同步的)。因此,始终提供了更强的数据一致性(数据在所有成员上都可用,没有因等待副本跟上而导致的延迟)。

这可以通过在分配给一个组的服务器之间进行强协调的分布式状态机来实现。这种通信允许服务器在组内自动协调复制。更具体地说,组维护成员关系,以便服务器之间的数据复制在任何时间点都是一致的。即使从组中删除了服务器,当它们被重新添加时,一致性也会自动启动。此外,对于离线或变得不可达的服务器,还有一个故障检测机制。图 2-2 展示了如何在应用中使用组复制来实现高可用性。

img/460910_1_En_2_Fig2_HTML.jpg

图 2-2

对应用使用组复制以实现高可用性(由 Oracle 提供)

请注意,组复制可以与 MySQL 路由一起使用,以允许您的应用拥有一个与集群隔离的层。您将在后面的章节中看到一些关于路由的内容。

组复制和标准复制的另一个重要区别是,组中的所有服务器都可以参与更新数据,并自动解决冲突。是的,您不再需要精心设计您的应用来发送写入(更新)到特定的服务器!但是,您可以配置组复制,只允许一台服务器(称为主服务器)进行更新,其他服务器充当辅助服务器或备份服务器(用于故障转移)。

使用组复制中内置的三种特定技术(组成员、故障检测和容错)可以实现以下功能及更多功能:

  • 组成员身份:管理服务器是否活动(在线)并加入组。此外,还确保组中的每台服务器都有一致的成员集视图。每个服务器都知道组中服务器的完整列表。当服务器添加到组中时,组成员资格服务会自动重新配置成员资格。

  • 故障检测:一种能够发现并报告哪些服务器离线(不可达)并被认为是死的机制。故障检测器是一种分布式服务,它允许组中的所有服务器测试假定失效服务器的状况,通过这种方式,组决定服务器是否不可达(失效)。这允许该组通过协调排除故障服务器的过程来自动重新配置。

  • 容错:该服务使用 Paxos 分布式算法的实现来提供服务器之间的分布式协调。简而言之,该算法允许自动提升组内的角色,以确保即使一个(或几个)服务器出现故障或离开组,组也保持一致(数据一致且可用)。像类似的容错机制一样,失败(失败的服务器)的数量是有限的。目前,组复制容错被定义为 n = 2f + 1,其中 n 是容忍 f 个故障所需的服务器数量。例如,如果您希望容忍多达 5 台服务器出现故障,则该组中至少需要 11 台服务器。

有关组复制的更多信息,请参见位于 https://dev.mysql.com/doc/refman/8.0/en/replication.html 的在线参考手册中的“组复制”部分。

MySQL Shell

旧的 MySQL 客户端(名为mysql)最大的缺失之一是没有任何形式的脚本功能。但是,可以使用旧客户端处理一批 SQL 命令,并且客户端对编写存储例程(过程和函数)的支持有限。对于那些想要创建和使用脚本来管理他们的数据库(和服务器)的人来说,过去有一些外部工具,比如 MySQL Workbench,但是没有专门用于合并多种脚本语言的工具。

MySQL Workbench 是 Oracle 的一款非常受欢迎的产品。MySQL Workbench 是一个 GUI 工具,设计为基于工作站的管理工具。它提供了许多特性,包括数据库设计和建模工具、SQL 开发、数据库管理、数据库迁移和 Python 脚本支持。有关 MySQL Workbench 的更多信息,请参见 https://dev.mysql.com/doc/workbench/en/

MySQL Shell 是 MySQL 产品组合中令人激动的新成员。MySQL Shell 代表了第一个连接到 MySQL 并与之交互的现代高级客户端。shell 可以用作脚本环境,用于开发处理数据的新工具和应用。尽管它支持 SQL 模式,但它的主要目的是允许用 JavaScript 和 Python 语言访问数据。没错,您可以编写 Python 脚本,并在 shell 中以交互方式或批处理方式执行它们。酷!图 2-3 展示了一个启动 MySQL Shell 的例子。请注意显示 MySQL 徽标、连接信息和模式的漂亮提示符。很好!

img/460910_1_En_2_Fig3_HTML.jpg

图 2-3

MySQL Shell

MySQL Shell 被设计成使用新的 X 协议通过 X 插件与服务器通信。然而,shell 也可以通过使用旧的协议连接到服务器,尽管在脚本模式中功能有限。这意味着,shell 允许您使用关系数据(SQL)、JSON 文档(NoSQL)或两者。

SQL 模式的加入为学习如何使用脚本管理数据提供了一个很好的基础。您可以继续使用您的 SQL 命令(或批处理),直到您将它们转换为 JavaScript 或 Python。此外,您可以使用这两者来确保您的迁移是完整的。

MySQL Shell 有很多特性,包括支持传统的 SQL 命令处理、脚本原型,甚至支持定制 Shell。大多数特性都可以通过命令行选项或特殊的 shell 命令来控制。在后面的章节中,您将更深入地了解一些更重要的特性。现在,下面列出了 shell 的一些主要特性:

  • 日志:你可以为你的会话创建一个日志,用于以后的分析或者保存消息的记录。您可以使用-option设置详细程度,范围从 1(无记录)到 8(最大调试)。

  • 输出格式:shell 支持三种格式选项。这些是您在启动 shell 时指定的命令行选项。

    • 表格 ( --table):传统的网格格式,您已经习惯了旧客户端的格式

    • 制表符:用制表符分隔显示信息,用于批量执行

    • JSON ( --json):以更易于阅读的方式格式化 JSON 文档

  • 交互codeeexecution:使用 shell 的默认模式是交互模式,它的工作方式就像一个传统的客户端:你输入一个命令,得到一个响应。

  • 批处理代码执行:如果您想在没有交互会话的情况下运行您的脚本,您可以使用 shell 以批处理模式运行脚本。但是,输出仅限于非格式化输出(但可以用--interactive选项覆盖)。

  • 脚本语言:shell 支持 JavaScript 和 Python,尽管你一次只能使用一种。

  • 会话:会话本质上是到服务器的连接。shell 允许您存储和删除会话。

  • 启动脚本:您可以定义一个脚本在 shell 启动时执行。您可以用 JavaScript 或 Python 编写脚本。

  • 命令历史:shell 保存您输入的命令,允许您使用上下箭头键调用它们。

  • 全局变量:shell 提供了一些在交互模式下可以访问的全局变量。其中包括以下内容。

    • session:全局会话对象,如果已建立

    • db:模式,如果通过连接建立

    • dba:用于使用 InnoDB 集群的 AdminAPI 对象

    • shell:使用 Shell 的通用功能

    • util:与服务器一起工作的实用功能

  • 自定义提示:您也可以通过使用特殊格式更新名为~/.mysqlsh/prompt.json的配置文件或定义名为MYSQLSH_PROMPT_THEME的环境变量来更改默认提示。

  • 自动完成关键字、类和方法:从 8.0.4 开始,shell 允许用户在 SQL 模式下按 Tab 键自动完成关键字,在 JavaScript 和 Python 模式下自动完成主要的类和方法。shell 还为已知的关键字、API 函数和 SQL 关键字提供代码补全。

小费

有关 MySQL Shell 的更多信息,请参见在线 MySQL 参考手册( https://dev.mysql.com/doc/refman/8.0/en/mysql-shell.html )中标题为“MySQL Shell 用户指南”的部分。

X DevAPI

X Developer application programming interface,简称 X DevAPI,是一个类库和方法库,为 MySQL 实现了一个新的 NoSQL 接口。具体来说,X DevAPI 旨在允许与 JSON 文档和关系数据轻松交互。X DevAPI 有专门支持这两个概念的类,允许开发者在他们的应用中使用其中一个(或两个)。X DevAPI 与 X 协议、X 插件以及为公开 X DevAPI 而编写的客户端一起构成了 MySQL 8 文档库。X DevAPI 有几个强大的特性,包括:

  • MySQLX :一个模块,用于获取 X 协议连接到 MySQL 服务器产生的 session 对象。

  • 会话:连接到 MySQL 服务器。

  • 集合:存储 JSON 文档的组织抽象。

  • 文档 : JSON 文档是集合中数据的主要存储机制。

  • CRUD 操作:创建、读取、更新和删除操作的简单方法。读操作简单易懂。

  • 关系数据:实现传统关系数据的 CRUD 操作,包括 SQL 语句执行和结果处理。

  • 表达式:现代实践和语法风格用于摆脱传统的 SQL 字符串构建,以便在您的集合和文档中查找内容。

  • 并行执行:非阻塞、异步调用遵循常见的宿主语言模式。

  • 方法链接:构建 API 是为了让创建或检索(获取)对象的方法返回该对象的实例。这允许我们将几种方法结合在一起(称为方法链)。尽管方法链接既不是新概念,也不是 X DevAPI 所独有的,但它是一种强大的机制,使我们的代码更具表现力,更易于阅读。

注意

X DevAPI 仅在使用 X 插件时可用。如果没有安装 X 插件,就不能使用 X DevAPI,只能通过支持 X 协议的客户机或数据库连接器。

X DevAPI 只能通过实现 X 协议的一个客户机使用,具体来说,就是下面的任何一个客户机。此外,要使用这些客户端中的任何一个,您还必须在您的服务器上安装和配置 X 插件。

小费

有关 X DevAPI 的更多信息,请参见 https://dev.mysql.com/doc/x-devapi-userguide/en/

AdminAPI

管理应用编程接口(AdminAPI)是一个类库和方法库,为 InnoDB 集群实现了一个新的管理接口。具体来说,AdminAPI 旨在通过使用 MySQL Shell 中的脚本语言来实现与 InnoDB Cluster 的轻松交互。MySQL Shell 包含 AdminAPI,它使您能够部署、配置和管理 InnoDB 集群。AdminAPI 包含两个用于访问 InnoDB 集群功能的类:

  • dba:使您能够使用 AdminAPI 管理 InnoDB 集群。dba类使您能够管理集群;例如,创建一个新集群,使用沙箱配置(一种在同一台机器上使用几个 MySQL 实例来试验 InnoDB 集群的方法),以及检查实例和集群的状态。

  • cluster:InnoDB 集群的管理句柄。cluster类使您能够使用集群来添加实例、删除实例、获取集群的状态(健康)等等。

因为我们将在本书中直接使用 AdminAPI,所以你将在第 5 章中看到关于每个类可用方法的更多细节。

小费

参见 https://dev.mysql.com/doc/dev/mysqlsh-api-python/8.0/group___admin_a_p_i.html 了解更多关于 AdminAPI 的信息。

路由

MySQL 路由是 MySQL 中相对较新的组件。它最初是为现已过时的 MySQL Fabric 产品而构建的,经过了显著的改进和修改,可用于 InnoDB Cluster。事实上,它是 InnoDB 集群的重要组成部分。

MySQL 路由是一个轻量级的中间件组件,在应用和 MySQL 服务器之间提供透明的路由。虽然它可以用于各种各样的用例,但它的主要目的是通过有效地将数据库流量路由到适当的 MySQL 服务器来提高高可用性和可伸缩性。

对于处理故障转移的客户端应用,它们需要了解 InnoDB 集群拓扑,并知道哪个 MySQL 实例是主(写)服务器。虽然应用可以实现这种逻辑,但是 MySQL 路由可以为您提供和处理这种功能。

此外,当与 InnoDB Cluster 一起使用时,MySQL Router 充当代理来隐藏网络上的多个 MySQL 实例,并将数据请求映射到集群中的一个实例。如果有足够多的在线副本,并且组件之间的通信完好无损,应用将能够(重新)连接到其中一个副本。MySQL 路由通过简单地重新打印应用来连接到路由而不是直接连接到 MySQL,也使这种情况成为可能。

小费

关于 MySQL 路由的更多信息,请参见 https://dev.mysql.com/doc/mysql-router/8.0/en/ .

安装 InnoDB 集群

回想一下,Oracle 选择将 InnoDB 集群构建到 MySQL 服务器中,并致力于为社区和企业客户提供 InnoDB 集群。当您安装 MySQL 时,您也安装了 InnoDB Cluster 和使其工作所需的所有组件。

在本节中,您将通过使用 MySQL Windows Installer 在 Windows PC 上安装 MySQL。如果你使用的是另一个平台,可以查看在线 MySQL 参考手册了解更多细节( https://dev.mysql.com/doc/refman/8.0/en/installing.html )。

MySQL Windows Installer(也称为 MySQL Installer )为您的所有 MySQL 软件需求提供了易于使用的、基于向导的安装体验。虽然某些特定于开发者的组件可能需要额外安装,但安装程序是您安装最新版本 MySQL 产品的一站式站点,包括:

  • MySQL 服务器

  • MySQL 连接器

  • MySQL 工作台和示例模型

  • 示例数据库

  • MySQL for Excel

  • MySQL 通告程序

  • 面向 Visual Studio 的 MySQL

  • 文件

小费

在 Windows 上安装时,Windows 可能会要求您批准升级安装。

安装程序允许您选择要安装的产品,并且您可以根据需要多次运行安装程序来更新、添加或删除产品。此外,您可以选择基于 web 的安装程序或独立安装程序。如果您在运行 MySQL 安装程序时有在线连接,并且您不想安装所有 MySQL 产品(从而只下载您需要的产品),请选择 web 安装程序。如果在运行 MySQL 安装程序时没有联机连接,或者希望现在或将来安装所有产品,请选择独立安装程序。

您可以在 https://dev.mysql.com/downloads/installer/ 下载 MySQL 安装程序。在该网站上,您将看到最新版本的安装程序,包括安装 32 位或 64 位二进制文件的选项。但是,请注意,安装程序本身是一个 32 位应用。

现在,让我们看一个在 Windows 机器上安装 MySQL 的快速、典型的演练。因为安装程序遵循的脚本会根据您的选择而变化,所以在您的 PC 上安装 MySQL 可能会有所不同。但是,下面显示了从头开始安装 MySQL、安装 InnoDB Cluster 和 MySQL 文档存储所需的所有产品的进度。我们从下载安装程序并启动它开始。图 2-4 显示了初始许可协议屏幕。请注意,这是安装程序的社区版(这意味着它只安装 GNUv2 许可下的社区版产品)。

img/460910_1_En_2_Fig4_HTML.jpg

图 2-4

许可协议(MySQL 安装程序)

阅读并同意许可协议后,您可以勾选“我接受许可条款”复选框,然后单击“下一步”以显示选择安装类型面板,如图 2-5 所示。该面板为您提供了多种选择,包括以开发者为中心的安装、仅安装服务器、仅安装客户端、完全安装所有产品,以及允许您选择要安装哪些组件的自定义选项。选择自定义选项,然后单击下一步。

img/460910_1_En_2_Fig5_HTML.jpg

图 2-5

选择安装类型(MySQL 安装程序)

下一个面板允许您选择要安装的产品。图 2-6 显示了带有 MySQL 服务器的面板和选择安装的文档。要选择要安装的产品,请展开左侧列表中的类别,然后选择要安装的产品,并单击向右箭头将其移动到右侧列表中。右侧列表中显示的产品将在您继续操作时安装。对于本章,您只需要 MySQL 服务器和文档。您将在后面的章节中添加其他产品。当您要安装的产品列在右边时,单击“下一步”按钮。

img/460910_1_En_2_Fig6_HTML.jpg

图 2-6

选择产品和功能(MySQL 安装程序)

下一个面板是安装摘要,允许您确认是否有正确的产品可供安装。图 2-7 所示的面板也显示了状态,以便您可以观察安装进度。当您准备好开始安装所选产品时,请单击执行。

img/460910_1_En_2_Fig7_HTML.jpg

图 2-7

安装对话框–暂存(MySQL 安装程序)

当安装开始时,你会看到每个产品的进度,如图 2-8 所示。

img/460910_1_En_2_Fig8_HTML.jpg

图 2-8

安装对话框–安装进度(MySQL 安装程序)

所有产品安装完成后,安装面板将显示所有安装的状态为完成,并将底部的按钮改为显示下一步,如图 2-9 所示。准备好后,单击下一步。

img/460910_1_En_2_Fig9_HTML.jpg

图 2-9

安装对话框–安装完成(MySQL 安装程序)

安装的下一步是配置任何具有安装后选项的产品。MySQL Server 就是这样一种产品,它允许您设置几个配置项来完成安装。图 2-10 显示了产品配置面板。准备好后,单击“下一步”开始配置。

img/460910_1_En_2_Fig10_HTML.jpg

图 2-10

产品配置(MySQL 安装程序)

MySQL 8.0.11 的 MySQL 安装程序新增了从安装程序设置测试 InnoDB 集群配置的功能。如果您想在测试服务器上安装 MySQL 进行开发或实验,这可以节省大量时间。在第 6 章中,您将采取一种更加谨慎的方式来设置 InnoDB 集群。现在,你可以保留默认选择来安装一个独立的 MySQL 服务器实例,如图 2-11 所示。然后单击下一步按钮。

img/460910_1_En_2_Fig11_HTML.jpg

图 2-11

在沙箱中设置组复制或 InnoDB 集群(MySQL 安装程序)

配置服务器时,第一步是设置网络和配置类型。图 2-12 显示了允许您选择配置类型(包含所选用例典型设置的基线)和任何您希望选择的连接选项的类型和网络面板。

img/460910_1_En_2_Fig12_HTML.jpg

图 2-12

类型和网络–配置服务器(MySQL 安装程序)

在这种情况下,我们将选择开发机器的配置类型(默认)。我们还将选择在端口 3306 上使用 TCP/IP,并打开 Windows 防火墙以允许与网络之间的通信;为此,我们勾选了每个选项旁边的复选框,如图所示。还建议勾选显示高级选项复选框进行进一步配置。选择选项后,单击“下一步”继续。

回想一下,MySQL 在 8.0.4 版中更改了默认的身份验证插件。因为许多安装仍然使用传统的身份验证方法,所以 Oracle 提供了一个选项,在安装过程中选择旧的方法,以便您的应用可以继续使用最新版本。如果您想使用新的身份验证和强密码加密,请保留默认选择,如图 2-13 所示。单击“下一步”按钮继续。

img/460910_1_En_2_Fig13_HTML.jpg

图 2-13

选择验证方法(MySQL 安装程序)

我们需要做的下一件事是为 root 用户帐户选择密码。这是 MySQL 用于所有管理操作的帐户。您应该明智地选择密码,以保护您的服务器免受意外访问。图 2-14 显示了账户和角色面板。请注意,此时您还可以设置其他用户帐户,这样可以节省安装后的时间。准备好后,请单击“下一步”按钮继续。

img/460910_1_En_2_Fig14_HTML.jpg

图 2-14

帐户和角色–配置服务器(MySQL 安装程序)

接下来,我们可以选择设置一个 Windows 服务来管理服务器的启动和停止。这是推荐给任何安装服务器的人的,他们希望服务器从启动开始运行。事实上,您可以选择创建服务,但不能将其设置为自动启动。图 2-15 显示了为服务器设置 Windows 服务的典型选择。选择所需选项后,单击“下一步”按钮继续。

img/460910_1_En_2_Fig15_HTML.jpg

图 2-15

Windows 服务–配置服务器(MySQL 安装程序)

接下来,我们可以选择通过 X 协议插件来启用和配置 MySQL 文档存储。图 2-16 显示了用于启用插件的插件和扩展面板。我们希望启用插件,将端口设置为 33060(默认),并允许端口通过防火墙。选择选项后,单击下一步。

img/460910_1_En_2_Fig16_HTML.jpg

图 2-16

插件和扩展–配置服务器(MySQL 安装程序)

接下来,因为我们选择了高级配置选项,所以我们可以设置各种日志选项,包括错误、查询和二进制日志。您应该考虑打开(选择)常规日志和查询日志。我们还必须启用二进制日志,以便与 InnoDB 集群一起使用。图 2-17 显示了高级选项面板。请注意,您还可以选择命名每个日志并重新定位它们。但是,对于本书,您可以保留默认名称,这些名称基于机器名称。例如,本演练在名为 OPTIPLEX-7010 的计算机上运行,因此文件名具有该前缀。选择选项后,单击下一步。

img/460910_1_En_2_Fig17_HTML.jpg

图 2-17

高级选项(MySQL 安装程序)

此时,安装程序将向您显示要执行的步骤摘要,并允许您开始该过程或返回并进行更改,如图 2-18 所示。准备就绪后,单击执行按钮继续。

img/460910_1_En_2_Fig18_HTML.jpg

图 2-18

应用配置-暂存(MySQL 安装程序)

当配置过程运行时,面板将变灰执行和返回按钮,并在每个步骤旁边的点上显示绿色复选标记,如图 2-19 所示。如果出现错误,面板将显示一个红色 X,如果错误禁止继续,可能会显示一条错误消息。

img/460910_1_En_2_Fig19_HTML.jpg

图 2-19

应用配置-进行中(MySQL 安装程序)

当产品配置完成时,面板将改变为在所有步骤旁边显示绿点。底部的按钮将变为一个标记为完成的按钮,如图 2-20 所示。准备就绪后,单击“完成”按钮继续。

img/460910_1_En_2_Fig20_HTML.jpg

图 2-20

应用配置-完成(MySQL 安装程序)

下一个面板显示了产品配置操作的摘要,如图 2-21 所示。

img/460910_1_En_2_Fig21_HTML.jpg

图 2-21

产品配置–摘要(MySQL 安装程序)

确认无误后,点击下一步按钮进入最后一个面板,如图 2-22 所示。您可以单击“完成”按钮来完成安装并关闭安装程序。

img/460910_1_En_2_Fig22_HTML.jpg

图 2-22

安装完成(MySQL 安装程序)

第一次在 Windows PC 上安装 MySQL 的演练到此结束。如上所述,您可以再次运行安装程序来安装其他产品。还记得,根据所选的产品,显示的面板顺序会有所不同。

摘要

除了添加组复制之外,InnoDB Cluster 可能是那些寻求用 MySQL 构建高可用性解决方案的人最重要的新特性。服务器中从未有过如此多的功能被设计为提供一个健壮、强大、可靠且易于管理的高可用性 MySQL。

在本章中,您了解了有关 InnoDB 存储引擎的更多信息,包括最新的新功能和构成 InnoDB 集群的许多组件,包括组复制、MySQL Shell 和 AdminAPI 以及用于应用连接路由的 MySQL 路由。

在下一章中,您将尝试组复制,并了解更多关于这个奇妙且高度复杂的特性。虽然您将看到 AdminAPI 使配置组复制变得很容易,但是优秀的系统和数据库管理员必须知道组复制是如何工作的,以便他们能够继续改进和扩展他们的高可用性解决方案,并做好排除组复制故障的准备。

Footnotes [1](#Fn1_source)

以及 MySQL 5.7 的部分版本。

 

三、MySQL 组复制

InnoDB 集群的核心是组复制。正如您在前一章中了解到的,组复制是 MySQL 复制的最新发展,旨在使数据复制更加健壮和可靠。与对 InnoDB 存储引擎的修改(全部隐藏在罩下)一起,组复制实现了高可用性功能,而在过去,这需要专门的、有时是定制的产品、中间件和定制的应用才能实现。

在本章中,您将探索从设置到活动组的组复制。这将演示并强化组复制的概念。您可能想知道为什么要在最低的手动配置级别研究这样一个特性,尤其是如果您已经尝试过 InnoDB Cluster 和 MySQL Shell(通过 AdminAPI)。

答案是知识的稳健性。每一个成功的系统或数据库管理员都必须知道产品是如何工作的,而不仅仅是如何设置和运行它们。这是容易的部分,由于有了 AdminAPI,任何人都可以设置 InnoDB 集群。但是,如果出错了,或者需要以不同的方式使用 InnoDB 集群(组复制)怎么办?有了在最低级别设置组复制的经验,您将对将来要做的事情有更深入的了解。

在本章中,您将深入了解组复制的组成部分。之后,您将在导游的带领下参观组复制。跟随我们探索 MySQL 历史上最伟大的进步之一!但是,让我们从组成描述组复制的语言的概念和术语列表开始。

概念、术语和行话

很可能除了最精通或者掌握 MySQL 最新知识的人之外,所有人都将完全理解描述组复制的所有术语和概念。在本节中,您将后退一步,花一点时间关注您将在本章和本书(或任何关于 MySQL 高可用性的书)的其余部分中遇到的一些术语和概念。本节提供了与组复制相关的术语表,您可以随时参考。

  • 二进制日志:服务器产生的文件,包含所有执行的事务的二进制形式。二进制日志文件也用于复制,以便在两台服务器之间交换事务。当在主服务器(master)上使用时,它形成了所有更改的记录,可以发送到辅助服务器(slave)执行以创建副本(有时有点不准确地称为副本)。

  • 多主节点:一个组,其中的写入可以发送到多个主节点,并在组内复制。

  • 故障转移:允许组从主服务器上的故障中恢复的事件,自动选举新的主服务器。

  • 容错:从组中检测到的故障或错误中恢复而不丢失数据或功能的能力。请注意,组复制中的容错能力受到组中服务器数量的限制。参见侧栏“我如何计算一个组可以处理的故障数量?”学习如何计算一个群体可以容忍的错误数量。

  • Group :参与同一个组复制通信设置的一组 MySQL 服务器。

  • 组通信:一种特殊的机制,使用状态机和通信协议来保持组内服务器的协调,包括事务执行的同步和角色的选择/选举。

  • 实例:正在运行的 MySQL 服务器。通常用于指在同一台机器上运行的一个或多个 MySQL 服务器。这和 MySQL 服务器不一样,后者往往指的是硬件和 MySQL 执行的集合。

  • Primary :组中的服务器,被分配收集所有数据写入(更新)的角色。

  • 中继日志:二进制日志文件,在辅助(从)上使用,记录从主(主)二进制日志中读取的事务,缓存以供执行。它的格式与二进制日志相同。

  • 辅助服务器:组中被分配了 reader 角色的服务器,这意味着应用可以从辅助服务器读取数据,但不能写入辅助服务器。

  • 单主:由一台主服务器和一台或多台从服务器组成的组。这类似于旧的 MySQL 复制特性中的主/从配置。

  • 切换:管理员主动改变主服务器角色的受控维护事件,将主服务器从一台服务器上移除,并将其分配给另一台服务器(使新服务器成为主服务器)。这不会自动发生,通常与故障无关。

  • 事务:一组数据更改,在将该组数据应用到数据之前,必须全部成功。失败的事务不会写入数据库。

  • 拓扑:复制组中服务器的逻辑布局。例子包括如下:

    • 单主服务器:单个服务器,与每个从服务器径向连接。

    • 分层:单主服务器组的连接,其中每个辅助服务器都是另一组辅助服务器的主服务器。

    • 多主服务器:每个主服务器连接到组中的所有其他主服务器以及组中的辅助服务器。

注意

回想一下,在 MySQL 复制中,主服务器被命名为主服务器,辅助服务器被命名为从服务器。虽然不完全是同义词,但您可以这样认为,但是在使用 InnoDB 集群和组复制时,一定要重新训练您的思维过程,以使用

概观

MySQL 组复制是 MySQL 复制的一种高级形式,用于实现容错系统。复制组(拓扑)是一组通过消息传递相互交互的服务器。通信层提供了一组保证,如原子消息和全序消息传递。这些强大的属性转化为有用的抽象,可以用来构建更高级的数据库复制解决方案。组复制具有以下优点:

  • 无需手动处理服务器故障转移

  • 提供分布式容错

  • 自动化重新配置(添加/删除实例、故障等)

  • 自动检测和处理冲突

  • 提供防止数据丢失的保证

组复制建立在这样的属性和抽象之上,并实现多主机、到处更新的复制协议。使组复制成为可能的技术之一是全局事务标识符(GTIDs)。因此,参与组复制的服务器将启用 GTIDs。

本质上,一个组由多个服务器组成,组中的每个服务器可以独立执行事务。但是所有读/写(RW)事务只有在得到组的批准后才会提交。只读(RO)事务不需要在组内协调,因此可以立即提交。换句话说,对于任何 RW 事务,组需要决定它是否提交,因此提交操作不是来自发起服务器的单方面决定。

准确地说,当一个事务准备在原始服务器上提交时,服务器自动广播写值(已更改的行)和相应的写集(已更新的行的唯一标识符)。然后为该事务建立全局总订单。最终,所有服务器以相同的顺序接收相同的事务集。因此,所有服务器以相同的顺序应用相同的更改集,并且它们在组内保持一致。

组复制通过在复制组之间复制系统状态来提供冗余。如果一台(或多台)服务器出现故障,系统仍然可用。如果足够多的服务器出现故障,性能或可伸缩性可能会受到影响,但系统将保持可用。

这是通过组成员服务实现的,该服务依赖于分布式故障检测器,当任何服务器通过有意的交互或由于故障而离开组时,该检测器可以发出信号。分布式恢复过程确保当服务器加入组时,它们会自动更新。不需要手动服务器故障转移,多主服务器无处不更新的特性确保了在单个服务器出现故障的情况下,甚至更新也不会被阻止。因此,MySQL 组复制保证了数据库服务的持续可用性。

设置 MySQL 组复制类似于设置 MySQL 复制的过程,这可能不会让您感到惊讶。毕竟,组复制建立在 MySQL 复制的基础上。在下一部分,您将看到组复制的演示。我们不再关注 MySQL 复制教程中的相同步骤,而是简要介绍相同的主题,深入探讨组复制特有的细微差别。

MySQL 组复制教程

本节演示如何在一组服务器之间设置组复制。如前所述,组复制对组中的角色使用不同的术语。具体来说,有一个主要角色和一个次要角色。与将一台服务器指定为主服务器的 MySQL 复制不同,组复制可以根据需要自动更改组中服务器的角色。因此,尽管我们将通过将其中一台服务器标识为主服务器来设置组复制,但是随着时间的推移,组的最终状态可能会导致其他服务器之一成为主服务器。

如果您想自己体验本教程,您应该准备四台服务器。和上一个教程一样,我们将使用当前机器上运行的几个实例。我们需要几个实例来确保该组有一个可行的集合来启用冗余和故障转移。在这种情况下,团队最多可以容忍一次失败。

我如何计算一个组可以处理的故障数量?

确定一组服务器可以容忍多少故障(同时或连续、不可恢复的故障)的公式如下,其中 S 是服务器组,f 是故障数:

S = 2f + 1

例如,一组七个服务器最多可以容忍三个故障:

7 = 2f + 1
6 = 2f
2f = 6
f = 6 / 2
f = 3

如果您想知道容忍已知数量的故障需要多少台服务器,s,F,一个小小的数学应用揭示了以下内容。请注意,您必须向下舍入任何分数。你不能让 1.5 服务器失败。 1

s = 2F + 1
(s – 1) = 2F
2F = (s – 1)
F = (s – 1)/2

例如,一组三个服务器可以容忍一个故障:

F = (31)/2
F = 2 / 2
F = 1

类似地,一组五个服务器可以容忍两个故障:

F = (51)/2
F = 4 / 2
F = 2

本教程中的四台服务器示例只能容忍一个故障:

(41) / 2 = 1.5

或者 1,向下舍入

设置和配置组复制的步骤包括以下内容。可能还有其他同样可行的步骤来设置组复制,但是这些可以在任何机器上完成,并且不会影响 MySQL 的任何现有安装。也就是说,建议在开发机器上执行这些步骤,以消除中断生产系统的风险。

注意

用于设置组复制的步骤类似于 MySQL 复制的步骤。事实上,除了术语(例如, vs. )、配置文件,以及第一次在主服务器上安装组复制插件和启动组复制的两个额外步骤,过程是相同的。

  1. 初始化数据目录。

  2. 配置主服务器。

  3. 配置辅助节点。

  4. 启动 MySQL 实例。

  5. 安装组复制插件。

  6. 创建复制用户帐户。

  7. 在主节点上启动组复制。

  8. 将辅助节点连接到主节点。

  9. 在辅助节点上启动组复制。

  10. 验证组复制状态。

下面几节将更详细地演示在安装了 MySQL 的 Linux 上运行这些步骤。对于其他平台,步骤是相同的,但路径可能略有不同。虽然本教程使用多个本地实例来演示如何使用复制,但是在生产环境中设置复制的过程是相同的。使用特定主机、驱动器、文件夹和端口的各个命令的详细信息是在生产中使用该过程时唯一需要更改的内容。

注意

我们将在示例中使用旧的 MySQL 客户端(mysql)和 SQL 命令。在第 4 章中,你将看到新的 MySQL Shell 的运行,在第 5 章中,你将看到 AdminAPI 的使用。

初始化数据目录

第一步是为使用的每台机器初始化一个数据目录。在这种情况下,我们将在本地计算机上创建一个文件夹来包含所有数据目录。我们将使用四个 MySQL 实例来代表一个主服务器和三个辅助服务器。下面演示了如何创建所需的文件夹。请注意,我在我使用的用户帐户可以访问的本地文件夹中创建这些文件,而不是系统或管理帐户。这是因为我们将在本地运行实例,不需要此类帐户允许的额外特权或访问权限。

$ mkdir gr
$ cd gr
$ mkdir data

现在我们有了一个文件夹<user_home>/gr/data,我们可以使用 MySQL 服务器的初始化选项来设置我们的数据目录,就像我们在 MySQL 复制中所做的一样。回想一下,我们使用服务器的特殊的--initialize-insecure--datadir选项。下面显示了初始化主节点和辅助节点的数据目录所需的命令:

mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/gr/data/primary
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/gr/data/secondary1
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/gr/data/secondary2
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/usr/ --datadir=<user_home>/gr/data/secondary3

现在我们已经创建并填充了数据目录,我们可以配置主服务器和从服务器了。

配置主服务器

这一步与 MySQL 复制最不同。事实上,配置文件有很大的不同。具体来说,除了必须设置的几个更常见的组复制变量之外,我们还使用启用 GTID 的复制中的相同变量。表 3-1 列出了与组复制相关的变量及其用途。控制组复制还有其他变量。参见在线参考手册中的 https://dev.mysql.com/doc/refman/8.0/en/group-replication-options.html 获取完整列表。

表 3-1

组复制变量(配置文件)

|

可变的

|

描述

| | --- | --- | | transaction_write_set_extraction | 定义用于对事务期间提取的写入进行哈希运算的算法。组复制必须设置为 XXHASH64。 | | loose-group_replication_recovery_use_ssl | 确定组复制恢复连接是否应使用 SSL。通常设置为开,但默认为关。 | | loose-group_replication_group_name | 此服务器实例所属的组的名称。必须是有效的 UUID。 | | loose-group_replication_start_on_boot | 确定服务器是否应该在服务器启动期间启动组复制。 | | loose-group_replication_local_address | 成员为来自其他成员的连接提供的网络地址,指定为 host:port 格式的字符串。 | | loose-group_replication_group_seeds | 群组成员列表,用于建立新成员与群组之间的连接。该列表由种子成员的 group _ replication _ local _ address 网络地址组成,以逗号分隔的列表形式指定,例如 host1:port1,host2:port2。 | | loose-group_replication_bootstrap_group | 将此服务器配置为引导组。此选项只能在一台服务器上设置,并且只能在第一次启动组或重新启动整个组时设置。引导组后,将此选项设置为 OFF。 |

注意最后一个变量,group_replication_bootstrap_group。这个变量是我们将在配置文件中设置为OFF的东西,但是只有在我们第一次引导组之后。这是初始主节点的用途之一,用于启动组。您将看到一个特殊步骤,您必须在第一次启动主服务器时执行该步骤,以启动该组。之后,该变量必须设置为OFF

注意

还要注意前缀loose-。这个特殊的前缀适用于变量,用于指示服务器继续启动,如果在服务器启动时插件还没有加载的话。这是一种预防措施,以避免在启动过程中出错。在生产服务器上,不应包括前缀,尤其是在依赖组复制来实现高可用性的情况下。

为了构造主服务器的配置文件,我们需要几样东西:数据目录、基本目录和端口的常用变量,以及 GTID 变量和组复制变量。添加插件目录也是一个好主意,以确保服务器可以找到组复制插件(您将在后面的步骤中看到这一点),并打开二进制日志校验和。

因为group_replication_group_seeds变量需要最初加入该组的服务器列表,所以我们必须决定每个服务器将使用的端口。组复制设置要求每台服务器有两个端口:一个用于正常连接,另一个用于组复制。在本教程中,我们将使用端口24801 +连接服务器,使用端口24901 +连接组复制端口。此外,因为我们使用本地实例,所以组中所有成员的主机名都将使用环回地址(127.0.0.1),但这通常是运行它的服务器的主机名。最后,我们还需要选择服务器 id,所以我们将使用从1开始的连续值。清单 3-1 显示了我们将在本教程中用于主服务器的配置文件。

[mysqld]
datadir=/home/cbell/gr/data/primary
basedir=/usr/
plugin_dir=/usr/lib/mysql/plugin/
port=24801
socket=/home/cbell/gr/primary.sock

server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE

transaction_write_set_extraction=XXHASH64
loose-group_replication_recovery_use_ssl=ON
loose-group_replication_group_name="bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee"
loose-group_replication_start_on_boot=OFF
loose-group_replication_local_address="127.0.0.1:24901"
loose-group_replication_group_seeds="127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903,127.0.0.1:24904"
loose-group_replication_bootstrap_group=OFF

Listing 3-1Primary Configuration File (Group Replication)

您可能会注意到没有设置log-bin变量。当服务器遇到用于组复制的变量时,它将自动启用二进制日志,因为这是必需的。但是,如果您想要命名二进制日志文件或者将它们放在另一个文件夹中,您可以包含变量,但是这是一个高级配置选项,对于教程甚至开发安装来说都不是必需的。

注意

如果您在 Windows 上运行本教程,并且没有安装安全套接字层(SSL ),也没有将 MySQL 配置为使用 SSL 连接,您必须删除group_replication_recovery_use_ssl选项。

对于本教程,您应该在我们之前创建的文件夹中创建一个名为primary.cnf的文件;比如/home/cbell/gr/primary.cnf。在后面的步骤中,我们将使用该文件启动主实例。

现在,让我们看看辅助节点的配置文件。

配置辅助节点

辅助节点的配置文件类似于主节点的配置文件。唯一的变化是为特定于实例的变量(如端口、数据目录、套接字和服务器 ID)使用正确的值。然而,除了这些设置之外,还存在一些差异。transaction_write_set_extraction变量在初始初级上设置。对于辅助节点,我们添加group_replication_recovery_get_public_key并将其设置为ON。此变量确定辅助节点是否向主节点请求基于 RSA 密钥对的密码交换所需的公钥。该变量适用于使用caching_sha2_password身份验证插件进行身份验证的辅助设备。清单 3-2 显示了第一个辅助节点(名为secondary1)的配置文件。

[mysqld]
datadir=/home/cbell/gr/data/secondary1
basedir=/usr/
plugin_dir=/usr/lib/mysql/plugin/
port=24802
socket=/home/cbell/gr/secondary1.sock

server_id=2
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE

loose-group_replication_recovery_get_public_key=ON
loose-group_replication_recovery_use_ssl=ON
loose-group_replication_group_name="bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee"
loose-group_replication_start_on_boot=OFF
loose-group_replication_local_address="127.0.0.1:24902"
loose-group_replication_group_seeds="127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903,127.0.0.1:24904"
loose-group_replication_bootstrap_group=OFF

Listing 3-2Secondary Configuration File (Group Replication)

在本教程中,我们将使用三个辅助节点,因此您应该在我们之前创建的文件夹中为每个节点创建一个文件,并将它们命名为secondary1.cnfsecondary2.cnfsecondary3.cnf。确保更改特定于实例的变量,例如数据目录、套接字、端口、服务器 ID 等等。您必须更改两个端口:服务器端口和组复制端口。

注意

如果您在 Windows 上运行本教程,并且没有安装 SSL 和配置 MySQL 来使用 SSL 连接,您必须删除group_replication_recovery_use_ssl选项。

在本教程中,我们将使用三个辅助节点,因此您应该在我们之前创建的文件夹中为每个节点创建一个文件,并将它们命名为secondary1.cnfsecondary2.cnfsecondary3.cnf。确保更改特定于实例的变量,例如数据目录、套接字、端口、服务器 ID 等等。您必须更改两个端口:服务器端口和组复制端口。

启动 MySQL 实例

现在我们已经准备好启动 MySQL 实例了。这很容易,因为我们已经创建了包含所有所需参数的配置文件。我们只需要提供带有--defaults-file选项的配置文件。下面显示了启动本教程中使用的服务器实例的命令。请注意,添加了一个重定向,将来自服务器的消息放在一个日志文件中。

mysqld --defaults-file=primary.cnf > primary_output.txt 2>&1 &
mysqld --defaults-file=secondary1.cnf > secondary1_output.txt 2>&1 &
mysqld --defaults-file=secondary2.cnf > secondary2_output.txt 2>&1 &
mysqld --defaults-file=secondary3.cnf > secondary3_output.txt 2>&1 &

运行这些命令时,应该从包含配置文件的文件夹中运行它们。否则,您必须提供配置文件的完整路径。尽管这些命令包含重定向,但您可能希望在第一次启动服务器时使用单独的终端,以确保没有错误。清单 3-3 显示了启动主服务器时打印的消息摘录。

$ mysqld --defaults-file=primary.cnf
2018-03-06T16:54:27.768154Z 0 [System] [MY-010116] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) starting as process 6533
2018-03-06T16:54:29.212063Z 0 [Warning] [MY-010068] CA certificate ca.pem is self signed.
2018-03-06T16:54:29.226500Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_recovery_use_ssl=ON'
2018-03-06T16:54:29.226523Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_group_name=bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee'
2018-03-06T16:54:29.226530Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_start_on_boot=OFF'
2018-03-06T16:54:29.226535Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_local_address=127.0.0.1:24901'
2018-03-06T16:54:29.226540Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_group_seeds=127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903,127.0.0.1:24904'
2018-03-06T16:54:29.226549Z 0 [Warning] [MY-011071] unknown variable 'loose-group_replication_bootstrap_group=OFF'
...
2018-03-06T16:54:29.313298Z 0 [System] [MY-010931] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld: ready for connections. Version: '8.0.11'  socket: '/home/cbell/gr/primary.sock'  port: 24801  MySQL Community Server (GPL).

Listing 3-3Starting the Primary Instance

同样,如果您计划使用单个终端,建议将输出重定向到一个文件,并使用选项在另一个进程中启动应用(例如,&符号)。

如果您正在按照本教程进行操作,并且还没有这样做,请继续操作并启动辅助服务器。启动所有服务器实例后,我们可以进入下一步——安装组复制插件。

安装组复制插件

MySQL 实例启动后,您必须安装组复制插件。 2 这只需要一条命令,如果你需要重启服务器,不需要重启插件。下面显示了您用来安装插件的命令。该命令需要插件的名称以及可动态加载的可执行文件的名称。在这种情况下,插件的名称是group_replication,,可加载的可执行文件的名称是group_replication.so:

INSTALL PLUGIN group_replication SONAME 'group_replication.so'

小费

注意文件名中的.so。这是您将用于*nix 平台的扩展。在 Windows 上,文件扩展名是.dll

下面显示了在主节点上执行的命令。请注意,没有其他消息。要检查插件状态,使用SHOW PLUGINS命令或在INFORMATION_SCHEMA.PLUGINS表中搜索插件,如清单 3-4 所示。

$ mysql -uroot -h 127.0.0.1 --port=24801
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.11 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';
Query OK, 0 rows affected (0.09 sec)

mysql> SELECT * FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'group_replication' \G
*************************** 1\. row ***************************
           PLUGIN_NAME: group_replication
        PLUGIN_VERSION: 1.1
         PLUGIN_STATUS: ACTIVE
           PLUGIN_TYPE: GROUP REPLICATION
   PLUGIN_TYPE_VERSION: 1.2
        PLUGIN_LIBRARY: group_replication.so
PLUGIN_LIBRARY_VERSION: 1.9
         PLUGIN_AUTHOR: ORACLE
    PLUGIN_DESCRIPTION: Group Replication (1.1.0)
        PLUGIN_LICENSE: GPL
           LOAD_OPTION: ON
1 row in set (0.01 sec)

mysql> \q
Bye

Listing 3-4Installing and Checking the Group Replication Plugin Status

请注意,当安装插件时,我们只得到一个粗略的 OK 消息。如果配置文件中的插件目录错误或者插件可执行文件丢失,那么在运行该命令时会出现错误。如果发生这种情况,使用SHOW VARIABLES LIKE 'plugin_dir';检查插件目录。然后关闭服务器,确保可执行文件在插件目录中,并且插件目录是配置文件中的正确值。

对于插件状态,我们期望从SELECT查询中获得一行,并看到状态被设置为ACTIVE。如果您看到另一个状态,请确保插件安装正确,并且是您安装的 MySQL 版本的正确插件。如果你安装了多个版本的 MySQL,很容易错误地将插件目录指向错误的插件。

注意

在开始组复制之前,必须在每个服务器实例上运行这些命令。

这是前面在比较启动组复制和 MySQL 复制时提到的额外步骤。如果您遵循本教程,现在执行这些语句在所有四个实例上安装插件。当插件加载到所有实例上时,您可以继续在所有实例上创建复制用户。

创建复制用户帐户

MySQL 实例启动后,您必须创建一个用户,供服务器相互连接使用。回想一下,在组复制中,服务器都相互“对话”。幸运的是,这些命令与我们在 MySQL 复制中使用的命令相同。我们需要在所有服务器实例上创建这个用户。下面显示了创建复制用户所需的命令。在所有服务器上执行以下命令:

SET SQL_LOG_BIN=0;
CREATE USER rpl_user@'%' IDENTIFIED BY 'rpl_pass';
GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;

注意主机名中使用了%。这样做是为了确保复制用户可以从任何服务器连接。对于生产环境,您通常不会这样做,但是对于教程或开发测试,这使事情变得简单了一些。

回想一下,set sql_log_bin=0命令告诉服务器暂时禁止记录对二进制日志的更改。每当我们不想在拓扑中的其他机器上复制命令时,我们就这样做。具体来说,不应复制维护和管理命令,如创建用户。关闭二进制日志是确保您不会意外发出无法在其他机器上执行的事务的好方法。

执行这些命令的最佳方式是将它们保存到名为create_rpl_user.sql的文件中,并使用mysql客户端的源命令从文件中读取命令并执行它们。您可以使用以下命令在所有实例上快速创建复制用户。

注意

本节中的路径使用主目录/home/cbell/。请确保替换用户目录的路径。

mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/create_rpl_user.sql" --port=24801
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/create_rpl_user.sql" --port=24802
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/create_rpl_user.sql" --port=24803
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/create_rpl_user.sql" --port=24804

在主节点上启动组复制

下一步是首次在主节点上启动组复制。回想一下我们对组复制变量的讨论,变量group_replication_bootstrap_group通常被设置为OFF,除非在组的第一次启动时。因为该组从未启动过,所以我们必须在主服务器上启动。

幸运的是,变量group_replication_bootstrap_group是动态的,我们可以动态地打开和关闭它。我们可以在主节点上运行以下命令来首次启动组复制:

SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;

您可能还记得,我们在主配置文件中将group_replication_bootstrap_group设置为OFF。这样,如果我们重新启动主服务器,设置将是正确的。如果您愿意,您可以将它设置为ON,但是您必须在重新启动主服务器之前在配置文件中更改它。设置为OFF安全多了,工作量也少了。

如果您正在学习本教程,那么现在就在主服务器上运行这些命令。完成后,您就可以将辅助节点连接到主节点了。

将辅助节点连接到主节点

下一步是将辅助节点连接到主节点。我们使用你在之前的教程中看到的相同的CHANGE MASTER命令。但是,我们只需要复制用户和密码。我们告诉服务器连接到名为group_replication_recovery的特殊复制通道。下面显示了用于将每个辅助节点连接到主节点的命令:

CHANGE MASTER TO MASTER_USER="rpl_user", MASTER_PASSWORD="rpl_pass" FOR CHANNEL 'group_replication_recovery';

注意

您可能会看到关于在命令中使用密码的警告。这是为了鼓励您不要将复制用户和密码放在文件中。使用可插拔身份验证选项更安全。

请注意,我们需要的信息甚至比启用了 GTID 的复制还要少。酷!您必须在所有辅助节点上运行该命令。将它保存到一个文件并使用mysql客户机执行它可能更容易,就像我们对复制用户所做的那样。例如,将它保存到一个名为change_master.sql的文件中,并如下所示执行它:

mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/change_master" --port=24802
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/change_master" --port=24803
mysql -uroot -h 127.0.0.1 -e "source /home/cbell/gr/change_master" --port=24804

现在,我们已经将辅助节点配置为连接到主节点,我们必须通过启动组复制来完成该过程。

在辅助节点上启动组复制

下一步是在辅助节点上启动组复制。组复制使用命令START GROUP_REPLICATION,而不是像 MySQL 复制那样使用START SLAVE命令。在每个辅助节点上运行此命令,如下所示:

mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24802
mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24803
mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24804

START GROUP_REPLICATION命令通常不会报告任何错误,可能需要更长时间才能返回。这是因为当辅助节点连接到主节点并开始与主节点协商时,许多事情都在后台进行。然而,与 MySQL 复制不同,您不能使用SHOW SLAVE STATUS来检查状态。事实上,发出那个命令不会得到任何结果。你是做什么的?

验证组复制状态

组复制重新设计了我们监控复制服务的方式。组复制向performance_schema数据库添加了几个视图,您可以使用这些视图来监控组复制。那里有很多信息,如果你有兴趣,你可以查看 https://dev.mysql.com/doc/refman/8.0/en/group-replication-monitoring.html 来了解更多关于视图及其包含的内容。

检查组复制状态需要针对performance_schema视图发出查询。replication_group_members视图(table)用于监控在当前视图中被跟踪的服务器实例的状态,换句话说,这些服务器实例是组的一部分,因此由成员资格服务进行跟踪。该信息在作为复制组成员的所有服务器实例之间共享,因此可以从任何成员处查询所有组成员的信息。清单 3-5 展示了该命令的实际应用。

$ mysql -uroot -h 127.0.0.1  --port=24802
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 34
Server version: 8.0.11 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW SLAVE STATUS\G

Empty set (0.00 sec)

mysql> SELECT * FROM performance_schema.replication_group_members \G
*************************** 1\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 21e6463c-4330-11e8-bc61-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24801
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.11
*************************** 2\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2854aecd-4330-11e8-abb6-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24802
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
*************************** 3\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2ecd9f66-4330-11e8-90fe-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24803
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
*************************** 4\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 3525b7be-4330-11e8-80b1-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24804
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
4 rows in set (0.01 sec)

Listing 3-5Checking Group Replication Status

注意,我们运行了SHOW SLAVE STATUS命令,但没有得到任何回报。Drat。然而,当我们查询视图时,我们得到大量信息,包括组中每个成员的当前状态。有趣的是,您可以对组中的任何成员运行这个查询。这显示了组复制如何将元数据传播到组中的所有成员。

您还可以缩小输出范围,以获得更令人满意的视图,仅包括成员主机、端口、状态和角色,如下所示:

mysql> SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members;
+-------------+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
+-------------+-------------+--------------+-------------+
| oracle-pc   |       24801 | ONLINE       | PRIMARY     |
| oracle-pc   |       24802 | ONLINE       | SECONDARY   |
| oracle-pc   |       24803 | ONLINE       | SECONDARY   |
| oracle-pc   |       24804 | ONLINE       | SECONDARY   |
+-------------+-------------+--------------+-------------+

如果您只想定位主节点,可以对任何组成员使用以下查询:

SELECT member_id, member_host, member_port FROM performance_schema.global_status JOIN performance_schema.replication_group_members ON VARIABLE_VALUE=member_id WHERE VARIABLE_NAME="group_replication_primary_member";

当您对组中的任何一个成员执行此查询时,您将看到主服务器的 UUID:

+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 21e6463c-4330-11e8-bc61-d4258b76e981 | oracle-pc   |       24801 |
+--------------------------------------+-------------+-------------+

您应该将这些 SQL 语句放在一个名为check_gr.sql的文件中,以便我们稍后可以在脚本中使用它来自动设置组复制。

现在我们已经运行了组复制,让我们创建一些数据。我们将使用与上一教程中相同的样本数据。但是,这一次,我们将在其中一个辅助节点上执行查询。你预计会发生什么?如果您从 MySQL 复制的角度考虑,您可能希望数据只出现在一个辅助服务器上。让我们看看会发生什么。以下代码在其中一个辅助节点上执行数据查询:

$ mysql -uroot -h 127.0.0.1  --port=24802
Welcome to the MySQL monitor.  Commands end with ; or \g.
...
mysql> CREATE DATABASE test;
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

为什么会出现这个错误?原来,每个辅助都是以super-read-only开始的,解决了拥有“超级”能力的用户能够写入副本的老问题;super-read-only=OFF禁止任何人写入副本。因此,(从 MySQL 复制)向从属服务器发送写操作的常见问题得到了解决。万岁。使用super-read-only还表明我们正在单主模式下运行组复制(这是默认模式)。当我们在后面的章节中探索 InnoDB 集群的细微差别时,您将看到其他模式。

回到我们创建一些数据的测试,让我们在主服务器上运行相同的命令。下面显示了预期的结果:

$ mysql -uroot -h 127.0.0.1  --port=24801
...
mysql> CREATE DATABASE test;
Query OK, 1 row affected (0.03 sec)

mysql> USE test;
Database changed
mysql> CREATE TABLE test.t1 (id INT PRIMARY KEY, message TEXT NOT NULL);
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO test.t1 VALUES (1, 'Chuck is here');
Query OK, 1 row affected (0.01 sec)

在这里,我们看到数据是创建的。现在,检查第二个。下面显示了在辅助节点上运行查询的结果。如您所见,数据已经被复制。

$ mysql -uroot -h 127.0.0.1  --port=24802
...
mysql> SELECT * FROM test.t1;
+----+----------------+
| id | message        |
+----+----------------+
|  1 | Chuck is here. |
+----+----------------+
1 row in set (0.00 sec)

您应该将四个 SQL 命令— CREATE DATABASECREATE TABLEINSERTSELECT—放到一个名为sample_data.sql的文件中,我们将在稍后的脚本中使用它来自动设置组复制。

故障转移演示

现在我们有了一个工作组复制设置,让我们看看自动故障转移是如何工作的。如果您还没有运行前面的教程,并且想继续学习,请确保先运行前面的步骤。

自动故障切换是组复制的内置功能。通信机制确保监控主节点(在单主节点配置中)的活动,并且当主节点不再可用或出现严重问题时,该组可以决定终止主节点连接并选举新的主节点。

让我们看看这是如何工作的。回想一下前面的教程,我们在端口 24801 上运行初始主服务器。我们可以通过终止该服务器的 MySQL 进程来模拟失败。因为我们运行在 Linux 上,所以我们可以通过检查进程 ID 文件来确定进程 ID,MySQL 在数据目录中用机器名和文件扩展名.pid创建该文件。例如,教程中显示的主文件在data/primary/oracle-pc.pid中。该文件使用机器命名,并存储在数据目录中。您系统的文件将被不同地命名。下面演示了如何找到进程 ID 并停止它。请注意,您可能需要超级用户权限来终止该进程。

$ more ./data/primary/oracle-pc.pid
18019
$ sudo kill -9 18019

小费

在 Windows 上,您可以使用任务管理器终止该进程。

既然主服务器已经关闭,我们可以使用前面的查询来查看组的运行状况。回想一下,我们使用包含查询的check_gr.sql文件。清单 3-6 显示了查询的输出。

$ mysql -uroot -h 127.0.0.1 --port=24802 -e "source check_gr.sql"
*************************** 1\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2854aecd-4330-11e8-abb6-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24802
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.11
*************************** 2\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2ecd9f66-4330-11e8-90fe-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24803
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
*************************** 3\. row ***************************
  CHANNEL_NAME: group_replication_applier

     MEMBER_ID: 3525b7be-4330-11e8-80b1-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24804
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 2854aecd-4330-11e8-abb6-d4258b76e981 | oracle-pc   |       24802 |
+--------------------------------------+-------------+-------------+

Listing 3-6Checking Group Health After the Primary Goes Down

请注意,该组已经自动选择了一个新的主服务器(在端口 24802 上),现在该组中只有三台服务器。因此,写入功能不会有任何损失。但是,回想一下前面的讨论,该组只能容忍这么多的故障,达到该限制后,该组将无法再成功进行故障切换,在这种情况下,该组可能不具备容错能力。清单 3-7 显示了第二台和第三台主机停止后同一组的状态。请注意,最后一个主节点的状态未知。

$ mysql -uroot -h 127.0.0.1 --port=24804 -e "source check_gr.sql"
*************************** 1\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2ecd9f66-4330-11e8-90fe-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24803
  MEMBER_STATE: UNREACHABLE
   MEMBER_ROLE: PRIMARY

MEMBER_VERSION: 8.0.11
*************************** 2\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 3525b7be-4330-11e8-80b1-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24804
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 2ecd9f66-4330-11e8-90fe-d4258b76e981 | oracle-pc   |       24803 |
+--------------------------------------+-------------+-------------+

Listing 3-7State of the Group When No More Primary Servers Remain

既然我们已经看到了故障转移的实际应用,那么让我们来看看如何自动化本教程,以便我们可以进一步(并且更容易地)进行实验。

DevOps 脚本

如果您和我一样,想要使您的开发生活更容易,您可能会想要使用一个脚本来协调启动和停止一个实验组复制设置。幸运的是,在这种情况下我们可以这样做,因为我们使用的是本地实例,因此确切地知道应该使用什么样的服务器 id、IP 地址和端口。清单 3-8 是为 Linux 操作系统编写的脚本。

#!/bin/sh
# This file contains the setup commands used to start the tests for using MEB'
# with GR. Specifically, this file contains commands to start (4) mysqld
# instances and establish group replication among them.
#
# Note: All of the files reside in a local directory such as /home/cbell/# gr_linux. If you wish to run these commands, substitute the correct
#       directory in the commands.
#
# Note: Change the user to your user account or appropriate surrogate.
#
# The instances are primary (primary), secondary1, secondary2, secondary3 # (secondaries). Each is started with a corresponding config file, which is
# expected to be in the base directory. Each instance uses a different
# port but runs on the local machine.
#
# The steps include:
# 1) initialize the data directories
# 2) launch all mysqld instances
# 3) install the GR plugin
# 4) create the replication user
# 5) start GR
# 6) check GR
# 7) create initial data

echo ====== Step 1 of 7: INITIALIZE DATA DIRECTORIES ======

cd /home/cbell/gr_linux
rm -rf /home/cbell/gr_linux/data
mkdir /home/cbell/gr_linux/data
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/home/cbell/source/git/mysql-bug-staging/build/ --datadir=/home/cbell/gr_linux/data/primary
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/home/cbell/source/git/mysql-bug-staging/build/ --datadir=/home/cbell/gr_linux/data/secondary1
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/home/cbell/source/git/mysql-bug-staging/build/ --datadir=/home/cbell/gr_linux/data/secondary2
mysqld --no-defaults --user=cbell --initialize-insecure --basedir=/home/cbell/source/git/mysql-bug-staging/build/ --datadir=/home/cbell/gr_linux/data/secondary3

echo ====== Step 2 of 7: START ALL INSTANCES ======

cd /home/cbell/gr_linux
rm *.sock*
mysqld --defaults-file=/home/cbell/gr_linux/primary.cnf > primary_output.txt 2>&1 &
mysqld --defaults-file=/home/cbell/gr_linux/secondary1.cnf > secondary1_output.txt 2>&1 &
mysqld --defaults-file=/home/cbell/gr_linux/secondary2.cnf > secondary2_output.txt 2>&1 &
mysqld --defaults-file=/home/cbell/gr_linux/secondary3.cnf > secondary3_output.txt 2>&1 &

sleep 5

echo ====== Step 3 of 7: INSTALL THE GR PLUGIN ======

mysql -uroot -h 127.0.0.1 -e "INSTALL PLUGIN group_replication SONAME 'group_replication.so'" --port=24801
mysql -uroot -h 127.0.0.1 -e "INSTALL PLUGIN group_replication SONAME 'group_replication.so'" --port=24802
mysql -uroot -h 127.0.0.1 -e "INSTALL PLUGIN group_replication SONAME 'group_replication.so'" --port=24803
mysql -uroot -h 127.0.0.1 -e "INSTALL PLUGIN group_replication SONAME 'group_replication.so'" --port=24804

echo ====== Step 4 of 7: CREATE THE REPLICATION USER ======

mysql -uroot -h 127.0.0.1 -e "source create_rpl_user.sql" --port=24801
mysql -uroot -h 127.0.0.1 -e "source create_rpl_user.sql" --port=24802
mysql -uroot -h 127.0.0.1 -e "source create_rpl_user.sql" --port=24803
mysql -uroot -h 127.0.0.1 -e "source create_rpl_user.sql" --port=24804

echo ====== Step 5 of 7: START GR ======

mysql -uroot -h 127.0.0.1 -e "source start_gr_primary.sql" --port=24801
mysql -uroot -h 127.0.0.1 -e "source change_master.sql" --port=24802
mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24802
mysql -uroot -h 127.0.0.1 -e "source change_master.sql" --port=24803
mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24803
mysql -uroot -h 127.0.0.1 -e "source change_master.sql" --port=24804
mysql -uroot -h 127.0.0.1 -e "START GROUP_REPLICATION" --port=24804

echo ====== Step 6 of 7: CHECK GR ======

echo "Waiting for GR to start and reconcile..."
sleep 5

mysql -uroot -h 127.0.0.1 -e "source check_gr.sql" --port=24801

echo ====== Step 7 of 7: CREATE SOME DATA ======

sleep 30

mysql -uroot -h 127.0.0.1 -e "source sample_data.sql" --port=24801
mysql -uroot -h 127.0.0.1 -e "SELECT * FROM test.t1" --port=24801

echo ====== SETUP COMPLETE ======

Listing 3-8DevOps Script to Start Group Replication (Linux)

花一些时间来研究这个脚本。您应该能够通过一些小的改动使它适应您自己的平台。例如,如果您使用的不是默认的 MySQL 安装,您可能需要提供可执行文件的路径,或者类似地,您可能需要修改设置各种目录的配置文件。

当您执行这个脚本时,您将看到类似于清单 3-9 的输出。请注意,这与我们在教程中遇到的输出相同。

$ ./setup_gr.sh
====== Step 1 of 7: INITIALIZE DATA DIRECTORIES ======
2018-04-18T17:44:19.902106Z 0 [System] [MY-013169] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server in progress as process 17828
2018-04-18T17:44:24.306322Z 4 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2018-04-18T17:44:2    9.133321Z 0 [System] [MY-013170] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server has completed
2018-04-18T17:44:30.615437Z 0 [System] [MY-013169] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server in progress as process 17876
2018-04-18T17:44:35.248184Z 4 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2018-04-18T17:44:40.080563Z 0 [System] [MY-013170] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server has completed
2018-04-18T17:44:41.589196Z 0 [System] [MY-013169] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server in progress as process 17925
2018-04-18T17:44:45.912417Z 4 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2018-04-18T17:44:50.810105Z 0 [System] [MY-013170] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server has completed
2018-04-18T17:44:52.246658Z 0 [System] [MY-013169] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server in progress as process 17971
2018-04-18T17:44:56.781545Z 4 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2018-04-18T17:45:01.652505Z 0 [System] [MY-013170] [Server] /home/cbell/source/git/mysql-bug-staging/build/bin/mysqld (mysqld 8.0.11) initializing of server has completed
====== Step 2 of 7: START ALL INSTANCES ======
rm: cannot remove '*.sock*': No such file or directory
====== Step 3 of 7: INSTALL THE GR PLUGIN ======
====== Step 4 of 7: CREATE THE REPLICATION USER ======
====== Step 5 of 7: START GR ======
====== Step 6 of 7: CHECK GR ======
Waiting for GR to start and reconcile...
*************************** 1\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 21e6463c-4330-11e8-bc61-d4258b76e981

   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24801
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.11
*************************** 2\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2854aecd-4330-11e8-abb6-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24802
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
*************************** 3\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 2ecd9f66-4330-11e8-90fe-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24803
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
*************************** 4\. row ***************************
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: 3525b7be-4330-11e8-80b1-d4258b76e981
   MEMBER_HOST: oracle-pc
   MEMBER_PORT: 24804
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.11
+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 21e6463c-4330-11e8-bc61-d4258b76e981 | oracle-pc   |       24801 |
+--------------------------------------+-------------+-------------+
====== Step 7 of 7: CREATE SOME DATA ======
+----+----------------+
| id | message        |
+----+----------------+
|  1 | Chuck is here. |
+----+----------------+
====== SETUP COMPLETE ======

Listing 3-9Executing the setup_gr.sh Script (Linux)

还有一个相应的关机脚本,如清单 3-10 所示。你可以用这个来快速关闭群。

# This file contains commands to shut down and destroy the test GR cluster as
# set up by the commands in gr_meb_setup.txt.
#
# Note: the primary is expected to be p1, but it doesn't matter as the data
#       directories are destroyed at the end
#
# The steps include:
# 1) issue STOP GROUP_REPLICATION on all secondary servers
# 2) issue STOP GROUP_REPLICATION on the primary
# 3) shut down all mysqld instances
# 4) destroy the data directories

echo ====== Step 1 of 4: STOP GROUP REPLICATION ON SECONDARIES ======
mysql -uroot -h 127.0.0.1 --port=24802 -e "STOP GROUP_REPLICATION"
mysql -uroot -h 127.0.0.1 --port=24803 -e "STOP GROUP_REPLICATION"
mysql -uroot -h 127.0.0.1 --port=24804 -e "STOP GROUP_REPLICATION"

echo ====== Step 2 of 4: STOP GROUP REPLICATION ON PRIMARY ======

mysql -uroot -h 127.0.0.1 --port=24801 -e "STOP GROUP_REPLICATION"

echo ====== Step 3 of 4: SHUTDOWN mysqld INSTANCES ======

mysql -uroot -h 127.0.0.1 --port=24802 -e "SHUTDOWN"
mysql -uroot -h 127.0.0.1 --port=24803 -e "SHUTDOWN"
mysql -uroot -h 127.0.0.1 --port=24804 -e "SHUTDOWN"
mysql -uroot -h 127.0.0.1 --port=24801 -e "SHUTDOWN"

echo ====== Step 4 of 4: DESTROY THE DATA DIRECTORIES ======

cd /home/cbell/gr_linux
rm -rf data/

echo ====== SHUTDOWN COMPLETE ======

Listing 3-10DevOps Shutdown Script (Linux)

当您运行这个脚本时,您只会看到关于进度的粗略陈述。如果您看到连接错误,这通常是正常的。这只是意味着客户端无法连接。在为已经关闭的服务器运行shutdown的情况下,这是意料之中的。

$ ./shutdown.sh
====== Step 1 of 4: STOP GROUP REPLICATION ON SECONDARIES ======
====== Step 2 of 4: STOP GROUP REPLICATION ON PRIMARY ======
====== Step 3 of 4: SHUTDOWN mysqld INSTANCES ======
====== Step 4 of 4: DESTROY THE DATA DIRECTORIES ======
====== SHUTDOWN COMPLETE ======

小费

本书的源代码包含了在 Ubuntu、macOS 和 Windows 上使用这些脚本的例子。

关于设置 MySQL 组复制的简短教程到此结束。本节用最简洁的术语简要介绍了组复制。

摘要

不可否认,组复制是 MySQL 高可用性的一次飞跃。然而,正如你在本章的教程中看到的,设置起来并不简单。虽然那些熟悉 MySQL 复制的人会认为这个过程是一样的,只是多了几个额外的步骤,但那些不熟悉 MySQL 和高可用性的人可能会觉得学习曲线非常陡峭。

本章提供了组复制的基础知识,以及在最初和一两次故障期间设置和维护组的方法。如果你也认为一定有更好的方法,那就有了——而且我们就快成功了!

在下一章中,我们将暂时停止探索 InnoDB 集群的更多技术细节,并看看令人兴奋的新 MySQL 客户端:MySQL Shell。

Footnotes [1](#Fn1_source)

随机重启机器在这里不被认为是一个小部分。

  2

MySQL 的未来版本可能会默认加载该插件。