Python-MySQL-Shell-入门指南-四-

134 阅读1小时+

Python MySQL Shell 入门指南(四)

原文:Introducing MySQL Shell

协议:CC BY-NC-SA 4.0

八、将 Shell 用于组复制

MySQL 内置的最先进的特性之一是它能够将两台或多台服务器连接在一起,其中所有服务器都维护数据的副本(复制品)以实现冗余。管理基础设施的数据库管理员和系统架构师了解在尽量减少维护工作量的同时构建冗余的必要性。用于实现这一点的工具之一是一类使服务器或服务尽可能可用的特性。我们称之为高可用性(HA)。

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

在这一章中,我们将大致了解如何在 MySQL 中设置、配置和维护高可用性。由于高可用性是一个很大的主题,需要考虑很多方面,我们将首先简要介绍一下高可用性——它是什么以及它是如何工作的,然后是 MySQL 的高可用性功能——我们将了解基本复制是如何工作的。然后,在下一章中,wxe 将看到如何在您自己的系统上用 MySQL Shell 设置和配置 MySQL 组复制的演示。

小费

本章通过学习经典复制为您开始使用 MySQL 组复制做准备。如果您熟悉 MySQL 复制,知道如何使用二进制日志文件设置经典复制,并且知道什么是全局事务标识符(GTIDs ),您可能希望浏览本章。

概观

MySQL 高可用性是建立在 MySQL 复制的长期稳定性之上的组件集合。这些组件包括对服务器的修改以及新的特性和组件,如全局事务标识符、对核心复制特性集的大量改进,以及 MySQL 组复制的添加,因此也是组复制。这些组件共同构成了 MySQL 高可用性的新范例。

正如您将看到的,在 MySQL 中使用高可用性有相当多的功能和几种选择。让我们从一个关于高可用性的简短教程开始。

什么是高可用性?

如果您认为高可用性大致等同于可靠性,那么高可用性就最容易理解了——使解决方案尽可能易于访问,并在约定的时间内容忍计划内或计划外的故障。也就是说,这是用户对系统可操作性的期望值。系统越可靠,运行时间越长,就相当于可用性水平越高。

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

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

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

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

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

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

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

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

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

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

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

  • 扩展:另一个可靠性实现与性能有关。在这种情况下,您希望最大限度地减少存储和检索数据的时间。您可以通过设计解决方案将数据写入(保存)到主设备(主设备)并从从设备(辅助设备)读取数据来实现这一点。随着应用的增长,您可以添加额外的从机来帮助最小化读取数据的时间。通过拆分写和读,可以减轻主机执行许多语句的负担。考虑到大多数应用的读操作比写操作多得多,使用不同的服务器(或几个服务器)来提供读操作的数据并将写操作留给一个主服务器是有意义的。

  • 容错:可靠性的最后一个实现,也是区分大多数高可用性解决方案正常运行时间的关键是容错,即检测故障并从事件中恢复的能力。容错是通过利用恢复和冗余以及添加检测机制和主动切换来实现的。也就是说,当一个组件出现故障时,另一个组件会取代它的位置。容错的最佳形式是实现自动切换(故障转移),即使单个组件出现故障,应用也能继续运行。

注意

横向扩展有两种形式:读取和写入。您可以使用冗余读取器(如 MySQL 复制中的多个从属读取器)实现读取扩展,但是实现写入扩展需要一个可以在两台或更多服务器上协商和处理更新的解决方案。幸运的是,我们有 MySQL 组复制。我们将在后面的章节中看到更多关于这个特性的内容。

MySQL 高可用性特性

MySQL 有几个高可用性特性,可以满足这些技术及其目标中更具挑战性的部分。下面总结了可以用于上述每种技术的功能。

  • 恢复 : MySQL 复制提供了一种通过副本来提供恢复的机制。如果主服务器关闭,可以提升一个从服务器来承担其角色。

    • 逻辑备份:客户端实用程序mysqlpump(或者更老的mysqldump)可以用来对你的数据进行逻辑备份,以便以后恢复。请注意,这些工具面临着逻辑备份的所有挑战。具体来说,它们将数据库转储到一个由 SQL CREATEINSERT语句构成的文件中,因此它们可能不是大型数据集的最佳选择。

    • 物理备份:MySQL 企业版提供了一个名为 MySQL 企业备份的工具,可以用来为你的数据创建物理备份,并进行恢复。

  • 冗余:通过使用多个从服务器,MySQL 复制可以通过某些技巧和窍门实现一定的冗余,例如使用一个与主服务器硬件相同的专用从服务器(称为热备用),或者使用多个从服务器来确保您始终有足够的数据读取权限。

  • 扩展:同样,MySQL 复制可以为您的应用提供读取扩展。使用 MySQL 组复制实现写入横向扩展。

  • 容错:可以使用 MySQL 复制来实现切换。也就是说,当主服务器关闭时,我们使用 MySQL 中的复制命令将主服务器的角色切换到一个从服务器。使用 MySQL 时,有两种类型的主角色变化:切换,即当主服务器仍在运行时,将主服务器的角色切换到从服务器;故障转移,即当主服务器不再运行时,选择从服务器来承担主服务器的角色。也就是说,切换是有意的,而故障转移是被动的。但是,您可以使用允许自动故障转移的组复制。

注意

还有 MySQL 路由器,它是 MySQL 的连接路由器,允许您设置路由器使用的一组特定服务器,以便路由器在当前服务器离线(变得不可访问)时自动切换到另一台服务器。幸运的是,组复制和路由器都是 InnoDB 集群的一部分,我们将在第十章中探讨。

现在我们知道了什么是高可用性,以及实现高可用性的一些技术和目标,让我们深入了解基本的高可用性特性——MySQL 复制。

什么是 MySQL 复制?

MySQL 复制是一个易于使用的特性,也是 MySQL 服务器的一个复杂和主要的组件。本节提供了复制的鸟瞰图,目的是解释其功能。我们将在下一节看到一个设置 MySQL 复制的例子。

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

复制机制使用一种称为二进制日志的技术工作,该技术以特殊的格式存储更改,从而保留所有更改的记录。这些更改随后被发送到从机,在那里更改被存储在类似的日志文件(称为中继日志)中,然后在从机上读取并执行。因此,一旦从机执行了更改(称为事件),它就拥有了数据的精确副本。

在最低级别,主服务器和从服务器之间的二进制日志交换支持三种格式:基于语句的复制(SBR),它复制整个 SQL 语句;基于行的复制(RBR),仅复制已更改的行;对于某些场景,混合式复制(MBR)是 RBR 与使用 SQL 语句记录的一些事件的混合。

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

MySQL 复制支持两种复制方法。最初的方法(有时称为经典复制、二进制日志文件和位置复制,或简称为日志文件和位置复制)涉及使用二进制日志文件名和位置来跟踪和执行事件,或应用更改以在主设备和从设备之间同步数据。较新的事务性方法使用全局事务标识符(GTIDs ),因此不需要处理日志文件或位置(但它仍然使用相同的二进制日志和中继日志文件),这大大简化了许多常见的复制任务。最重要的是,使用 gtid 的复制保证了主设备和从设备之间的一致性,因为当从设备连接到主设备时,新协议允许从设备请求丢失的 gtid。因此,每个从设备可以与主设备协商接收丢失的事件。

什么是 GTIDs?

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

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

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

小费

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

什么是组复制?

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

组复制建立在现有复制属性和抽象的基础上,并实现多主机、随处更新的复制协议。使组复制成为可能的技术之一是 GTIDs。因此,参与组复制的服务器必须启用 GTIDs。

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

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

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

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

组复制使得拓扑最终同步复制(在属于同一个组的节点之间)成为现实,而现有的 MySQL 复制特性是异步的(或者最多是半同步的)。因此,可以提供更好的高可用性保证,因为事务以相同的顺序交付给所有成员(尽管在被接受后在每个成员中以自己的速度应用)。

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

组复制还可以与 MySQL 路由器一起使用,以实现应用级路由和操作容错(在应用级)。图 8-1 显示了您将如何在我们的应用中使用组复制来实现高可用性。

img/478423_1_En_8_Fig1_HTML.jpg

图 8-1

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

请注意,组复制可以与 MySQL 路由器一起使用,以允许您的应用拥有一个与集群隔离的层。当我们在第 10 和 11 章中研究 InnoDB 集群时,我们会看到一些关于路由器的内容。

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

使用组复制中内置的三种特定技术,可以实现这些功能以及更多功能:组成员资格、故障检测和容错。下面列出了这些技术,并对每种技术进行了简要概述。

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

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

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

小费

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

现在我们对 MySQL 复制和组复制有了更多的了解,让我们来看一个关于如何设置和配置 MySQL 复制的简短入门。我们将把它作为下一章的跳板,在下一章中,我们将使用 MySQL Shell 配置组复制。

设置和配置

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

注意

术语“主服务器”和“从服务器”专门用于 MySQL 复制,表示只有一个服务器可以写入,因此拥有“主”副本。其余的服务器是只读的,包含数据的副本。在组复制中,这些术语被更改为“主”和“次”,以便更好地描述新功能中的角色。

但是首先,您需要在使用不同端口的系统上、在另外两个系统上或者在两个虚拟机上运行两个 MySQL 实例。对于大多数情况下的探索,在本地计算机上运行多个 MySQL 实例会很好。

启动实例时,必须设置一些复制的先决条件。建议您为每个实例创建一个单独的配置文件(在 Windows 中为my.cnfmy.ini),这样您就不会冒险为两个实例使用相同的目录。为此,我们应该已经在系统上安装了 MySQL。

启动一个新的 MySQL 实例很容易,只需要几个管理任务。以下是这些任务的概要。

  • 数据目录:您必须创建一个文件夹来包含数据目录。

  • 端口:您必须为每个实例选择一个端口。

  • 配置文件:您必须为每台服务器创建一个单独的配置文件。

  • 手动启动实例:要运行实例,您将从命令行(或通过批处理文件)启动 MySQL (mysqld ),指定正确的配置文件。

我们将在下一节中看到这些步骤以及更多演示,下一节将介绍如何在本地计算机上设置和运行 MySQL 复制的教程。

辅导的

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

注意

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

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

  • 初始化数据目录:创建文件夹存储数据。

  • 配置主机:用二进制日志,新配置文件配置主机。

  • 配置从机:用二进制日志,新配置文件配置从机。

  • 启动 MySQL 实例:启动 MySQL 服务器实例。

  • 创建复制用户帐号:在所有服务器上创建复制用户。

  • 将从机连接到主机:将每个从机连接到主机。

  • 开始复制:发起复制。

  • 验证复制状态:执行一个简短的测试以确保数据正在被复制。

以下部分将更详细地演示这些步骤。虽然本教程使用多个本地实例来演示如何使用复制,但是在使用离散机器(或虚拟机)的开发或生产环境中设置复制的过程是相同的。使用特定主机、驱动器、文件夹、端口等的各个命令的详细信息。是在生产中使用该程序唯一会改变的东西。

注意

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

初始化数据目录

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

$ mkdir rpl
$ cd rpl
$ mkdir data

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

--datadir选项指定数据目录主文件夹的位置。因为我们是作为本地用户运行的,所以我们还需要--user选项。

小费

如果您正在复制本教程中的命令,请确保使用您自己的用户名作为--user选项和所有路径。

我们还需要知道安装在本地机器上的 MySQL 服务器的基目录(名为basedir)。您可以从服务器配置文件中获取这些信息,或者使用 shell 并发出SHOW SQL 命令。下面演示了如何做到这一点。在这里,我们看到的基本目录是/usr/local/mysql-8.0.16-macos10.14-x86_64。我们将使用这个值,以便mysqld可执行文件可以找到它的依赖库和文件。

$ mysqlsh --uri root@localhost:33060 --sql -e "SHOW VARIABLES LIKE 'basedir'"
Variable_name      Value
basedir      /usr/local/mysql-8.0.16-macos10.14-x86_64/

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

$ mysqld --user=cbell --initialize-insecure --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ --datadir=/Users/cbell/rpl/data/master
$ mysqld --user=cbell --initialize-insecure --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ --datadir=/Users/cbell/rpl/data/master

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

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

配置主服务器

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

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

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

[mysqld]
datadir="/Users/cbell/rpl/data/master"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
port=13001
socket="/Users/cbell/rpl/master.sock"
server_id=1
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=master_binlog
binlog_format=row

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

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

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

如果我们想要使用基于 GTID 的复制,那么必须设置一些额外的选项。对于大师来说,只有三个;打开 GTIDs,设置一致性强制,并记录从属更新。因此,启用 GTID 的主服务器的配置文件如清单 8-2 所示。请注意,文件的第一部分与前面的示例相同。只添加最后几行来启用 GTIDs。

[mysqld]
datadir="/Users/cbell/rpl/data/master"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
port=13001
socket="/Users/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 8-2Master Configuration File (GTIDs)

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

小费

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

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

配置从机

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

像 master 一样,我们需要设置几个变量,包括 datadir、basedir、port 和 socket(对于 nix 风格的平台)。清单 8-3 显示了第一个从机(名为 slave1)的配置文件。

[mysqld]
datadir="/Users/cbell/rpl/data/slave1"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
port=13002
socket="/Users/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 8-3Slave Configuration File (Log File and Position)

注意,这里设置了两个额外的变量;报告端口和报告主机。这些对于确保像SHOW SLAVE HOSTS这样的命令报告正确的信息是必要的。也就是说,该视图的信息来自这些变量。因此,正确设置它们总是一个好主意。

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

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

[mysqld]
datadir="/Users/cbell/rpl/data/slave1"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
port=13002
socket="/Users/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 8-4Slave Configuration File (GTIDs)

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

启动 MySQL 实例

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

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

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

297Z 0 [System] [MY-010116] [Server] /usr/local/mysql-8.0.16-macos10.14-x86_64/bin/mysqld (mysqld 8.0.16) starting as process 2615
2019-05-03T23:14:46.081413Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /Users/cbell/rpl/data/master/ is case insensitive
2019-05-03T23:14:46.341919Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2019-05-03T23:14:46.342661Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/Users/cbell/rpl/data' in the path is accessible to all OS users. Consider choosing a different directory.
2019-05-03T23:14:46.355855Z 0 [System] [MY-010931] [Server] /usr/local/mysql-8.0.16-macos10.14-x86_64/bin/mysqld: ready for connections. Version: '8.0.16'  socket: '/Users/cbell/rpl/master.sock'  port: 13001  MySQL Community Server - GPL.
2019-05-03T23:14:46.569522Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/Users/cbell/rpl/masterx.sock' bind-address: '::' port: 33061

Listing 8-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 客户端的源命令从文件中读取命令并执行它们。因此,您可以使用以下命令在所有实例上快速创建复制用户。

$ mysqlsh --uri root@localhost:33061 --sql -f "create_rpl_user.sql"
$ mysqlsh --uri root@localhost:33062 --sql -f "create_rpl_user.sql"

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

将从设备连接到主设备

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

连接日志文件并定位

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

表 8-1

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

|

主文件中的项目

|

来源

|

例子

| | --- | --- | --- | | IP 地址或主机名 | master.cnf | 本地主机 | | 港口 | master.cnf | Thirteen thousand and one | | 二进制日志文件 | SHOW MASTER STATUS | master_binlog.000005 | | 二进制日志文件位置 | SHOW MASTER STATUS | One hundred and fifty-four | | 复制用户 ID | create_rpl_user.sql | rpl _ 用户 | | 复制用户密码 | create_rpl_user.sql | rpl_pass |

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

$ mysqlsh --uri root@localhost:33061 --sql -e "SHOW MASTER STATUS"
File    Position    Binlog_Do_DB    Binlog_Ignore_DB    Executed_Gtid_Set
master_binlog.000005    155

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

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

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

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

$ mysqlsh --uri root@localhost:33062 --sql -f "change_master.sql"

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

用 GTIDs 连接

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

表 8-2

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

|

主文件中的项目

|

来源

|

例子

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

请注意,我们需要的信息比日志文件和位置复制少。我们不需要知道主二进制日志文件或位置,因为 GTID 握手过程将为我们解析该信息。我们需要的只是主服务器和复制服务器的主机连接信息以及密码。对于支持 GTID 的复制,我们使用一个特殊的参数MASTER_AUTO_POSITION来指示复制自动协商连接信息。可以根据表 8-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的文件中,并如下执行。

mysqlsh --uri root@localhost:33062 --sql -f "change_master.sql"

如果您希望能够将该文件用于任何一种形式的复制,您可以简单地将这两个命令放在文件中,并注释掉一个您不需要的命令。例如,下面显示了带有两个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.000005', MASTER_LOG_POS=155;
# 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命令所做的那样。下面显示了启动从机的命令。

$ mysqlsh --uri root@localhost:33062 --sql -e "START SLAVE"

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

$ mysqlsh --uri root@localhost:33062 --sql -e "SHOW SLAVE STATUS\G"
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 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.000005
          Read_Master_Log_Pos: 155
               Relay_Log_File: MacBook-Pro-2-relay-bin.000002
                Relay_Log_Pos: 377
        Relay_Master_Log_File: master_binlog.000005
             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: 155
              Relay_Log_Space: 593
              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: b6632bf2-6df6-11e9-8bf5-cc9584d9b3f3
             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: ccc5263e-6df6-11e9-88d5-910b8477c67b:1
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
       Master_public_key_path:
        Get_master_public_key: 0
            Network_Namespace:

Listing 8-6Checking SLAVE STATUS

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

对于这个例子,您只需要确保两个线程都在运行(YES)并且没有错误。关于SHOW SLAVE STATUS命令中所有字段的详细解释,请参见在线 MySQL 参考手册中的“用于控制从属服务器的 SQL 语句”一节1

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

验证复制状态

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

mysqlsh --uri root@localhost:33061 --sql -e "SHOW SLAVE HOSTS\G"
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 1\. row ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
 Server_id: 2
      Host: localhost
      Port: 13002
 Master_id: 1
Slave_UUID: ccc5263e-6df6-11e9-88d5-910b8477c67b

Listing 8-7SHOW SLAVE HOSTS Command (Master)

在这里,我们看到所有从机都已连接,从最后一部分我们知道从机状态良好。

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

$ mysqlsh --uri root@localhost:33061 --sql
MySQL Shell 8.0.16

Copyright (c) 2016, 2019, 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 '\?' for help; '\quit' to exit.
Creating a session to 'root@localhost:33061'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 18 (X protocol)
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

 MySQL  localhost:33061+ ssl  SQL > CREATE DATABASE test;
Query OK, 1 row affected (0.0029 sec)

 MySQL  localhost:33061+ ssl  SQL > USE test;
Query OK, 0 rows affected (0.0002 sec)

 MySQL  localhost:33061+ ssl  SQL > CREATE TABLE test.t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL);
Query OK, 0 rows affected (0.0054 sec)

 MySQL  localhost:33061+ ssl  SQL > INSERT INTO test.t1 VALUES (1, 'Dr. Charles Bell');
Query OK, 1 row affected (0.0092 sec)

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

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

$ mysqlsh --uri root@localhost:33062 --sql -e "SELECT ∗ FROM test.t1"
c1    c2
1     Dr. Charles Bell

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

关闭复制

如果您在自己的机器上尝试本教程,请记住按照精确的顺序关闭实例。在每个从属服务器上,首先要用下面的命令停止从属服务器。

$ mysqlsh --uri root@localhost:33062 --sql -e "STOP SLAVE"

一旦所有从属服务器都停止了,您可以使用以下命令首先关闭从属服务器,然后关闭主服务器。注意,我们对主设备和从设备使用了旧的协议端口(13001、13002)。这是因为 X 协议不支持 shutdown 命令。如果在使用 MySQL X 端口时遇到错误,请尝试旧的协议并重新运行该命令。

$ mysqlsh --uri root@localhost:13002 --sql -e "SHUTDOWN"
$ mysqlsh --uri root@localhost:13001 --sql -e "SHUTDOWN"

MySQL 高可用性参考资料

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

  • Bell,Kindahl,Thalmann, MySQL 高可用性:构建健壮数据中心的工具,第二版(O'Reilly,2014)

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

  • 特卡琴科扎依采夫施瓦茨高性能 MySQL:优化、备份、复制等 (O'Reilly,2012)

  • Davies, MySQL 高可用性食谱 (Packt,2010 年)

在线参考手册包含大量文档,应该是您的主要来源( https://dev.mysql.com/doc/refman/8.0/en/replication.html )。

摘要

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

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

在这一章中,我们了解了什么是高可用性,MySQL 中一些高可用性特性的概述,以及如何用一个主服务器和一个从服务器实现 MySQL 复制。尽管本教程仅限于两台机器,但是您可以轻松地将其扩展到多台机器。

您可能认为 MySQL 复制将满足您的高可用性需求(这很好),但 MySQL Group Replication 通过引入容错和一系列功能将高可用性提升到了另一个水平,使其更加通用,可以满足更苛刻的高可用性需求。

在下一章,我们将看到如何使用 MySQL Shell 设置组复制的完整演练。

Footnotes 1

https://dev.mysql.com/doc/refman/8.0/en/replication-slave-sql.html

 

九、示例:组复制设置和管理

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

在本章中,我们将更深入地了解组复制的组成部分。之后,我们将在动手演练中对组复制进行指导。

入门指南

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

但是首先,让我们从组成描述组复制的语言的概念和术语的列表开始。

概念、术语和行话

很可能除了最精通或者掌握 MySQL 最新知识的人之外,所有人都会完全理解描述组复制的所有术语和概念。在这一节中,我们暂时后退一步,讨论一些您将在本章和接下来的两章(或任何一本关于 MySQL 高可用性的书)中遇到的术语和概念。因此,本节是与组复制相关的术语表。请随时参考这一部分。

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

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

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

  • 容错:从组中检测到的故障或错误中恢复而不丢失数据或功能的能力。请注意,组复制中的容错能力受到组中服务器数量的限制。有关如何计算服务器数量以及组可以容忍的故障数量,请参见联机参考手册中的“容错”一节。 1

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

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

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

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

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

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

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

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

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

  • 拓扑:描述复制组中服务器逻辑布局的术语。示例包括单主服务器,表示为单个服务器与每个从服务器之间的放射状连接;分层服务器,表示为单主服务器组的连接,其中每个从服务器都是另一组从服务器的主服务器;多主服务器,通常表示为每个主服务器连接到组中的每个其他主服务器以及组中的从服务器。

您应该了解组复制的另一个方面;通过计算故障数量,一个组可以恢复并继续提供高可用性。

组复制容错

回想一下第八章,我们了解到当服务器离线(离开组)时,组复制可以成功容忍一定数量的服务器故障。该组可以容忍的故障数量取决于该组中的服务器数量。用于确定一组服务器 fS 能够容忍多少故障同时或连续、未恢复故障的公式如下。

S = 2f + 1

例如,一组 11 台服务器最多可以容忍 5 次故障。

11 = 2f + 1
10 = 2f
2f = 10
f = 10/2
f = 5

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

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

例如,一组 5 台服务器可以容忍 2 次故障。

F = (5 - 1)/2
F = 4/2
F = 2

类似地,一组 7 台服务器可以容忍 3 次故障。

F = (7 - 1)/2
F = 6/2
F = 3

设置和配置

现在您已经对组复制及其工作原理有了一些了解,让我们来看看如何设置它。我们将了解如何使用四台服务器设置组复制。因此,您需要在使用不同端口的系统上、在另外四个系统上或者在四个虚拟机上运行四个 MySQL 实例。对于大多数情况下的探索,在本地计算机上运行多个 MySQL 实例会很好。

启动实例时,必须设置组复制的一些先决条件。建议您为每个实例创建一个单独的配置文件(my.cfg),这样就不会冒险为两个实例使用相同的目录。为此,我们应该已经在系统上安装了 MySQL。

启动一个新的 MySQL 实例很容易,只需要几个管理任务。下面概述了这些任务。

  • 数据目录:您必须创建一个文件夹来包含数据目录。

  • 端口:您必须为每个实例选择一个端口。

  • 配置文件:您必须为每台服务器创建一个单独的配置文件。

  • 手动启动实例:要运行实例,您将从命令行(或通过批处理文件)启动 MySQL (mysqld ),指定正确的配置文件。

我们将在下一节中看到这些步骤以及更多演示,下一节将介绍如何在本地计算机上设置和运行 MySQL 组复制的教程。

辅导的

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

如果您想自己体验本教程,您应该准备四台服务器。像上一个教程一样,我们将使用在当前机器上运行的几个实例。我们需要几个实例来确保该组有一个可行的集合来启用冗余和故障转移。在这种情况下,该组最多可以容忍 1 次故障;(4-1)/2 = 1.5 或 1 向下舍入。

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

注意

用于设置组复制的步骤与 MySQL 复制非常相似。事实上,除了术语(例如,从属与辅助)、配置文件以及首次在主服务器上启动组复制之外,过程是相同的。

  • 初始化数据目录:创建文件夹存储数据。

  • 配置主节点:用新的配置文件配置主节点。

  • 配置从站:用新的配置文件配置从站。

  • 启动 MySQL 实例:启动 MySQL 服务器实例。

  • 创建复制用户帐号:在所有服务器上创建复制用户。

  • 在主节点上启动组复制:启动主节点,建立组。

  • 将辅助节点连接到主节点:启动复制。

  • 在辅助节点上启动组复制:将辅助节点添加到组成员中。

  • 验证组复制状态:执行一个简短的测试以确保正在复制数据。

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

初始化数据目录

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

$ mkdir gr
$ cd gr
$ mkdir data

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

--datadir选项指定数据目录主文件夹的位置。因为我们是作为本地用户运行的,所以我们还需要--user选项。

小费

如果您正在复制本教程中的命令,请确保使用您自己的用户名作为--user选项和所有路径。

我们还需要知道安装在本地机器上的 MySQL 服务器的基目录(名为basedir)。您可以从服务器配置文件中获取这些信息,或者使用 shell 并发出SHOW SQL 命令。下面演示了如何做到这一点。在这里,我们看到的基本目录是/usr/local/mysql-8.0.16-macos10.14-x86_64。我们将使用这个值,以便mysqld可执行文件可以找到它的依赖库和文件。

$ mysqlsh --uri root@localhost:33060 --sql -e "SHOW VARIABLES LIKE 'basedir'"
Variable_name  Value
basedir        /usr/local/mysql-8.0.16-macos10.14-x86_64/

下面显示了初始化主节点和辅助节点的数据目录所需的命令。

$ mysqld --user=cbell --initialize-insecure \
  --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ \
  --datadir=/Users/cbell/gr/data/primary
$ mysqld --user=cbell --initialize-insecure \
  --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ \
  --datadir=/Users/cbell/gr/data/secondary1
$ mysqld --user=cbell --initialize-insecure \
  --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ \
  --datadir=/Users/cbell/gr/data/secondary2
$ mysqld --user=cbell --initialize-insecure \
  --basedir=/usr/local/mysql-8.0.16-macos10.14-x86_64/ \
  --datadir=/Users/cbell/gr/data/secondary3

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

配置主服务器

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

  • transaction_write_set_extraction:定义用于散列在事务期间提取的写入的算法。组复制必须设置为XXHASH64

  • group_replication_recovery_use_ssl:决定组复制恢复连接是否使用 SSL。通常设置为ON。默认是OFF

  • group_replication_group_name:该服务器实例所属的组的名称。必须是有效的、唯一的 UUID。

  • group_replication_start_on_boot:决定服务器启动时是否启动组复制。

  • group_replication_local_address:成员为来自其他成员的连接提供的网络地址,指定为 host:port 格式的字符串。请注意,此连接用于组复制成员之间的通信,而不是供客户端使用。

  • group_replication_group_seeds:群组成员列表,用于建立新成员到群组的连接。该列表由种子成员的group_replication_local_address网络地址组成,指定为逗号分隔列表,例如 host1:port1,host2:port2。

  • group_replication_bootstrap_group:配置此服务器以引导组。此选项只能在一台服务器上设置,并且只能在第一次启动组或重新启动整个组时设置。组启动后,将该选项设置为OFF

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

主要配置文件

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

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

[mysqld]
datadir="/Users/cbell/gr/data/primary"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
plugin_dir=/usr/local/mysql/lib/plugin/
plugin-load=group_replication.so
port=24801
mysqlx-port=33061
mysqlx-socket="/Users/cbell/rpl/primaryx.sock"
socket="/Users/cbell/rpl/primary.sock"
server_id=101
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
binlog_checksum=NONE

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

Listing 9-1Primary Configuration File (Group Replication)

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

注意

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

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

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

辅助配置文件

辅助节点的配置文件与主节点的配置文件非常相似,唯一的变化是为特定于实例的变量(如端口、数据目录、套接字和服务器 id)使用了正确的值。然而,除了这些设置之外,还有一些不同之处。transaction_write_set_extraction变量在初始初级上设置。

对于辅助节点,我们添加group_replication_recovery_get_public_key并将其设置为ON。此变量确定辅助节点是否向主节点请求基于 RSA 密钥对的密码交换所需的公钥。该变量适用于通过caching_sha2_password认证插件进行认证的辅助节点。

我们还包含了插件可执行文件路径的plugin_dir,您可以使用SHOW VARIABLES LIKE '%plugin%'命令。我们包含的另一个变量是值为group_replication.soplugin-load变量。注意,.so文件扩展名指的是 nix 计算机上的共享对象库。在 Windows 上,你可以使用.dll

清单 9-2 显示了第一个辅助节点(名为secondary1.cnf)的配置文件。

[mysqld]
datadir="/Users/cbell/gr/data/secondary1"
basedir="/usr/local/mysql-8.0.16-macos10.14-x86_64/"
plugin_dir=/usr/local/mysql/lib/plugin/
plugin-load=group_replication.so
port=24901
mysqlx-port=33062
mysqlx-socket="/Users/cbell/rpl/secondary1x.sock"
socket="/Users/cbell/rpl/data/secondary1.sock"
server_id=102
master_info_repository=TABLE
relay_log_info_repository=TABLE
log_bin=slave1_binlog
binlog_format=row
report-port=24901
report-host=localhost

# GTID VARIABLES
gtid_mode=ON
enforce_gtid_consistency=ON
log_slave_updates=ON
binlog_checksum=NONE

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

Listing 9-2Secondary Configuration File (Group Replication)

在本教程中,我们将使用三个辅助节点,因此您应该在我们之前创建的文件夹中为每个节点创建一个文件,并将它们命名为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 &

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

$ mysqld --defaults-file=primary.cnf
MacBook-Pro-2:gr cbell$ 2019-05-05T21:00:42.388965Z 0 [System] [MY-010116] [Server] /usr/local/mysql-8.0.16-macos10.14-x86_64/bin/mysqld (mysqld 8.0.16) starting as process 935
2019-05-05T21:00:42.392064Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /Users/cbell/gr/data/primary/ is case insensitive
2019-05-05T21:00:42.662123Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2019-05-05T21:00:42.676713Z 0 [System] [MY-010931] [Server] /usr/local/mysql-8.0.16-macos10.14-x86_64/bin/mysqld: ready for connections. Version: '8.0.16'  socket: '/Users/cbell/rpl/primary.sock'  port: 24801  MySQL Community Server - GPL.
2019-05-05T21:00:42.895674Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/Users/cbell/rpl/primaryx.sock' bind-address: '::' port: 33061

Listing 9-3Starting the Primary Instance

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

如果您正在按照本教程进行操作,并且还没有这样做,请继续操作并启动辅助服务器。使用前面显示的命令重定向到一个文件。一旦启动了所有的服务器实例,我们就可以进入下一步了。

安装组复制插件

如果您不想在配置文件中包含组复制插件,您可以使用INSTALL PLUGIN命令手动安装。完成后,您不必再次运行该命令——服务器将重新启动并启用插件。该命令需要插件的名称以及可动态加载的可执行文件的名称。在这种情况下,插件的名字是group_replication,可加载的可执行文件的名字是group_replication.so。因此,我们将使用的命令是INSTALL PLUGIN group_replication SONAME 'group_replication.so'

注意文件名中的.so。这是您将用于*nix 平台的扩展。在 Windows 上,文件扩展名是.dll。你可以用SHOW PLUGINS命令检查插件的状态。

您必须在所有实例上运行该命令。一旦插件加载到所有实例上,我们就可以继续在所有实例上创建复制用户。

创建复制用户帐户

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;

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

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

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

$ mysqlsh --uri root@localhost:24801 --sql -f "create_rpl_user.sql"
$ mysqlsh --uri root@localhost:24802 --sql -f "create_rpl_user.sql"
$ mysqlsh --uri root@localhost:24803 --sql -f "create_rpl_user.sql"
$ mysqlsh --uri root@localhost:24804 --sql -f "create_rpl_user.sql"

现在,我们准备在主节点上启动组复制。

在主节点上启动组复制

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

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

$ mysqlsh --uri root@localhost:24801 --sql
...
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的文件中,并按如下方式执行。

$ mysqlsh --uri root@localhost:24802 --sql -f "change_master.sql"
$ mysqlsh --uri root@localhost:24803 --sql -f "change_master.sql"
$ mysqlsh --uri root@localhost:24804 --sql -f "change_master.sql"

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

在辅助节点上启动组复制

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

$ mysqlsh --uri root@localhost:24802 --sql -e "START GROUP_REPLICATION"
$ mysqlsh --uri root@localhost:24803 --sql -e "START GROUP_REPLICATION"
$ mysqlsh --uri root@localhost:24804 --sql -e "START GROUP_REPLICATION"

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视图(表)用于监视不同服务器实例的状态,这些实例在当前视图中被跟踪,或者换句话说,它们是组的一部分,因此由成员资格服务跟踪。该信息在作为复制组成员的所有服务器实例之间共享,因此可以从任何成员处查询所有组成员的信息。清单 9-4 展示了运行中的命令。您可以将命令保存在一个名为check_gr.sql的文件中,以备后用。

$ mysqlsh --uri root@localhost:24802 --sql
MySQL Shell 8.0.16

Copyright (c) 2016, 2019, 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 '\?' for help; '\quit' to exit.
Creating a session to 'root@localhost:24802'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 28
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> SHOW SLAVE STATUS\G

Empty set (0.0003 sec)

> SELECT ∗ FROM performance_schema.replication_group_members \G

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 1\. row ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: e0b8aeca-6f7e-11e9-bd22-533c3552fe03
   MEMBER_HOST: MacBook-Pro-2.local
   MEMBER_PORT: 24801
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 2\. row ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: e32085ac-6f7e-11e9-a081-cc47fe26c35d
   MEMBER_HOST: localhost
   MEMBER_PORT: 24901
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 3\. row ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: e5818c4c-6f7e-11e9-a41a-c85d7844eaca
   MEMBER_HOST: localhost
   MEMBER_PORT: 24902
  MEMBER_STATE: ONLINE
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 4\. row ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
  CHANNEL_NAME: group_replication_applier
     MEMBER_ID: e7f23058-6f7e-11e9-a7c3-c576fe9a0754
   MEMBER_HOST: localhost
   MEMBER_PORT: 24903
  MEMBER_STATE: RECOVERING
   MEMBER_ROLE: SECONDARY
MEMBER_VERSION: 8.0.16
4 rows in set (0.0013 sec)

Listing 9-4Checking Group Replication Status

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

您还可以缩小输出范围,以获得更令人满意的视图,其中仅包括此处显示的成员主机、端口、状态和角色。

> SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members;
+---------------------+-------------+--------------+-------------+
| MEMBER_HOST         | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE |
+---------------------+-------------+--------------+-------------+
| MacBook-Pro-2.local |       24801 | ONLINE       | PRIMARY     |
| localhost           |       24901 | ONLINE       | SECONDARY   |
| localhost           |       24902 | ONLINE       | SECONDARY   |
| localhost           |       24903 | ONLINE       | SECONDARY   |
+---------------------+-------------+--------------+-------------+
4 rows in set (0.0006 sec)

如果您只想定位主服务器,可以对任何组成员使用以下查询。当您对组中的任何一个成员执行此查询时,您将看到主服务器的 UUID 如下所示。

> 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";
+--------------------------------------+---------------------+-------------+
| member_id                            | member_host         | member_port |
+--------------------------------------+---------------------+-------------+
| e0b8aeca-6f7e-11e9-bd22-533c3552fe03 | MacBook-Pro-2.local |       24801 |
+--------------------------------------+---------------------+-------------+
1 row in set (0.0014 sec)

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

> CREATE DATABASE test;
ERROR: 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

为什么会出现这个错误?事实证明,每个辅助节点都是以超级只读启动的,这意味着任何人都不能提交写操作,即使是那些拥有“超级”权限的人。因此(从 MySQL 复制)向从服务器发送写操作的常见问题得到了解决。万岁。使用超级只读还表明我们正在单主模式下运行组复制(这是默认模式)。当我们在后面的章节中探索 InnoDB 集群的细微差别时,我们将看到其他模式。

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

$ mysqlsh --uri root@localhost:24801 --sql
...

> CREATE DATABASE test;

Query OK, 1 row affected (0.0042 sec)

> USE test;

Query OK, 0 rows affected (0.0003 sec)

> CREATE TABLE test.t1 (id INT PRIMARY KEY, message TEXT NOT NULL);

Query OK, 0 rows affected (0.0093 sec)

> INSERT INTO test.t1 VALUES (1, 'Chuck');

Query OK, 1 row affected (0.0103 sec)

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

$ mysqlsh --uri root@localhost:24803 --sql
...

> SELECT ∗ FROM test.t1;

+----+---------+
| id | message |
+----+---------+
|  1 | Chuck   |
+----+---------+
1 row in set (0.0006 sec)

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

正在关闭组复制

如果您在自己的机器上尝试本教程,请记住按照精确的顺序关闭实例。在每个辅助节点上,您首先需要使用以下命令停止组复制。

$ mysqlsh --uri root@localhost:24802 --sql -e "STOP GROUP_REPLICATION"

一旦停止了所有从服务器,您可以使用以下命令先关闭从服务器,然后关闭主服务器。注意,我们对主设备和从设备使用了旧的协议端口(13001、13002)。这是因为 X 协议不支持 shutdown 命令。如果在使用 MySQL X 端口时遇到错误,请尝试旧的协议并重新运行该命令。

$ mysqlsh --uri root@localhost:24804 --sql -e "SHUTDOWN"
$ mysqlsh --uri root@localhost:24803 --sql -e "SHUTDOWN"
$ mysqlsh --uri root@localhost:24802 --sql -e "SHUTDOWN"
$ mysqlsh --uri root@localhost:24801 --sql -e "SHUTDOWN"

故障转移演示

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

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

让我们看看这是如何工作的。回想一下前面的教程,我们在端口 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文件(参见清单 9-4 )。清单 9-5 显示了查询的输出。

$ mysqlsh --uri root@localhost:24802 --sql -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.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 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.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 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.16
+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 2854aecd-4330-11e8-abb6-d4258b76e981 | oracle-pc   |       24802 |
+--------------------------------------+-------------+-------------+

Listing 9-5Checking Group Health After Primary Goes Down

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

$ mysqlsh --uri root@localhost:24804 --sql -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.16
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 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.16
+--------------------------------------+-------------+-------------+
| member_id                            | member_host | member_port |
+--------------------------------------+-------------+-------------+
| 2ecd9f66-4330-11e8-90fe-d4258b76e981 | oracle-pc   |       24803 |
+--------------------------------------+-------------+-------------+

Listing 9-6State of the Group When No More Primary Servers Remain

在这里,我们可以看到其中一个辅助节点确实接管了主节点的角色,并且该组容忍了故障。但是,请注意,由于我们从四台服务器开始,我们只能容忍一台服务器出现故障。但是,我们可以随时添加新的辅助节点,以提高组可以容忍的故障数量。例如,我们可以修复出现故障的辅助节点,并将其添加回组中。

摘要

不可否认,组复制是 MySQL 高可用性的一次飞跃。然而,正如我们在本章的教程中所看到的,设置起来并不简单。虽然那些熟悉 MySQL 复制的人会看到类似的过程,但有一些额外的步骤和略有不同的命令,配置文件中的变化最多,但那些不熟悉 MySQL 和高可用性的人可能会觉得学习曲线相当陡峭。

在本章中,我们对组复制进行了初步了解,并体验了最初以及在一两次故障期间设置和维护组的过程。如果你是那些认为一定有更好的方法的人之一,那就有,我们就快到了!

在下一章中,我们将了解 MySQL 中最新、最好的高可用性特性——InnoDB Cluster,并使用 MySQL Shell 来管理它。

Footnotes 1

https://dev.mysql.com/doc/refman/8.0/en/group-replication-fault-tolerance.html

 

十、将 Shell 与 InnoDB 集群一起使用

到目前为止,我们已经了解了什么是高可用性,以及如何使用 MySQL 复制设置一个基本的高可用性安装。我们还学习了如何配置组复制以获得更好的高可用性。然而,我们在这个过程中了解到,完成所有这些工作的设置和命令是特定的,需要比大多数人想要的更多的手动设置和配置步骤。幸运的是,Oracle 听取了客户的意见,并一直致力于 MySQL 高可用性,不仅大幅改进了特性和功能,还提高了易用性(或管理)。这是 InnoDB 集群真正闪光的地方。

InnoDB Cluster 代表了 MySQL 在高可用性方面的一次巨大飞跃。最重要的是,它是 MySQL 8.0 所有版本的标准配置。在本章中,我们将发现是什么使 InnoDB Cluster 成为大大小小企业的重要特征。正如您将看到的,InnoDB Cluster 由几个组件组成,这些组件可以很好地协同工作,并且可以立即为 MySQL 实现最高形式的高可用性!

概观

MySQL 8.0 中最令人兴奋的新特性之一是 InnoDB 集群。它旨在使高可用性更易于设置、使用和维护。InnoDB Cluster 通过 MySQL Shell 和 AdminAPI、组复制和 MySQL 路由器与 X DevAPI 一起工作,将高可用性和读取可伸缩性提升到一个新的水平。

也就是说,它将 InnoDB 存储引擎(MySQL 的内部)中用于克隆数据的新功能与组复制和 MySQL 路由器相结合,提供了一种在应用层设置和管理高可用性的新方法。下面的列表描述了构成 InnoDB 集群的组件。我们之前已经看到了其中的大部分,我们将在接下来的章节中了解更多,并在下一章中详细介绍如何使用它们。

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

  • MySQL Shell:JavaScript 和 Python 的新 MySQL 客户端和编程环境,以及我们将看到的 InnoDB 集群的管理控制台。

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

  • AdminAPI :是一个特殊的 API,可以通过 MySQL Shell 配置 InnoDB 集群并与之交互。因此,AdminAPI 具有旨在简化 InnoDB 集群工作的特性。

  • MySQL 路由器:轻量级的中间件,在你的应用和后端 MySQL 服务器之间提供透明的路由。我们将在后面的章节中学习更多关于 MySQL 路由器的知识。

您可能想知道所有这些产品和功能如何无缝地协同工作。正如您将看到的,通过 MySQL Shell 使用 InnoDB Cluster 隐藏了单独使用组件的许多细节(和繁琐)。例如,我们不再必须为复制编写专门的配置文件。

让我们看一个概念性的配置,以了解组件是如何交互的。在此使用案例中,一个由三台服务器组成的集群设置了一个主服务器,它是所有写入(更新)的目标。多个辅助服务器维护数据的副本,这些副本可以被读取,因此能够在不给主服务器增加负担的情况下读取数据,从而实现读取的可伸缩性(但是所有服务器都参与协商和协调)。

组复制的引入意味着集群是容错的,并且组成员是自动管理的。MySQL 路由器缓存 InnoDB 集群的元数据,并执行到 MySQL 服务器实例的高可用性路由,从而更容易编写应用来与集群进行交互。图 10-1 显示了这些组件是如何在概念上排列以形成 InnoDB 集群的。

img/478423_1_En_10_Fig1_HTML.jpg

图 10-1

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

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

此外,您可以通过 MySQL Shell 在沙盒中部署 InnoDB 集群。更具体地说,您可以部署一个在本地计算机上运行的测试集群,并在将其部署到生产环境之前进行试验。幸运的是,所有的步骤都是相同的,只是在一些函数名中添加了关键字sandbox和一些用于创建本地 MySQL 实例的额外函数。我们将在第十一章中看到在沙箱中运行 InnoDB 集群的深入报道。

什么是沙盒?

沙箱是一个用来描述数据和元数据(配置文件等)的情况的术语。)的组织方式使得数据和元数据不会影响(替换)产品的现有数据或安装。在 MySQL AdminAPI 的例子中,它实现的沙箱确保 InnoDB 集群中服务器的任何配置都不会影响机器上 MySQL 的任何现有安装。

在生产环境中部署 InnoDB 集群需要单独设置服务器,然后从 shell 连接到它们并准备它们。同样,这一步与沙盒部署中的步骤相同。唯一的区别是您使用的是现有的正在运行的 MySQL 服务器,而不是运行在本地机器上的另一个实例。

现在我们已经对 InnoDB 集群有了一个大致的了解,让我们从 InnoDB 存储引擎开始,看看 InnoDB 集群的核心组件。

什么是存储引擎?

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

InnoDB 存储引擎

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

InnoDB 是一个通用存储引擎,它平衡了高可靠性和高性能。使用 InnoDB 存储引擎的决定是在多次尝试为 MySQL 构建一个健壮、高性能的存储引擎之后做出的。考虑到 InnoDB 的成熟性和复杂性,使用已经存在的东西更有意义。另外,甲骨文同时拥有 MySQL 和 InnoDB。

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

酸代表原子性、一致性、隔离性和持久性。也许是数据库理论中最重要的概念之一,它定义了数据库系统必须表现出的行为,才能被认为是可靠的事务处理。下面简要描述每个方面。

  • 原子性意味着对于包含多个命令的事务,数据库必须允许在“全有或全无”的基础上修改数据。也就是说,每个事务都是原子的。如果命令失败,则整个事务失败,并且事务中到该点为止的所有更改都将被丢弃。这对于在高交易环境(如金融市场)中运行的系统尤其重要。

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

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

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

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

警告

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

虽然 InnoDB 使用精心选择的缺省值,开箱即可工作,而且对大多数人来说可能不需要太多的调优,但那些需要调优 MySQL 的人会发现他们需要的一切,甚至更多,以使他们的数据库系统以最高效率运行。

参见 https://dev.mysql.com/doc/refman/8.0/en/innodb-introduction.html 了解有关 InnoDB 存储引擎的更多信息,包括众多配置和调优选项。

小费

关于配置 MySQL 和 InnoDB 的技巧和建议的另一个很好的来源是特卡琴科扎依采夫 Schwartz 的书高性能 MySQL:优化、备份、复制(O ' Reilly,2012)。

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

小费

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

档案馆

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

黑洞

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

战斗支援车

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

联邦的

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

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

记忆

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

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

我的天

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

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

合并(MyISAM)

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

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

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

  • 不允许替换操作。

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

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

性能模式

性能模式存储引擎是一个特殊的报告引擎,用于在较低的级别监控 MySQL 服务器的执行。虽然它显示在可用存储引擎列表中,但它不是存储数据的可用选项。

现在,我们对什么是存储引擎,尤其是 InnoDB 存储引擎有了更多的了解,让我们看看 InnoDB 集群的其他组件。

组复制

如果您使用过 MySQL 复制,那么您无疑非常熟悉如何在构建高可用性解决方案时利用它。事实上,您很可能已经发现了许多使用 MySQL 复制来提高应用可用性的方法。而且,如果你一直在看这本书,你也已经了解了组复制。

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

回想一下,组复制也使同步复制(在属于同一个组的节点之间)成为现实,而现有的 MySQL 复制特性是异步的(或者至多是半同步的)。因此,在任何时候都提供了更强的数据一致性(数据在所有成员上都可用,没有延迟)。

我们了解到,组复制和标准复制之间的另一个重要区别是,组中的所有服务器都可以参与更新数据,并自动解决冲突。但是,您可以将组复制配置为只允许一台服务器(称为主服务器)进行更新,其他服务器充当辅助服务器或备份服务器(用于故障转移)。

因此,组复制是 InnoDB 集群的核心组件也就不足为奇了。我们获得了组复制的所有好处,而没有配置和维护组的复杂性。

MySQL Shell

回想一下,MySQL Shell 被设计为使用新的 X 协议通过 X 插件与服务器进行通信,这允许 Shell 与 MySQL 服务器及其组件进行通信,公开新的 API 来处理数据和管理。我们在第六章和第七章中学习了 X DevAPI。管理 API 被称为 X AdminAPI,它允许 shell 与 InnoDB Cluster 进行设置和管理通信。

X DevAPI

回想一下,X DevAPI 是一个类库和方法库,为 MySQL 实现了一个新的 NoSQL 接口。具体来说,X DevAPI 旨在允许与 JSON 文档和关系数据轻松交互。X DevAPI 有专门支持这两个概念的类,允许开发人员在他们的应用中使用其中一个(或两个)。X DevAPI 允许我们使用 JavaScript 或 Python 处理 MySQL,并与 AdminAPI 结合使用,为管理 InnoDB 集群提供了一个强大的机制。

小费

参见 https://dev.mysql.com/doc/x-devapi-userguide/en/ 了解更多关于 X DevAPI 的信息。

AdminAPI

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

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

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

随着我们探索如何设置和管理 InnoDB 集群,我们将在第十一章中看到更多的 AdminAPI。

小费

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

MySQL 路由器

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

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

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

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

小费

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

Innodb 集群和 NDB 集群的区别是什么?

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

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

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

在应用中使用 InnoDB

您可能想知道 InnoDB 集群如何在您的环境中发挥作用(甚至想知道如何使用它)。也就是说,我们知道 InnoDB 集群的好处是更好的高可用性形式,但是 MySQL 路由器和我们的应用如何适应这种情况呢?

当与 MySQL InnoDB Cluster(通过底层组复制)一起使用以跨多个服务器复制数据库,同时在服务器出现故障时执行自动故障转移时,路由器充当代理来隐藏网络上的多个 MySQL 实例,并将数据请求映射到其中一个集群实例。

如果有足够的在线副本并且可靠的网络通信是可能的,那么使用该路由器的应用将能够联系剩余的服务器之一。路由器通过让应用连接到 MySQL 路由器而不是直接连接到特定的 MySQL 服务器来实现这一点。图 10-2 显示了路由器相对于您的应用和 InnoDB 集群所处位置的逻辑视图。

img/478423_1_En_10_Fig2_HTML.jpg

图 10-2

使用 MySQL 路由器的应用架构(由 Oracle 公司提供)

注意,我们描述了两个应用,每个都连接到 MySQL 路由器的一个实例。路由器的工作原理是位于应用和 MySQL 服务器之间。当一个应用连接到路由器时,路由器从候选服务器池中选择一个合适的 MySQL 服务器,并将所有网络流量从应用转发到该服务器(以及从服务器返回的响应到应用)。

在后台,路由器存储来自 InnoDB 集群的服务器列表及其状态。虽然服务器列表(或缓存)最初是从配置文件中读取的,但路由器和集群之间的后续通信确保了它在拓扑结构发生变化时得到更新。这意味着当服务器丢失时,它们会被路由器标记为离线,路由器会跳过它们。同样,如果集群中添加了新的服务器,路由器的缓存也会更新以包含这些服务器。

因此,为了保持高速缓存更新,路由器保持与集群中的一个服务器的开放连接,从性能模式数据库查询集群元数据。每当检测到集群状态发生变化时,组复制就会实时更新这些表(或视图)。例如,如果一个 MySQL 服务器意外关闭。

最后,该路由器使开发人员能够使用插件为定制用例扩展 MySQL 路由器。这意味着,如果您的应用需要不同的路由策略,或者您想在解决方案中构建数据包检测,您可以使用自定义插件来扩展路由器。虽然为路由器构建定制插件超出了本章的范围,也没有例子可以学习,但是一定要查看 MySQL 开发者网站( dev。mysql。com )和 MySQL 工程博客( https://mysqlserverteam.com/ )获取最新信息和示例。

现在我们已经了解了构成 InnoDB 集群的组件,让我们简单讨论一下设置和配置 InnoDB 集群需要做些什么。我们将在下一章演示 InnoDB 集群。

设置和配置

除了我们在第二章中所做的,InnoDB 集群的设置和配置不需要任何新的复杂步骤。如果你还记得在第二章的 MySQL 安装过程中,我们没有为 MySQL 服务器和 InnoDB 集群选择沙盒选项。我们也没有选择自动配置 MySQL 路由器。如果您选择了这些选项,您就可以让 InnoDB Cluster 运行在一个沙箱中,并准备好使用 MySQL 路由器。

虽然您可以通过重新运行安装来完成(例如,在 Windows 上,运行 MySQL Installer for Windows),但我们将使用更传统的手动设置,以便您可以了解如何设置 InnoDB Cluster 和 MySQL Router,这将为您在环境中部署 InnoDB Cluster 和 MySQL Router 提供更好的基础。

准备您的系统运行 InnoDB Cluster 作为测试的过程并不困难,其中几个 MySQL 实例在本地运行,并且配置路由器也运行。我们将在本章中看到该过程的概述,并确保第十一章的演示。但首先,让我们更深入地讨论一个在规划新的企业级功能(如 InnoDB Cluster)时经常出现的话题——升级现有服务器。

升级检查器

使用 InnoDB 集群有几个先决条件。首先也是最重要的是,你必须使用一个支持包括组复制在内的所有组件的 MySQL 版本。幸运的是,还有一个更重要的步骤可以确保 MySQL 服务器为 InnoDB 集群做好准备。您可以使用 MySQL Shell 升级检查工具来检查每台服务器。

升级检查器是 MySQL Shell 中的一项功能,它允许您验证服务器是否已针对升级进行了正确配置。如果您正在使用较旧版本的 MySQL 或一组具有不同 MySQL 版本的服务器,升级检查器实用程序可以在部署组复制或 InnoDB 集群等功能时为您省去许多麻烦。

升级检查器适用于较新版本的 MySQL,但也可以用于 MySQL 5.7 服务器,检查它们的兼容性和安装中的错误。从 8.0.16 版开始,升级检查器还可以检查配置文件中具有非默认值的系统变量。

要使用升级检查器,只需运行 shell 并连接到您想要检查的 MySQL 服务器。最好总是在同一台服务器上运行 shell,但是除了检查配置文件之外,这不是必需的。

升级检查器函数包含在util库中,命名为util.check_for_server_upgrade()。升级检查器可以接受两个可选参数:1)到服务器的连接信息(如果还没有建立的话),以及 2)选项字典。有许多选项,包括以下选项。

  • targetVersion:您计划升级到的 MySQL 服务器版本

  • configPath:MySQL 服务器实例的配置文件路径

  • outputFormat:显示结果的格式——TEXTJSON

为了更好地使用升级检查器,下面演示了在较旧的 MySQL 5.7.22 服务器上运行该实用程序。我们将检查它是否可以升级到 8.0.16,我们将请求文本输出(默认)。正如您将看到的,该实用程序检查了相当多的东西。清单 10-1 显示了运行实用程序的完整输出。

> util.check_for_server_upgrade('root@localhost:13000', {'targetVersion':'8.0.16', 'outputFormat':'TEXT'})
The MySQL server at localhost:13000, version 5.7.22-log - MySQL Community
Server (GPL), will now be checked for compatibility issues for upgrade to MySQL
8.0.16...

1) Usage of old temporal type
  No issues found

2) Usage of db objects with names conflicting with reserved keywords in 8.0
  No issues found

3) Usage of utf8mb3 charset
  No issues found

4) Table names in the mysql schema conflicting with new tables in 8.0
  No issues found

5) Foreign key constraint names longer than 64 characters
  No issues found

6) Usage of obsolete MAXDB sql_mode flag
  No issues found

7) Usage of obsolete sql_mode flags
  No issues found

8) ENUM/SET column definitions containing elements longer than 255 characters
  No issues found

9) Usage of partitioned tables in shared tablespaces
  No issues found

10) Usage of removed functions
  No issues found

11) Usage of removed GROUP BY ASC/DESC syntax

  No issues found

12) Removed system variables for error logging to the system log configuration
  To run this check requires full path to MySQL server configuration file to be specified at 'configPath' key of options dictionary
  More information:
    https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-13.html#mysqld-8-0-13-logging

13) Removed system variables
  To run this check requires full path to MySQL server configuration file to be specified at 'configPath' key of options dictionary
  More information:
    https://dev.mysql.com/doc/refman/8.0/en/added-deprecated-removed.html#optvars-removed

14) System variables with new default values
  To run this check requires full path to MySQL server configuration file to be specified at 'configPath' key of options dictionary
  More information:
    https://mysqlserverteam.com/new-defaults-in-mysql-8-0/

15) Schema inconsistencies resulting from file removal or corruption
  No issues found

16) Issues reported by 'check table x for upgrade' command
  No issues found

17) New default authentication plugin considerations
  Warning: The new default authentication plugin 'caching_sha2_password' offers
    more secure password hashing than previously used 'mysql_native_password'
    (and consequent improved client connection authentication). However, it also
    has compatibility implications that may affect existing MySQL installations.
    If your MySQL installation must serve pre-8.0 clients and you encounter
    compatibility issues after upgrading, the simplest way to address those
    issues are to reconfigure the server to revert to the previous default
    authentication plugin (mysql_native_password). For example, use these lines
    in the server option file:

    [mysqld]
    default_authentication_plugin=mysql_native_password

    However, the setting should be viewed as temporary, not as a long term or
    permanent solution, because it causes new accounts created with the setting
    in effect to forego the improved authentication security.
    If you are using replication please take time to understand how the
    authentication plugin changes may impact you.
  More information:
    https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password-compatibility-issues
    https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password-replication

Errors:   0

Warnings: 1

Notices:  0

No fatal errors were found that would prevent an upgrade, but some potential issues were detected. Please ensure that the reported issues are not significant before upgrading.

Listing 10-1Demonstration of the Upgrade Checker Utility

请注意,该实用程序发现了一个警告。在这种情况下,它是身份验证插件的使用。测试的服务器没有使用更新、更安全的插件。幸运的是,该实用程序为我们如何克服这个问题提供了一些提示。

还要注意,我们没有提供配置文件的路径,因此跳过了这一步。它没有显示为警告,因为这是一个可选参数(check ),可以在选项字典中指定。

您可以使用其他几种配置来检查服务器的兼容性。有关升级检查器实用程序的更多信息,请参见位于 https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-upgrade.html 的实用程序的在线参考手册。

安装 InnoDB 集群概述

安装 InnoDB Cluster 的过程非常简单,只要你安装几次,你就会发现这比设置 MySQL 复制或 MySQL 组复制要简单得多。唯一可能需要多做一点工作的步骤是配置路由器,但幸运的是这不是一个常规操作(设置一次就让它运行)。所需步骤的概要如下所示。我们将在第十一章中看到这些步骤中的每一步。

  • 选择 MySQL 实例的数量(为了容错)

  • 为 MySQL 实例和路由器选择端口号

  • 创建并配置 MySQL 实例

  • 创建集群

  • 向集群添加 MySQL 实例

  • 检查集群的状态

  • 配置(引导)路由器

虽然路由器的配置和在您的应用中使用它与 MySQL Shell 无关,但演示没有它的 InnoDB Cluster 将是一个错误,因为路由器提供应用级故障转移,这对于一些高可用性要求高可靠性的用例来说可能是至关重要的。

摘要

我们现在有了一个完整的高可用性故事。虽然 MySQL InnoDB Cluster 为我们的数据提供了高可用性,但它并不能(直接)帮助我们在应用级别实现高可用性。是的,您可以编写您的应用来查询集群,并获取信息,以便在服务器离线时帮助您的应用“恢复”,但是实践表明这是一个非常脆弱的解决方案,它过于依赖于已知的参数。如果集群配置发生任何变化,应用可能会失败,或者需要重新启动。

这对大多数组织来说并不理想。我们需要的是能够快速轻松地使我们的应用适应集群中的变化。更具体地说,如果集群中的服务器脱机或被脱机或其角色改变,应用不应该停止。这就是 MySQL 路由器大放异彩的地方。

MySQL Router 将连接路由的负担从应用中分离出来,将其放在自己的轻量级、易于配置的实例中。现在,应用可以依赖路由器进行所有连接路由,包括故障转移事件或正常的高可用性恢复事件。

在下一章中,我们将在一组机器上部署 MySQL InnoDB 集群,并使用一个简单的应用配置路由器,以展示如何为自己的应用实现高可用性目标。我们将展示如何将 MySQL Shell 作为管理控制台与 InnoDB Cluster 配合使用,并快速了解 AdminAPI。

十一、示例:InnoDB 集群设置和管理

现在,我们已经了解了更多关于什么是 InnoDB 集群以及构成该特性的组件的信息,我们几乎已经掌握了足够的信息,可以开始使用一个小型的实验性 InnoDB 集群了。我们还需要学习一些东西,包括如何在 shell 中使用 AdminAPI,以及熟悉设置 InnoDB 集群和 MySQL 路由器所需的步骤。

在本章中,我们将看到 InnoDB 集群部署的更简单形式的演示——通过 MySQL Shell 和 AdminAPI 在沙盒部署方法中运行它。我们将创建一个 InnoDB 集群,在本地机器上运行四个实例。我们不仅将看到如何设置集群以供使用,还将看到集群如何处理故障转移,最后将看到如何设置 MySQL 路由器并演示它如何与应用一起工作。

但是首先,让我们从 AdminAPI 的概述开始。

入门指南

允许我们设置实验性 InnoDB 集群的关键组件称为沙箱。AdminAPI 有几种方法可以在本地机器上的沙箱中使用 MySQL 服务器。然而,AdminAPI 也有一些类,它们的方法用于在远程机器上使用 MySQL 服务器的 InnoDB 集群。在本章中,我们将看到 AdminAPI 中可用的类和方法的概述。在下一节的 InnoDB 集群演示中,我们将使用本节中讨论的一些方法。

AdminAPI 中有两个主要的类:dbacluster。让我们来看看每个类的细节。

注意

以下是在线可用文档的压缩版本,旨在提供概述,而不是具体的使用示例。

工商管理学博士

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

因为这个类是 API 的设置和配置部分,它有使用沙箱的方法和使用远程服务器的方法。表 11-1 显示了可用于处理沙箱中实例(名称中带有沙箱的实例)的方法 1

表 11-1

沙盒方法(dba 类)

|

返回

|

功能

|

描述

| | --- | --- | --- | | 没有人 | delete_sandbox_instance(int port, dict options) | 删除本地主机上现有的 MySQL 服务器实例 | | 情况 | deploy_sandbox_instance(int port, dict options) | 在本地主机上创建新的 MySQL 服务器实例 | | 没有人 | kill_sandbox_instance(int port, dict options) | 终止本地主机上正在运行的 MySQL 服务器实例 | | 没有人 | start_sandbox_instance(int port, dict options) | 在本地主机上启动现有的 MySQL 服务器实例 | | 没有人 | stop_sandbox_instance(int port, dict options) | 停止本地主机上正在运行的 MySQL 服务器实例 |

请注意,有一些方法可以在沙箱中部署实例,以及删除或终止实例(delete 删除实例,kill 停止实例,但保留数据和元数据),以及启动和停止实例(kill 发出不受控制的关闭)。在后面的小节中,我们将在沙箱中演示 InnoDB 集群时使用这些方法中的大部分。

还要注意,这些方法需要一个端口号和一个选项字典。AdminAPI 中可以用于这些方法和其他方法的选项取决于方法本身,因为每个方法都允许一个或多个选项。表 11-2 显示了表 11-1 中方法可用的选项。

表 11-2

沙盒方法的选项(dba 类)

|

功能

|

[计]选项

|

描述

| | --- | --- | --- | | delete_sandbox_instance | sandboxDir | 将被删除的新实例位置的路径 | | deploy_sandbox_instance | portx | 新实例将侦听 X 协议连接的端口 | |   | sandboxDir | 将部署新实例的路径 | |   | password | 新实例上 MySQL root 用户的密码 | |   | allowRootFrom | 创建远程根帐户,仅限于给定的地址模式(%) | |   | ignoreSslError | 默认情况下,为新实例添加 SSL 支持时忽略错误:true | | kill_sandbox_instance | sandboxDir | 将部署新实例所在的路径 | | start_sandbox_instance | sandboxDir | 将启动新实例的路径 | | stop_sandbox_instance | password | 已部署实例上 MySQL root 用户的密码 | |   | sandboxDir | 新实例将停止的路径 |

这些选项以简单 JSON 文档的形式在字典中指定。例如,如果您想要停止端口 13004 上的实例,并指定沙箱目录和密码,您可以按如下方式调用方法。

> stop_sandbox_instance(13004, {'sandboxDir':'/home/cbell/data1', 'password':'secret'})

警告

如果您使用sandboxDir选项来改变沙箱的位置,您必须确保为每个允许它的方法使用它;否则,您的一些沙盒实例可能会被放置在默认位置。

表 11-3 显示了该类中用于设置和配置 MySQL 实例和集群的其余方法。

表 11-4

dba 类方法的选项

|

面积

|

[计]选项

|

描述

| | --- | --- | --- | | 一般 | 大多数方法的通用选项 | |   | verifyMyCnf | 实例的 MySQL 配置文件的可选路径。如果给定了这个选项,那么除了全局 MySQL 系统变量之外,还将验证配置文件的预期选项值。 | |   | outputMycnfPath | 写入实例的 MySQL 配置文件的备选输出路径 | |   | password | 要在连接上使用的密码 | |   | clusterAdmin | 要创建的 InnoDB 集群管理员用户的名称。支持的格式是标准的 MySQL 帐户名格式。 | |   | clusterAdminPassword | InnoDB 集群管理员帐户的密码 | |   | clearReadOnly | 用于确认必须禁用 super_read_only 的布尔值 | |   | interactive | 用于在命令执行中禁用向导的布尔值,即不向用户提供提示,也不显示确认提示 | | URI 还是字典 | 安全连接的选项 | |   | ssl-mode | 要在连接中使用的 SSL 模式 | |   | ssl-ca | PEM 格式的 X509 证书颁发机构的路径 | |   | ssl-capath | 包含 PEM 格式的 X509 证书颁发机构的目录路径 | |   | ssl-cert | PEM 格式的 X509 证书的路径 | |   | ssl-key | PEM 格式的 X509 密钥的路径 | |   | ssl-crl | 包含证书吊销列表的文件的路径 | |   | ssl-crlpath | 包含证书吊销列表文件的目录路径 | |   | ssl-cipher | 要使用的 SSL 密码 | |   | tls-version | 安全连接允许的协议列表 | |   | auth-method | 认证方法 | |   | get-server-public-key | 向服务器请求基于 RSA 密钥对的密码交换所需的公钥。在禁用 SSL 模式的情况下,使用经典 MySQL 会话连接 MySQL 8.0 服务器时使用。 | |   | server-public-key-path | 文件的路径名,该文件包含服务器进行基于 RSA 密钥对的密码交换所需的公钥的客户端副本 | | 连接词典 | 连接参数 | |   | scheme | 要在连接上使用的协议 | |   | user | 要在连接上使用的 MySQL 用户名 | |   | dbUser | 用户的别名 | |   | password | 要在连接上使用的密码 | |   | dbPassword | 与密码相同 | |   | host | TCP 连接上使用的主机名或 IP 地址 | |   | port | TCP 连接中使用的端口 | |   | socket | 要在通过 unix 套接字的连接上使用的套接字文件名 | |   | schema | 连接完成后要选择的模式。 |

表 11-3

实例和集群方法(dba 类)

|

返回

|

功能

|

描述

| | --- | --- | --- | | 数据 | check_instance_configuration(InstanceDef instance, dict options) | 验证 MySQL InnoDB 集群使用情况的实例 | | 没有人 | configure_local_instance(InstanceDef instance, dict options) | 验证和配置 MySQL InnoDB 集群使用的本地实例 | | 没有人 | configure_instance(InstanceDef instance, dict options) | 验证和配置 MySQL InnoDB 集群使用的实例 | | 串 | create_cluster(str name, dict options) | 创建一个 MySQL InnoDB 集群 | | 没有人 | drop_metadata_schema(dict options) | 删除元数据架构 | | 串 | get_cluster(str name, dict options) | 从元数据存储中检索到一个群集 | | 没有人 | reboot_cluster_from_complete_outage(str clusterName, dict options) | 当所有成员脱机时,使群集重新联机 |

这些方法的选择更多。事实上,有些方法允许一长串选项。下面的列表没有列出每种方法的每个选项,而是将选项总结为三个类别。在演示过程中,我们将看到其中一些技术的实际应用。某些方法需要更具体的选项。

cluster 类是 InnoDB 集群的句柄(想想对象实例)。cluster 类使您能够使用集群来添加实例、删除实例、获取集群的状态(健康状况)等。

由于该类用于直接处理实例和集群,因此大多数方法都设计为处理通过 dba 类检索的特定集群实例。表 11-5 列出了集群类中的方法。

表 11-5

Cluster 类的方法

|

返回

|

功能

|

描述

| | --- | --- | --- | | 没有人 | add_instance(InstanceDef instance, dict options) | 向群集添加实例 | | 词典 | check_instance_state (InstanceDef instance, str password) | 验证与集群相关的实例 GTID 状态 | | 潜艇用热中子反应堆(submarine thermal reactor 的缩写) | describe() | 描述集群的结构 | | 没有人 | disconnect() | 断开群集对象使用的所有内部会话 | | 没有人 | dissolve(Dictionary options) | 溶解群集 | | 没有人 | force_quorum_using_partition_of(InstanceDef instance, str password) | 从仲裁丢失中恢复群集 | | 潜艇用热中子反应堆(submarine thermal reactor 的缩写) | get_name() | 检索群集的名称 | | 没有人 | rejoin_instance(InstanceDef instance, dict options) | 将实例重新加入集群 | | 没有人 | remove_instance(InstanceDef instance, dict options) | 从集群中删除实例 | | 没有人 | rescan() | 重新扫描集群 | | 潜艇用热中子反应堆(submarine thermal reactor 的缩写) | status() | 描述集群的状态 | | 没有人 | switch_to_single_primary_mode(InstanceDef instance) | 将群集切换到单主模式 | | 没有人 | switch_to_multi_primary_mode() | 将群集切换到多主模式... | | 没有人 | set_primary_instance(InstanceDef instance) | 选举一个特定的集群成员作为新的主集群成员 | | 潜艇用热中子反应堆(submarine thermal reactor 的缩写) | options(dict options) | 列出了群集配置选项 | | 没有人 | set_option(str option, str value) | 更多地更改整个集群的配置选项值... | | 没有人 | set_instance_option(InstanceDef instance, str option, str value) | 更改集群成员中配置选项的值... | | 空的 | invalidate () | 将群集标记为无效(例如,已解散) |

请注意,我们有添加、移除和重新加入实例的方法。在管理集群中的实例时,我们会经常用到它们。还有几种方法可以获得信息、状态,并强制更新元数据,如get_name()status()rescan()

我们还有切换实例模式的方法,如果我们想要手动将主要角色更改为特定实例,这将非常方便。我们还有显示和设置集群常规选项的方法,这同样有助于维护。

注意,也像dba类一样,一些方法接受选项字典。这些选项也是该方法所特有的,但是通常使用上一节中描述的相同选项来连接到实例。如前所述,有些允许特定于方法的选项。

该类有一个属性:集群的名称。该属性简单地命名为 name,可以通过编程方式设置,但通常是在使用dba类创建集群时设置的。

小费

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

现在,我们已经对 AdminAPI 中的类和方法有了一个简要的概述,让我们通过在沙箱中设置 InnoDB 集群来看看它的运行情况。

设置和配置

要准备使用沙箱,您只需要决定一些参数,并在系统上准备一个区域来处理集群的数据。有一个参数是必需的。我们必须决定实验集群要使用的端口号。在这种情况下,我们将使用端口 3311-3314 作为服务器监听端口。

我们还可以指定一个目录来包含沙盒数据。虽然这不是必需的,但如果您希望以后重新初始化群集,建议这样做。不需要另外指定目录,因为 AdminAPI 使用沙箱的预定路径。例如,在 Windows 上,它位于名为MySQL\mysql-sandboxes的用户目录中。该文件夹形成了存储沙箱的所有数据和元数据的根。例如,当您使用端口 3312 将一个实例部署到沙箱时,您将看到一个具有该名称的文件夹,如下所示。

C:\Users\cbell\MySQL\mysql-sandboxes\3312

如果您计划重用或重启集群,您可能希望使用sandboxDir选项指定一个特定的文件夹。例如,您可以在 AdminAPI 中将字典指定为{'sandboxDir':'c://idc_sandbox'}。然而,这个文件夹必须存在,否则当你调用deploy_sandbox_instance()方法时会得到一个错误。清单 11-1 显示了 Windows 上的一个定制沙箱目录,在端口 3311 上部署了一个实例。

C:\idc_sandbox>dir
 Volume in drive C is Local Disk
 Volume Serial Number is AAFC-6767

 Directory of C:\idc_sandbox

05/09/2019  07:18 PM    <DIR>          .
05/09/2019  07:18 PM    <DIR>          ..
05/09/2019  07:18 PM    <DIR>          3311               0 File(s)              0 bytes
               3 Dir(s)  172,731,768,832 bytes free

C:\idc_sandbox>dir 3311
 Volume in drive C is Local Disk
 Volume Serial Number is AAFC-6767

 Directory of C:\idc_sandbox\3311

05/09/2019  07:19 PM    <DIR>          .
05/09/2019  07:19 PM    <DIR>          ..
05/09/2019  07:19 PM                 6 3311.pid
05/09/2019  07:18 PM               726 my.cnf
05/09/2019  07:18 PM    <DIR>          mysql-files
05/09/2019  07:18 PM    <DIR>          sandboxdata
05/09/2019  07:18 PM               147 start.bat
05/09/2019  07:18 PM               207 stop.bat
               4 File(s)          1,086 bytes
               4 Dir(s)  172,557,893,632 bytes free

Listing 11-1Creating a Directory for the Sandbox

注意

要重用实例数据,必须启动实例。尝试使用相同的端口重新部署它将会产生错误,因为目录不为空。

现在,让我们来看一个在沙箱中设置集群的演示。创建 InnoDB 集群的沙盒部署有几个步骤。它们如下。

  • 在沙箱中创建和部署实例:设置和配置我们的 MySQL 服务器。

  • *创建集群:*创建集群类的对象实例。

  • 向集群添加实例:向集群添加沙盒实例。

  • 检查集群状态:检查集群健康状况。

我们还将通过终止其中一个实例来演示故障转移在集群中是如何工作的。我们开始吧!

在沙箱中创建和部署实例

让我们从启动 shell 并使用 AdminAPI 部署四台服务器开始。在这种情况下,我们将使用端口 3311-3314 和 dba 对象中的deploy_sandbox_instance()方法为每个服务器创建新的实例。所有这些都将在我们的本地主机上运行。

注意

没有必要导入dba类。MySQL Shell 使它在您切换到 Python 模式时可用。

沙箱是在第一次调用 deploy 方法时创建的。让我们现在部署四台服务器。deploy 方法将要求您为 root 用户提供密码。建议您对所有四台服务器使用相同的密码。

注意

您必须创建为沙箱指定的文件夹。

清单 11-2 展示了如何部署四台服务器。使用的命令以粗体突出显示,有助于从消息中识别命令。请注意,我以 Python 模式启动了 shell。为了便于参考,这四个命令以粗体显示。

$ mysqlsh --py

MySQL Shell 8.0.16
...
Type '\help' or '\?' for help; '\quit' to exit.

> sandbox_options = {'sandboxDir':'/home/cbell/idc_sandbox'}

> dba.deploy_sandbox_instance(3311, sandbox_options)

A new MySQL sandbox instance will be created on this host in
/home/cbell/idc_cluster/3311
Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.
Please enter a MySQL root password for the new instance: ∗∗∗∗
Deploying new MySQL instance...
Instance localhost:3311 successfully deployed and started.
Use shell.connect('root@localhost:3311'); to connect to the instance.

> dba.deploy_sandbox_instance(3312, sandbox_options)

A new MySQL sandbox instance will be created on this host in
/home/cbell/idc_cluster/3312
Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.
Please enter a MySQL root password for the new instance: ∗∗∗∗
Deploying new MySQL instance...
Instance localhost:3312 successfully deployed and started.
Use shell.connect('root@localhost:3312'); to connect to the instance.

> dba.deploy_sandbox_instance(3313, sandbox_options)

A new MySQL sandbox instance will be created on this host in
/home/cbell/idc_cluster/3313
Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.
Please enter a MySQL root password for the new instance: ∗∗∗∗
Deploying new MySQL instance...
Instance localhost:3313 successfully deployed and started.
Use shell.connect('root@localhost:3313'); to connect to the instance.

> dba.deploy_sandbox_instance(3314, sandbox_options)

A new MySQL sandbox instance will be created on this host in
/home/cbell/idc_cluster/3314
Warning: Sandbox instances are only suitable for deploying and
running on your local machine for testing purposes and are not
accessible from external networks.
Please enter a MySQL root password for the new instance: ∗∗∗∗
Deploying new MySQL instance...
Instance localhost:3314 successfully deployed and started.
Use shell.connect('root@localhost:3314'); to connect to the instance.

Listing 11-2Creating Local Server Instances

注意,deploy_sandbox_instance()方法显示沙箱数据和元数据的位置(例如,c:\\idc_sandbox\\3314),并提示我们输入实例的密码。如果您打算重新启动或重新使用群集,请确保使用一个容易记住的密码。可以对所有实例使用相同的密码。一旦您运行了所有的命令,您将有四个实例在本地机器上运行。

dba 类中有一个经常被忽略的特性。check_instance_configuration()方法允许您检查一个实例是否被正确配置用于 InnoDB 集群。您可以在沙盒实例上运行它(但是它们总是兼容的),或者更好的是,您可以在远程实例上运行它,以便在将它们添加到集群之前检查它们。清单 11-3 演示了运行检查。这是构建集群之前的推荐步骤。请注意,您必须首先连接到实例。

> \connect root@localhost:3311

Creating a session to 'root@localhost:3311'
Please provide the password for 'root@localhost:3311': ∗∗∗∗
Save password for 'root@localhost:3311'? [Y]es/[N]o/Ne[v]er (default No): Y
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 12
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> dba.check_instance_configuration()

Validating local MySQL instance listening at port 3311 for use in an InnoDB cluster...
Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as OPTIPLEX-7010
Clients and other cluster members will communicate with it through this address by default. If this is not correct, the report_host MySQL system variable should be changed.

Checking whether existing tables comply with Group Replication requirements...
No incompatible tables detected

Checking instance configuration...
Instance configuration is compatible with InnoDB cluster

The instance 'localhost:3311' is valid for InnoDB cluster usage.

{
    "status": "ok"
}

Listing 11-3Checking an Instance for Configuration Compatibility

还有一种自动配置本地实例的方法。使用configure_local_instance()方法进行任何必要的更改,以便为 InnoDB 集群正确配置本地实例。如果您正在使用已配置 MySQL 复制的现有 MySQL 服务器,这将非常方便。

创建集群

我们需要做的下一件事是建立一个新的集群。我们使用 dba 对象中的create_cluster()方法来实现这一点,该方法为集群类创建一个对象实例。但是首先,我们必须连接到我们希望作为主服务器的服务器。请注意,这是我们的 shell 会话的延续,演示了如何创建新的集群。注意清单 11-4 中是如何做到的。

\connect root@localhost:3311

Creating a session to 'root@localhost:3311'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 9
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> my_cluster = dba.create_cluster('MyClusterSB')

A new InnoDB cluster will be created on instance 'root@localhost:3311'.

Validating instance at localhost:3311...
Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as localhost

Instance configuration is suitable.
Creating InnoDB cluster 'MyClusterSB' on 'root@localhost:3311'...

Adding Seed Instance...
Cluster successfully created. Use Cluster.add_instance() to add MySQL instances.
At least 3 instances are needed for the cluster to be able to withstand up to
one server failure.

Listing 11-4Creating a Cluster in InnoDB Cluster MySQL Py >

注意,我们将集群命名为MyClusterSB,并使用一个名为my_cluster的变量来存储从create_cluster()方法返回的对象。还要注意,我们首先连接的服务器已经成为主服务器,AdminAPI 检测到我们正在沙箱中运行。

无法创建集群

如果您的本地机器运行的 MySQL 实例不是复制拓扑的一部分,您可能会得到一个错误,抱怨主机不可用于组复制或解析为127.0.0.1,您必须停止您的每个沙盒实例,编辑my.cnf,将report_host选项设置为localhost,将report_port选项设置为实例的端口。然后启动实例,如下文所示。对每个部署的实例重复上述步骤。还要注意,在每个实例文件夹中都有一个特殊的启动和停止脚本,您可以使用它来快速启动和停止实例。酷吧。

$ cd ~/idc_sandbox
$ ./3311/stop.sh
Stopping MySQL sandbox using mysqladmin shutdown... Root password is required.
Enter password:
$ nano ./3311/my.cnf
...
report_host='localhost'
report_port=3311
$ ./3311/start.sh
Starting MySQL sandbox

注意,如果您在 shell 中使用dba.stop_sandbox_instance(),这将从沙箱中完全删除实例。最好使用助手脚本(stop.sh 或 stop.bat)来停止实例。但是,您可以通过使用传入实例端口的start_sandbox_instance()方法从 shell 内部启动实例。

> dba.start_sandbox_instance(3314, sandbox_options)
The MySQL sandbox instance on this host in
/home/cbell/idc_sandbox/3314 will be started
Starting MySQL instance...
Instance localhost:3314 successfully started.

小费

如果退出 shell,可以用get_cluster()方法检索正在运行的集群。例如,您可以重启 shell,然后发出命令my_cluster = dba.get_cluster('MyClusterSB')

将实例添加到集群

接下来,我们添加另外两个服务器实例来完成集群。我们现在使用保存在变量my_cluster中的集群类实例,并使用add_instance()。我们将剩余的三个实例添加到集群中。这些服务器自动成为组中的辅助服务器。清单 11-5 展示了如何将实例添加到集群中。

> my_cluster.add_instance('root@localhost:3312')

A new instance will be added to the InnoDB cluster. Depending on the amount of data on the cluster this might take from a few seconds to several hours.

Adding instance to the cluster ...

Please provide the password for 'root@localhost:3312': ∗∗∗∗
Save password for 'root@localhost:3312'? [Y]es/[N]o/Ne[v]er (default No): Y
Validating instance at localhost:3312...
Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as localhost

Instance configuration is suitable.
The instance 'root@localhost:3312' was successfully added to the cluster.

> my_cluster.add_instance('root@localhost:3313')

A new instance will be added to the InnoDB cluster. Depending on the amount of data on the cluster this might take from a few seconds to several hours.

Adding instance to the cluster ...

Please provide the password for 'root@localhost:3313': ∗∗∗∗
Save password for 'root@localhost:3313'? [Y]es/[N]o/Ne[v]er (default No): Y
Validating instance at localhost:3313...
Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as localhost

Instance configuration is suitable.
The instance 'root@localhost:3313' was successfully added to the cluster.

> my_cluster.add_instance('root@localhost:3314')

A new instance will be added to the InnoDB cluster. Depending on the amount of data on the cluster this might take from a few seconds to several hours.

Adding instance to the cluster ...

Please provide the password for 'root@localhost:3314': ∗∗∗∗
Save password for 'root@localhost:3314'? [Y]es/[N]o/Ne[v]er (default No): Y
Validating instance at localhost:3314...
Instance detected as a sandbox.
Please note that sandbox instances are only suitable for deploying test clusters for use within the same host.

This instance reports its own address as localhost

Instance configuration is suitable.
The instance 'root@localhost:3314' was successfully added to the cluster.

Listing 11-5Adding Instances to the Cluster

注意,add_instance()方法接受一个带有 URI 连接信息的字符串。在这种情况下,它只是用户名、at 符号(@)、主机名和端口,格式为<user>@<host>:<port>。另请注意,该方法提示输入实例的密码。

至此,我们已经了解了 InnoDB Cluster 如何设置服务器并将它们添加到组中。花点时间回想一下组复制教程。您在幕后看不到的是所有的组复制机制—您可以免费获得它们!这有多酷?

显然,使用 shell 来设置和管理集群比设置和管理标准的组复制设置要容易得多。具体来说,您不必手动配置复制!更好的是,如果服务器出现故障,您不必担心重新配置您的应用或拓扑来确保解决方案保持可行——InnoDB Cluster 会自动为您完成这一任务。

检查集群的状态

一旦创建了集群并添加了实例,我们就可以使用我们的my_cluster对象的status()方法来获取集群的状态,如清单 11-6 所示。在本例中,我们还将看到如何通过连接\connect 命令并使用 dba 类中的get_cluster()方法,从一个正在运行的服务器实例中检索集群。您还可以使用命令行(mysqlsh --uri root@localhost:3313)连接到服务器实例。请注意,您不必连接到第一个(或主)服务器实例来检索集群。您可以连接到任何服务器来检索集群。

> \connect root@localhost:3313

Creating a session to 'root@localhost:3313'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 30
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> my_cluster = dba.get_cluster('MyClusterSB')

> my_cluster.status()

{
    "clusterName": "MyClusterSB",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "localhost:3311",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "localhost:3311": {
                "address": "localhost:3311",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3312": {
                "address": "localhost:3312",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "localhost:3311"
}

Listing 11-6Getting the status of the cluster

注意,输出是 JSON 文档的形式,包含关于集群的元数据,包括所有实例、它们的角色和状态。您希望确保所有实例都在线。

现在,让我们来看看群集如何自动处理故障转移的演示。

故障转移演示

现在,让我们来模拟一个故障场景。在这种情况下,我们将有目的地删除其中一个实例。让我们杀了在 3311 端口上运行的那个。我们可以通过多种方式实现这一点,例如使用操作系统终止 mysqld 进程,从 shell 或 MySQL 客户端或 dba 类使用 shutdown SQL 命令。清单 11-7 显示了如何终止实例以及实例停止后的状态结果。

> sandbox_options = {'sandboxDir':'/home/cbell/idc_sandbox'}

 MySQL  Py > \connect root@localhost:3311
Creating a session to 'root@localhost:3311'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 55
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> dba.kill_sandbox_instance(3311, sandbox_options)

The MySQL sandbox instance on this host in
/home/cbell/idc_sandbox/3311 will be killed

Killing MySQL instance...

Instance localhost:3311 successfully killed.

> \connect root@localhost:3312

Creating a session to 'root@localhost:3312'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 38
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> my_cluster = dba.get_cluster('MyClusterSB')

> my_cluster.status()

{
    "clusterName": "MyClusterSB",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "localhost:3313",
        "ssl": "REQUIRED",
        "status": "OK_PARTIAL",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure. 1 member is not active",
        "topology": {
            "localhost:3311": {
                "address": "localhost:3311",
                "mode": "n/a",
                "readReplicas": {},
                "role": "HA",
                "status": "(MISSING)"
            },
            "localhost:3312": {
                "address": "localhost:3312",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "localhost:3313"
}

Listing 11-7
Failover Demonstration

请注意,我们终止了运行在端口 3311 上的服务器。然而,当我们去获取集群时,我们得到了一个错误。这是因为我们已经连接到我们杀死的服务器(3311)。因此,我们需要连接到另一个服务器并再次检索集群来刷新数据。然后,我们可以获得状态,当我们这样做时,我们会看到端口 3311 上的服务器实例被列为缺失,端口 3312 上的服务器已经接管了读写功能。

此时,我们可以尝试恢复端口 3311 上的服务器实例,或者将其从集群中删除。清单 11-8 演示了如何从集群中删除它。请注意,我们使用 recover 方法删除实例,因为我们无法连接到它(它已关闭)。

> my_cluster.rescan()

Rescanning the cluster...

Result of the rescanning operation for the 'default' ReplicaSet:

{

    "name": "default",
    "newTopologyMode": null,
    "newlyDiscoveredInstances": [],
    "unavailableInstances": [
        {
            "host": "localhost:3311",
            "label": "localhost:3311",
            "member_id": "27e8019b-8315-11e9-9f3e-5882a8945ac2"
        }
    ]

}

The instance 'localhost:3311' is no longer part of the ReplicaSet.

The instance is either offline or left the HA group. You can try to add it to the cluster again with the cluster.rejoinInstance('localhost:3311') command or you can remove it from the cluster configuration.

Would you like to remove it from the cluster metadata? [Y/n]: y

Removing instance from the cluster metadata...

The instance 'localhost:3311' was successfully

removed from the cluster.

> my_cluster.status()

{
    "clusterName": "MyClusterSB",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "localhost:3313",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "localhost:3312": {
                "address": "localhost:3312",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            }
        },
        "topologyMode": "Single-Primary"
    },
    "groupInformationSourceMember": "localhost:3313"
}

Listing 11-8Removing Downed Instance from Cluster

要添加丢失的实例,只需通过运行位于沙盒数据目录中的 start 命令(例如,idc_sandbox\3311\start.bat)重新启动它,并使用如下的rescan()方法将其添加回集群。使用此方法添加以前属于群集的实例。如果要用一个新的实例来替换整个实例,可以使用add_instance()方法。

> my_cluster.rescan()

Rescanning the cluster...

Result of the rescanning operation for the 'default' ReplicaSet:
{
    "name": "default",
    "newTopologyMode": null,
    "newlyDiscoveredInstances": [
        {
            "host": "localhost:3311",
            "member_id": "1e8f53e2-7335-11e9-9bb1-4ccc6ae8a7a4",
            "name": null,
            "version": "8.0.16"
        }
    ],
    "unavailableInstances": []
}
A new instance 'localhost:3311' was discovered in the ReplicaSet.
Would you like to add it to the cluster metadata? [Y/n]: y
Adding instance to the cluster metadata...
The instance 'localhost:3311' was successfully added to the cluster metadata.

既然我们已经了解了如何创建 InnoDB 集群,那么让我们简单地讨论一下如何设置 MySQL Router 以用于集群和一个测试应用。

使用 MySQL 路由器

如前所述,如果不简要了解一下 MySQL 路由器,对 InnoDB 集群的任何介绍都是不完整的。在本节中,我们将看到一个设置路由器并将其用于应用的简短教程。我们将使用一个简单的 Python 脚本来演示应用级故障转移。

引导路由器

回想一下,配置路由器是创建 InnoDB 集群的步骤,这可能需要一些额外的设置。虽然这是事实,但在大多数情况下,路由器可以自行配置。只有当您的群集变得很大,或者您已经为性能(读取扩展)定制了群集,或者您想要路由到多个应用或多个群集时,才需要这样做。

小费

如果您还没有安装 MySQL 路由器,现在必须安装。有些平台,如 Linux,可能需要单独下载软件包。

幸运的是,我们可以使用特殊的引导选项连接到您的集群,读取元数据,然后自动更新配置文件。如果您使用沙盒安装,这是设置路由器的最快和最可靠的方法。即使您没有使用沙盒安装,也可以使用这种方法快速设置基本配置,以后可以根据需要进行更改。

让我们看看如何使用引导选项。要使用该选项,我们需要一些其他参数。我们需要以下内容。简而言之,必须提供连接信息和用户来保护配置文件。我们还添加了一个可选参数来为配置提供一个名称,如果您正在使用不同的集群或配置,这可能会很有帮助。

  • --bootstrap <server_url>:引导并配置路由器,以便与 MySQL InnoDB 集群一起运行。也可以使用快捷键-B

  • --name:(可选)给路由器实例一个符号名。

  • --user <username>:以指定的用户名运行路由器(在 Windows 上不可用)。也可以使用快捷键-u

在本例中,我们以 URI(如<username>:<password>@<hostname>:<port>)的形式提供带有引导选项的连接信息。我们还将使用本地用户,以便更容易地使用沙盒安装来运行路由器,沙盒安装也是在当前用户下运行的。因此,我们将使用以下命令。我们使用提升的权限,因为路由器文件的默认位置是受保护的。

$ sudo mysqlrouter --bootstrap root:secret@localhost:3313 \
  --name sandbox --user cbell

当我们运行这个命令时,路由器将联系我们指定的服务器,并检索集群的所有元数据,为我们自动创建路由。清单 11-9 显示了该命令的输出示例。

$ sudo mysqlrouter --bootstrap root:secret@localhost:3313 --name sandbox --user cbell
# Bootstrapping system MySQL Router instance...
Fetching Group Replication Members
disconnecting from mysql-server
trying to connecting to mysql-server at localhost:3313
- Checking for old Router accounts
  - No prior Router accounts found
- Creating mysql account mysql_router1_9twobjgwueud@'%' for cluster management
- Storing account in keyring
- Adjusting permissions of generated files
- Creating configuration /etc/mysqlrouter/mysqlrouter.conf

# MySQL Router 'sandbox' configured for the InnoDB cluster 'MyClusterSB'

After this MySQL Router has been started with the generated configuration

    $ /etc/init.d/mysqlrouter restart
or
    $ systemctl start mysqlrouter
or
    $ mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf

the cluster 'MyClusterSB' can be reached by connecting to:

## MySQL Classic protocol

- Read/Write Connections: localhost:6446
- Read/Only Connections:  localhost:6447

## MySQL X protocol

- Read/Write Connections: localhost:64460
- Read/Only Connections:  localhost:64470

Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak'

Listing 11-9Configuration with the Bootstrap Option

请注意,我们看到路由器已经分别使用默认端口 6446 和 6447 为我们标识了读写(RW)和只读(RO)连接。我们还看到引导步骤分别在端口 64460 和 64470 上创建使用 X 协议的路由。在我们测试路由器之前,让我们了解一下自举方法为我们做了什么。具体来说,我们将查看修改后的配置文件。

现在,我们可以启动路由器了。

启动路由器

我们可以使用以下命令启动路由器。这将启动路由器,它将读取配置文件。请注意,我们没有使用提升的特权。这是因为我们在引导步骤中提供了一个用户选项,允许用户读取文件。这对于保护您的安装非常重要,我们将在后面的章节中探讨这一点。

$ mysqlrouter &
Loading all plugins.
  plugin 'logger:' loading
  plugin 'metadata_cache:MyClusterSB' loading
  plugin 'routing:MyClusterSB_default_ro' loading
  plugin 'routing:MyClusterSB_default_rw' loading
  plugin 'routing:MyClusterSB_default_x_ro' loading
  plugin 'routing:MyClusterSB_default_x_rw' loading
Initializing all plugins.
  plugin 'logger' initializing
logging facility initialized, switching logging to loggers specified in configuration

现在我们已经配置了路由器,让我们用示例 Python 连接脚本来测试它。

示例应用

现在我们已经安装了路由器,为 InnoDB 集群进行了配置,并且正在运行,让我们看看如何使用一个简单的 Python 脚本来测试路由器。

清单 11-10 展示了一个通过路由器连接到 InnoDB 集群的简单 Python 脚本。回想一下,我们在我们的机器上安装了路由器,因此这个脚本(为了一致性,如果不是练习的话)应该在同一台机器上执行。花点时间检查一下代码。如果您正在跟进,您可以在您的机器上将文件保存为router_connection_test.py

#
# Introducing MySQL Shell
#
# This example shows how to use the MySQL Router to connect to
# the cluster. Notice how connecting via the router port 6446
# results in a seamless transport to one of the cluster servers,
# in this case, the server with the primary role.
#
# Dr. Charles Bell, 2019
#
import mysql.connector

# Simple function to display results from a cursor
def show_results(cur_obj):
  for row in cur:
    print(row)

my_cfg = {
  'user':'root',
  'passwd':'secret',
  'host':'127.0.0.1',
  'port':6446   # <<<< Router port (R/W)
}

# Connecting to the server
conn = mysql.connector.connect(∗∗my_cfg)

print("Listing the databases on the server.")
query = "SHOW DATABASES"
cur = conn.cursor()
cur.execute(query)
show_results(cur)

print("\Retrieve the port for the server to which we’re connecting.")
query = "SELECT @@port"
cur = conn.cursor()
cur.execute(query)
show_results(cur)

# Close the cursor and connection
cur.close()
conn.close()

Listing 11-10Router Connection Test

代码的第一部分简单地导入连接器并定义一个连接术语字典。在这种情况下,是路由器的用户、口令、主机和端口。我们使用的端口号是 6446,如路由器配置过程中所示。

接下来,代码打开一个连接,然后运行两个查询:一个获取数据库列表并显示它们(使用定义为show_results()的函数),另一个选择服务器的当前端口。我们将看到,第二个查询结果可能会让您感到惊讶。

要执行代码,请保存名为 router_connect_test.py 的文件(扩展名将其标识为 Python 脚本)。然后,使用以下命令运行代码。

$ python ./router_connection_test.py
Listing the databases on the server.
(u'information_schema',)
(u'mysql',)
(u'mysql_innodb_cluster_metadata',)
(u'performance_schema',)
(u'sys',)
Retrieve the port for the server to which we’re connecting.
(3313,)

等等!为什么输出显示端口 3313?不应该显示端口 6446 吗?毕竟,这是我们在代码中使用的端口。回想一下,路由器只是将通信路由到适当的服务器,它本身不是服务器连接。因此,路由器成功地将我们的连接路由到端口 331 上的机器。回想一下,这台机器是主机器(在集群中列为读写机器)。

那么我们如何连接到集群中的只读服务器呢?我们现在需要做的就是修改程序来连接只读服务器(在端口 6447 上)。当我们重新运行脚本时,我们将看到以下输出。

$ python ./router_connection_test.py
Listing the databases on the server.
(u'information_schema',)
(u'mysql',)
(u'mysql_innodb_cluster_metadata',)
(u'performance_schema',)
(u'sys',)
Retrieve the port for the server to which we're connecting.
(3312,)

现在我们看到我们连接到的不是端口 3311 上的服务器。回想一下沙箱设置,端口 3312、3313 和 3314 上的机器都是只读的。

虽然这个例子很简单,但它确实说明了路由器如何将连接重定向到其他 MySQL 服务器。它还有助于强化这样一个概念,即我们必须将我们的应用连接到路由器本身,而不是集群中的机器,并允许路由器为我们完成所有繁重的连接路由。正如您所看到的,它非常复杂,并根据其初始(和后来缓存的)配置知道基于路由器监听的端口请求哪些服务器。在这种情况下,我们使用 6446 进行读写连接,使用 6447 进行只读连接。是的,就是这么简单。不再有复杂的硬编码端口!

应用故障转移演示

现在,让我们只在应用层尝试故障转移。更具体地说,我们将终止集群中的读写(或主)服务器,然后再次启动脚本。回想一下,我们想要连接到路由器正在使用的读写端口,在本例中是端口 6446。在运行这个测试之前,一定要检查脚本中的my_cfg字典。

花点时间验证集群中的哪个实例具有读写角色(主实例)。我们可以如下使用 shell 来实现这一点。这里我们看到端口 3313 上的服务器具有读写模式。

$ mysqlsh --uri root@localhost:3312 --py
> dba.get_cluster('MyClusterSB').status()
...
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE",
                "version": "8.0.16"
            },

让我们首先在不终止任何实例的情况下连接到集群,并查看为读写连接返回了什么端口。

$ python ./router_connection_test.py
Listing the databases on the server.
(u'information_schema',)
(u'mysql',)
(u'mysql_innodb_cluster_metadata',)
(u'performance_schema',)
(u'sys',)

Retrieve the port for the server to which we're connecting.
(3313,)

好的,它映射到端口 3313。很好。现在,让我们毫不客气地杀死那个服务器实例。

more ~/idc_sandbox/3313/3313.pid
10264
$ sudo kill -9 10264

然后,再次运行该脚本,并查看为读写服务器显示了哪个端口。

$ python ./router_connection_test.py
Listing the databases on the server.
(u'information_schema',)
(u'mysql',)
(u'mysql_innodb_cluster_metadata',)
(u'performance_schema',)
(u'sys',)

Retrieve the port for the server to which we're connecting.
(3311,)

在这里,我们看到我们确实通过路由器连接到了 InnoDB 集群,我们看到报告的端口是 3311,这是新的主(读写)服务器的端口。酷!

该演示展示了即使集群中存在故障转移,我们也可以继续运行我们的应用。在这种情况下,我们只是简单地重新运行应用(脚本),但是在生产(或开发)中,您只需构建您的应用来重试读写端口或只读端口的连接。这样,您的应用甚至不需要重启,您只需重新连接并继续运行。这有多酷?

小费

参见 https://dev.mysql.com/doc/mysql-router/8.0/en/mysql-router-configuration.html 了解更多关于为您的应用和环境配置路由器的信息。

在我们结束关于 InnoDB 集群的讨论之前,让我们简要地讨论一下您可能想要执行的一些管理任务。

管理

正如您已经发现的,设置 InnoDB Cluster 并不困难,除了学习如何使用 MySQL Shell 和 AdminAPI 中的一些类和方法之外,配置 InnoDB Cluster 的步骤也同样简单。然而,我们从经验中知道,设置和后续管理在复杂性上并不总是一致的。

在这一节中,我们将从较高的层次来看一下您可能需要在 InnoDB 集群上执行的管理任务。我们还将看到一些您可能希望在沙箱中运行的 InnoDB 集群上执行的特定任务,这可能有助于您从测试环境过渡到开发和后续生产。

常见任务

使用 InnoDB Cluster 的首选工具是 MySQL Shell,这是本书的重点。特别有用的是,您可以用 Java 或 Python 编写自己的特殊脚本来处理集群。下面列出了使用 InnoDB 集群的常见管理任务。还有其他几种,但这些是最常见的。

  • 获取集群:当使用 MySQL Shell 管理 InnoDB 集群时,我们必须首先请求集群类的一个实例。回想一下,我们在本书中已经多次看到这种情况。为了检索集群实例,我们使用了dba.get_cluster()方法。

  • 检查集群状态:和上一个任务一样,我们已经看到了如何检索集群状态报告。回想一下,我们使用的是cluster.status()方法。我们必须连接到集群中的一个服务器,检索它,然后使用 status 方法。

  • 描述集群:您还可以获得关于集群的信息,比如集群中机器的主机名以及每个 MySQL 实例使用的端口。我们使用的命令是cluster.describe()方法。

  • 检查实例是否适合与 InnoDB 集群一起使用:我们已经看到了两种方法,您可以使用这两种方法来准备实例以与 InnoDB 集群一起使用。第一个是dba.configure_local_instance(),用于准备在集群中使用的本地机器。第二,dba.check_instance_configuration()可以用来测试服务器的设置是否正确。与第一种方法不同,检查实例配置方法可以远程运行。

  • 检查和实例化集群状态:您还可以使用dba.check_instance_state()方法检查和实例化集群的当前或最后已知状态。此方法将服务器连接信息作为参数,并返回其状态。

  • 将实例加入集群:在本书中,我们已经多次看到如何将实例加入集群。回想一下,我们使用传入连接信息的cluster.add_instance()方法连接到一个实例,以加入当前集群。

  • 从集群中删除一个实例:如果你需要对一台物理机器或者运行在服务器上的 MySQL 实例进行维护,你应该首先从集群中删除它。我们可以用cluster.remove_instance()方法做到这一点。

现在,让我们来看几个任务,它们对于探索 InnoDB 集群和使用沙盒部署可能很方便。

示例任务

以下是您可能希望在 InnoDB 集群上执行的一些特定任务,例如关闭并重新启动集群或重新启动集群。

通常,InnoDB 集群(或任何高可用性系统)永远不会完全关闭。事实上,保持系统始终运行是我们的目标。然而,对于我们运行沙箱的开发集群,我们可能不希望实例长时间运行。我们不仅希望关闭集群,还可能希望稍后重新启动它。本节介绍一种安全关闭并重新启动集群的方法。

正在关闭集群

简而言之,InnoDB 集群不是为随意打开和关闭而设计的。相反,关闭所有服务器将导致集群完全失去集群连续性。虽然这对于生产系统、对于我们的开发集群(或者任何类似的集群)来说是非常糟糕的,但是这并不是一个严重的问题。如果您发现自己想要保留集群,因为其中有您不想丢失的数据或依赖于它的应用,那么您已经超出了使用沙箱或类似的小型实验性安装的范围。

那你是做什么的?AdminAPI 在dba模块中包含从完全丢失中恢复集群的方法。但是,只有在对集群中的服务器执行受控关闭时,这种方法才有效。下面概述了可以用来关闭集群电源的过程。

  • 获取集群状态并记录读写服务器

  • 连接到每个只读服务器并关闭它们

  • 关闭读写服务器

回想一下,我们可以连接到集群中的任何机器,获取集群,并使用status()方法找到读写服务器。应该通过 MySQL Shell 或 MySQL 客户端发出如下 shutdown SQL 命令来连接到只读服务器并关闭它们。

$ mysqlsh --uri root@localhost:3311 --sql -e "SHUTDOWN"

对其他只读服务器重复此命令,然后对读写服务器重复此命令。记下哪个服务器是读写服务器。

重新启动集群

虽然您可能希望通过重启集群中的所有服务器来重新建立集群,但事实并非如此。当从头开始重新启动集群时,我们必须在 AdminAPI 中使用一种特殊的方法。这种方法适用于没有出现任何错误的集群,即那些已经成功关闭的集群。这就是所谓的从完全中断中恢复集群。然而,这只有在所有服务器都已重启,MySQL 已在所有服务器上启动,并且它们可以访问网络(以及相互访问)的情况下才有效。

下面演示了如何从完全中断中恢复集群。具体来说,服务器已经全部重启(mysqld 重启),您需要从最后一个已知良好的位置重启集群。我们将使用dba.reboot_cluster_from_complete_outage()方法重启集群。首先,当您关闭服务器并运行清单 11-11 中所示的命令时,登录到读写服务器。

$ ./3311/start.sh

Starting MySQL sandbox

$ ./3312/start.sh

Starting MySQL sandbox

$ ./3313/start.sh

Starting MySQL sandbox

$ ./3314/start.sh

Starting MySQL sandbox

$ mysqlsh --py --uri root@localhost:3313

MySQL Shell 8.0.16

Copyright (c) 2016, 2019, 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 '\?' for help; '\quit' to exit.
Creating a session to 'root@localhost:3313'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 57
Server version: 8.0.16 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.

> my_cluster = dba.reboot_cluster_from_complete_outage('MyClusterSB')

Reconfiguring the cluster 'MyClusterSB' from complete outage...

The instance 'localhost:3312' was part of the cluster configuration.
Would you like to rejoin it to the cluster? [y/N]: y

The instance 'localhost:3314' was part of the cluster configuration.
Would you like to rejoin it to the cluster? [y/N]: y

The instance 'localhost:3311' was part of the cluster configuration.
Would you like to rejoin it to the cluster? [y/N]: y

The cluster was successfully rebooted.

Listing 11-11Restarting a Cluster from Complete Outage

请注意,该命令读取集群元数据,并尝试重新连接(重新加入)所有服务器。如果成功,您将会看到指示集群已重新启动的消息。如果遇到错误,请确保所有服务器都在运行并且可以访问网络,更正任何问题,然后重试该命令。

小费

有关 InnoDB Cluster 的更多信息以及如何使用 InnoDB Cluster 的更深入报道,包括如何调整您的应用,请参见我的书介绍 InnoDB Cluster ,Bell(2018 年 4 月)。

摘要

MySQL Shell 改变了 MySQL 的游戏规则,这听起来像是炒作,但现在应该开始看起来更像事实了。我们探讨了如何在构建应用时使用 shell,或者通过它的 SQL 接口,或者通过 NoSQL 接口。在这样做的过程中,我们通过使用一个示例应用探索了 X DevAPI。在本章中,我们研究了在沙盒中创建 InnoDB 集群时使用的 AdminAPI。

既然您已经看到了如何设置 MySQL 复制以及后来的组复制,那么您现在应该对 MySQL Shell 和 AdminAPI 在用户友好性方面的巨大进步有所了解了。简而言之,InnoDB Cluster 使得使用组复制成为学习一些 API 类和方法的简单事情。最棒的是,它为 InnoDB 集群的开发操作和自动化打开了大门——迄今为止,这需要昂贵的定制工具。是的,使用 MySQL Shell,InnoDB Cluster 更易于管理和自动化。

我们的 MySQL Shell 之旅到此结束。到目前为止,您应该渴望有机会开始使用它来满足您所有的 MySQL 需求,从简单的 SQL 命令到 InnoDB 集群的管理。Shell 完成了所有的工作。

Footnotes 1

本章中的此表和后续表显示了这些方法的 Python 名称。由于 JavaScript 的 camelCase 标准不同,JavaScript 名称略有不同。