InnoDB-集群入门指南-二-

130 阅读1小时+

InnoDB 集群入门指南(二)

原文:Introducing InnoDB Cluster

协议:CC BY-NC-SA 4.0

四、MySQL Shell

可能有些被忽视的最大特性之一是新的 MySQL Shell。回想一下,MySQL Shell 是一种与 MySQL 服务器交互的新方式。与以前与服务器捆绑在一起的客户机相比,它有许多优势,最强大的是能够直接从 shell 中使用 Python 或 JavaScript。

在这一章中,你将更详细地探索 MySQL Shell。您将了解更多关于它的主要特性和选项,以及如何使用新的 shell 来交互式地执行脚本。正如您将看到的,MySQL Shell 是 MySQL 未来的另一个关键元素。

我建议在自己尝试 MySQL Shell 之前,至少通读一遍本章中的示例部分。所提供的信息将帮助您适应使用新的命令和连接,在您理解这些概念之前,这些命令和连接有时会有点混乱。

注意

我使用术语 shell 来指代 MySQL Shell 支持的特性或对象。我用 MySQL Shell 来指代产品本身。

使用 MySQL Shell

MySQL Shell 是 MySQL 产品组合中令人激动的新成员。MySQL Shell 代表了第一个连接到 MySQL 并与之交互的现代高级客户端。shell 可以用作脚本环境,用于开发处理数据的新工具和应用。酷!图 4-1 展示了一个启动 MySQL Shell 的例子。请注意显示 MySQL 徽标、连接信息和模式的漂亮提示符。很好!

img/460910_1_En_4_Fig1_HTML.jpg

图 4-1

MySQL Shell

注意

与需要服务器连接才能启动的旧客户端不同,当您在没有指定服务器连接的情况下启动 shell 时,shell 将会运行,但不会连接到服务器。您必须使用\connect shell 命令来连接到服务器。

回想一下第 2 章的内容,MySQL Shell 被设计成使用新的 X 协议通过 X 插件与服务器通信。然而,shell 也可以通过使用旧的协议连接到服务器,尽管在脚本模式中功能有限。因此,shell 允许您处理关系文档(SQL)或 JSON 文档(NoSQL),或者两者都处理。

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

以下各节从较高的层面介绍了 shell 的主要特性。有关 MySQL Shell 的更多信息,请参见在线 MySQL 参考手册( https://dev.mysql.com/doc/mysql-shell-excerpt/8.0/en/ )中的“MySQL Shell 用户指南”一节。

Shell 命令

与最初的 MySQL 客户端一样,一些特殊的命令控制应用本身,而不是与数据交互(通过 SQL 或 X DevAPI)。要执行 shell 命令,请发出带斜线(\)的命令。例如,\help打印所有 shell 命令的帮助。表 4-1 列出了一些更常用的 shell 命令。

表 4-1

Shell 命令

|

命令

|

捷径

|

描述

| | --- | --- | --- | | \ |   | 开始多行输入(仅限 SQL 模式) | | \connect | (\c) | 连接到服务器 | | \help | (\?,\h) | 打印帮助文本 | | \js |   | 切换到 JavaScript 模式 | | \nowarnings | (\w) | 不显示警告 | | \py |   | 切换到 Python 模式 | | \quit | (\q,\exit) | 放弃 | | \source | (\.) | 执行指定的脚本文件 | | \sql |   | 切换到 SQL 模式 | | \status | (\s) | 打印有关连接的信息 | | \use | (\u) | 设置会话的模式 | | \warnings | (\W) | 在每个语句后显示警告 |

注意,您可以使用\sql\js\py shell 命令来动态切换模式。这使得处理 SQL 和 NoSQL 数据更加容易,因为您不必退出应用来切换模式。此外,即使使用了启动选项来设置模式,也可以使用这些 shell 命令。

小费

要获得任何 shell 命令的帮助,请使用\help命令。例如,要了解更多关于\connect命令的信息,请输入\help connect

最后,注意您退出 shell 的方式(\q\quit)。如果您像在旧客户端中习惯的那样键入quit,shell 将根据您所处的模式做出不同的响应。以下是每种模式下发生的情况的示例:

MySQL  SQL > quit;
ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'quit' at line 1
 MySQL  SQL > \js
Switching to JavaScript mode...
 MySQL  JS > quit
ReferenceError: quit is not defined
 MySQL  JS > \py
Switching to Python mode...
 MySQL  Py > quit
Use quit() or Ctrl-D (i.e. EOF) to exit
 MySQL  Py > \q
Bye!

如果您习惯了旧的 MySQL 客户端,并且不小心使用了旧的客户端命令,您可能会看到类似的奇怪现象,但是只需要经常使用它就可以提醒您要使用的正确命令。现在,让我们看看 shell 的启动选项。

选择

可以使用几个控制模式、连接、行为等的启动选项来启动 shell。表 4-2 介绍了一些你可能想要使用的更常用的选项。您将在后面的部分中看到更多关于连接选项的内容。

表 4-2

常见的 MySQL Shell 选项

|

[计]选项

|

描述

| | --- | --- | | -f, --file=file | 用于执行的流程文件。 | | -e, --execute=<cmd> | 执行命令并退出。 | | --uri | 通过统一资源标识符(URI)连接。 | | -h, --host=<value> | 用于连接的主机名。 | | -P, --port=# | 用于连接的端口号。 | | -S, --socket=sock | UNIX 中用于连接的套接字名称或 Windows 中的命名管道名称(仅限经典会话)。 | | -u, --dbuser=<value> | 用于连接的用户。 | | --user=<value> | dbuser的别名。 | | --dbpassword=<value> | 连接到服务器时使用的密码。 | | --password=<value> | dbpassword的别名。 | | -p | 请求密码提示来设置密码。 | | -D --schema=<value> | 要使用的架构。 | | --database=<value> | --schema的别名。 | | --sql | 以 SQL 模式启动。 | | --sqlc | 使用经典会话在 SQL 模式下启动。 | | --sqlx | 使用 X 协议会话在 SQL 模式下启动。 | | --js | 以 JavaScript 模式启动。 | | --py | 以 Python 模式启动。 | | --json | 以 JSON 格式生成输出。 | | --table | 以表格格式生成输出(默认为交互模式)。 | | -i, --interactive[=full] | 为了在批处理模式下使用,它强制模拟交互模式处理。批处理中的每一行都像在交互模式下一样进行处理。 | | --log-level=value | 日志级别。值必须是 1 到 8 之间的整数或[无、内部、错误、警告、信息、调试、调试 2、调试 3]中的任何一个。 | | --mx --mysqlx | 创建一个 X 协议会话(简称为“会话”)。 | | --mc --mysql | 创建经典(旧协议)会话。 | | --ma | 创建一个带有自动协议选择的会话。 | | --nw, --no-wizard | 禁用执行脚本的向导模式(非交互式)。 | | --ssl-mode | 为连接启用 SSL(使用其他标志自动启用)。 | | --ssl-key=name | PEM 格式的 X509 密钥。 | | --ssl-cert=name | PEM 格式的 X509 证书。 | | --ssl-ca=name | PEM 格式的 CA 文件(查看 OpenSSL 文档)。 | | --ssl-capath=dir | CA 目录。 | | --ssl-cipher=name | 要使用的 SSL 密码。 | | --ssl-crl=name | 证书吊销列表。 | | --ssl-crlpath=dir | 证书吊销列表路径。 | | --tls-version=version | 要使用的 TLS 版本。允许值为 TLSv1、TLSv1.1。 | | --auth-method=method | 要使用的身份验证方法。 | | --dba=enableXProtocol | 在连接到的服务器中启用 X 协议。必须和--mysql一起使用。 |

请注意,有些选项的别名与原始客户端的用途相同。如果您有启动客户机来执行操作的脚本,这使得切换到 shell 变得更容易一些。还要注意使用安全套接字层(SSL)连接的一组选项。其中大部分都是不言自明的,你以前已经见过几个了。现在让我们看看可用的会话和连接以及如何使用它们。要获得完整的选项列表,请使用--help选项执行 shell,如清单 4-1 所示。

$ mysqlsh --help
MySQL Shell 8.0.11

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

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

Usage: mysqlsh [OPTIONS] [URI]
       mysqlsh [OPTIONS] [URI] -f <path> [script args...]
       mysqlsh [OPTIONS] [URI] --dba [command]
       mysqlsh [OPTIONS] [URI] --cluster

  -?, --help                  Display this help and exit.
  -e, --execute=<cmd>         Execute command and quit.
  -f, --file=file             Process file.
  --uri=value                 Connect to Uniform Resource Identifier. Format:
                              [user[:pass]@]host[:port][/db]
  -h, --host=name             Connect to host.
  -P, --port=#                Port number to use for connection.
  -S, --socket=sock           Socket name to use in UNIX, pipe name to use in
                              Windows (only classic sessions).
  -u, --dbuser=name           User for the connection to the server.
  --user=name                 see above
  -p, --password[=name]       Password to use when connecting to server.
  --dbpassword[=name]         see above
  -p                          Request password prompt to set the password
  -D, --schema=name           Schema to use.
  --database=name             see above
  --recreate-schema           Drop and recreate the specified schema.Schema
                              will be deleted if it exists!
  -mx, --mysqlx               Uses connection data to create Creating an X
                              protocol session

.
  -mc, --mysql                Uses connection data to create a Classic Session.
  -ma                         Uses the connection data to create the session
                              withautomatic protocol detection.
...

Listing 4-1Getting Help for MySQL Shell

小费

在 Windows 上,MySQL Shell 显示为一个应用,但是您可以将C:\Program Files\MySQL\MySQL Shell 8.0\bin添加到您的路径中,并从命令窗口执行它。

会话和模式

与最初的客户机以及实际上大多数 MySQL 客户机应用一样,您需要连接到 MySQL 服务器,以便可以运行命令。MySQL Shell 支持多种连接 MySQL 服务器的方式和多种与服务器交互的选项(称为会话)。在一个会话中,您可以更改 shell 接受命令的方式(称为模式,以包含 SQL、JavaScript 或 Python 命令。

考虑到使用服务器的所有不同的新概念,那些初学使用 shell 的人可能会发现其中的细微差别,甚至有时会感到困惑。事实上,在线参考手册和各种博客及其他报告有时会交替使用模式会话,但正如您将看到的,它们是不同的(无论多么微妙)。下面几节阐明了每个主要概念,包括会话、模式和连接,以便您可以更快地适应新方法。我首先用简单的例子介绍概念,然后用详细的例子讨论如何建立联系。让我们从查看可用的会话对象开始。

会话对象

关于会话 s,首先要理解的是,会话是到单个服务器的连接。第二件要理解的事情是,每个会话都可以从两个会话对象中的一个开始。会话是到服务器的连接(定义了所有参数),会话对象是 shell 用来以几种方式之一与服务器交互的对象。更具体地说,MySQL Shell 会话对象定义了您如何与服务器交互,包括支持哪些模式,甚至 Shell 如何与服务器通信。shell 支持如下两个会话对象:

  • 会话:X 协议会话用于应用开发,支持 JavaScript、Python、SQL 模式。通常用于开发脚本或执行脚本。要使用该选项启动 shell,请使用--mx ( --mysqlx)选项。

  • 经典会话:使用旧的服务器通信协议,对 DevAPI 的支持有限。对没有 X 插件或不支持 X 协议的旧服务器使用这种模式。通常用于旧服务器的 SQL 模式。要使用该选项启动 shell,请使用--mc ( --mysqlc)选项。

注意

经典会话仅在 MySQL Shell 中可用。它不是 X DevAPI 的一部分。通过 X DevAPI,只有通过 X 协议的会话连接是可用的。

当您使用\connect shell 命令时,您可以通过指定-mc用于经典会话、-mx用于 X 协议会话或-ma用于自动协议选择来指定要使用的会话对象(协议)。下面依次展示了其中的每一个。注意<URI>指定了一个统一的资源标识符。

  • \connect -mx <URI>:使用 X 协议(会话)。

  • \connect -mc <URI>:使用经典协议(经典会话)。

  • \connect -ma <URI>:使用自动协议选择。

回想一下,会话在广义上与连接同义。但是,会话不仅仅是一个连接,因为用于建立连接的所有设置(包括会话对象)以及用于与服务器通信的协议都包括在内。因此,我们有时会遇到术语协议来描述会话。在后面的部分中,您将看到更多使用会话的示例。

支持的模式

shell 支持三种模式(也称为语言支持或简称为活动语言 ): SQL、JavaScript 和 Python。回想一下,我们可以通过使用 shell 命令来启动这些模式中的任何一种。你可以随时切换模式(语言),每次都不会断线。下面列出了三种模式以及如何切换到每种模式。

  • \sql:切换到 SQL 语言。

  • \js:切换到 JavaScript 语言(默认模式)。

  • \py:切换到 Python 语言。

现在您已经了解了会话、会话对象和模式,接下来您可以看看如何连接 MySQL 服务器。

连接

在 shell 中建立连接可能需要一些时间来适应与最初的 MySQL 客户端不同的工作方式,最初的 MySQL 客户端需要在命令行中使用几个选项。您可以使用特殊格式的 URI 字符串,或者通过名称使用单个选项连接到服务器(像旧客户端一样)。也支持 SSL 连接。可以通过启动选项、shell 命令和脚本来建立连接。但是,所有连接都需要使用密码。除非您另外声明,否则如果没有给出密码,shell 将提示您输入密码。

注意

如果您想使用没有密码的连接(不推荐),您必须使用--password选项,或者,如果使用 URI,包括一个额外的冒号来代替密码。

下面的部分没有讨论所有可用的连接方式和选项,而是给出了每种连接方式的一个例子。

使用 URI

URI 是使用格式<dbuser>[:<dbpassword>]@host[:<por>t][/<schema>/]的特殊字符串,其中<>表示各种参数的字符串值。请注意,口令、端口和模式是可选的,但用户和主机是必需的。在这种情况下,模式是您希望在连接时使用的默认模式(数据库)。X 协议的默认端口是 33060。要在启动 shell 时使用命令行上的 URI 连接到服务器,请使用--uri选项指定它,如下所示:

$ mysqlsh --uri root:secret@localhost:33060

shell 假定所有连接都需要密码,如果没有提供密码,它将提示输入密码。清单 4-2 显示了没有密码的相同连接。注意 shell 是如何提示输入密码的。

$ mysqlsh --uri root@localhost:33060/world_x
Creating a session to 'root@localhost:33060/world_x'
Enter password:
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 13 (X protocol)
Server version: 8.0.11 MySQL Community Server (GPL)
Default schema `world_x` accessible through db.
MySQL Shell 8.0.11

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

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

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

 MySQL  localhost:33060+  world_x  JS >

Listing 4-2Connecting with a URI

注意,我们还在 URI 中用/schema选项指定了默认模式(world_x)。world_x数据库是一个示例数据库,您可以从 https://dev.mysql.com/doc/index-other.html 下载。您将在后面的 MySQL Shell 教程中安装这个数据库。

使用单个选项

您还可以通过使用单独的选项在 shell 命令行上指定连接。可用的连接选项如表 4-1 所示。为了向后兼容(并使向 MySQL Shell 的过渡更容易),Shell 还支持用--user代替--dbuser,用--password代替--dbpassword,用--database代替--schema。清单 4-3 展示了如何使用单独的选项连接到 MySQL 服务器。注意,我用--py选项将模式(语言)改为 Python。

$ mysqlsh --dbuser root --host localhost --port 33060 --schema world_x --py -mx
Creating an X protocol session to 'root@localhost:33060/world_x'
Enter password:
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 14 (X protocol)
Server version: 8.0.11 MySQL Community Server (GPL)
Default schema `world_x` accessible through db.
MySQL Shell 8.0.11

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

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

owners.

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

 MySQL  localhost:33060+  world_x  Py >

Listing 4-3Connecting by Using Individual Options

在脚本中使用连接

如果您计划使用 shell 来创建脚本或者仅仅作为一个原型工具,那么您还会希望在脚本中使用会话。在这种情况下,我们将创建一个变量来包含提取后的会话。以这种方式创建的会话被称为全局会话,因为在它被创建之后,它可用于任何模式。然而,根据我们使用的会话对象(回想一下,这是经典或 X 协议),我们将使用mysqlx对象的不同方法来创建 X 或经典会话。我们对 X 协议会话对象使用getSession()方法,对经典会话对象使用getClassicSession()方法。

下面演示了在 JavaScript 中获取 X 协议会话对象。请注意,我在 URI 中将密码指定为方法参数:

 MySQL  JS > var js_session = mysqlx.getSession('root@localhost:33060', 'secret')
 MySQL  JS > print(js_session)
<Session:root@localhost:33060>
The following demonstrates getting a Classic session object in JavaScript.
 MySQL  JS > var js_session = mysql.getClassicSession('root@localhost:3306', 'secret')
 MySQL  JS > print(js_session)
<ClassicSession:root@localhost:3306>

使用 SSL 连接

您还可以创建 SSL 连接,以便安全地连接到您的服务器。要使用 SSL,您必须将服务器配置为使用 SSL。要在运行 MySQL 的同一台机器上使用 SSL,可以使用--ssl-mode=REQUIRED选项。您也可以指定 SSL 选项,如表 4-1 所示。您可以使用命令行选项在命令行上指定它们,或者将其作为\connect shell 命令的扩展。下面显示了如何通过 SSL 和命令行选项连接到服务器:

$ mysqlsh -uroot -h127.0.0.1 --port=33060 --ssl-mode=REQUIRED

小费

有关加密连接( https://dev.mysql.com/doc/refman/8.0/en/encrypted-connections.html )的更多详细信息,请参见《MySQL Shell 参考手册》中的“使用加密连接”一节。

现在您已经知道了如何连接到我们的服务器,让我们回顾一下如何设置和安装 shell,更重要的是,如何确保 X 插件设置正确。

安装 MySQL Shell

在 MySQL 的当前版本中,MySQL Shell 是作为独立于服务器的产品发布的。在除 Windows 之外的所有平台上,您可以单独安装它。本节演示了在 Windows 上安装 MySQL Shell 所需的步骤。要在其他平台上安装,请访问 http://dev.mysql.com/downloads/shell/ 并为您的平台选择最新版本和软件包,然后安装 shell。

注意

shell 中的服务器配置脚本需要 Python 2.7。如果要在另一个平台上安装 shell,必须确保要在 InnoDB 集群中使用的所有服务器上都安装了 Python 2.7。

使用 MySQL 安装程序安装 MySQL Shell 遵循与安装 MySQL Server 相同的模式。但是,由于安装程序已经在系统中,我们只需再次启动它,并添加我们想要的 MySQL 产品(如 MySQL Shell)。当您启动安装程序时,会出现一个欢迎面板,其中包含已安装产品的列表。图 4-2 显示了服务器安装后 MySQL 安装程序的欢迎面板。

img/460910_1_En_4_Fig2_HTML.jpg

图 4-2

安装程序欢迎面板-安装后(MySQL 安装程序)

请注意,我们可以选择添加(添加… )新产品,修改(修改… )已安装产品的安装或配置,从目录(安装程序)中升级(升级… )具有较新版本的已安装产品,或者移除已安装产品(移除… )。请注意,还有一个名为 Catalog… 的按钮,它允许您更新安装程序中的产品目录。这允许您用新版本更新产品。我们将在后面的步骤中看到如何做到这一点。

对于本教程,我们希望安装 MySQL Shell,因此单击 Add 继续。然后你会看到一个产品选择面板,如图 4-3 所示。导航左边的树找到 MySQL Shell,选择它,然后单击绿色箭头将其添加到右边的列表中。添加后,单击“下一步”按钮继续。

img/460910_1_En_4_Fig3_HTML.jpg

图 4-3

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

下一个屏幕是一个安装摘要,允许您确认列出的安装产品是否正确。此面板还指示状态,以便您可以观察安装进度。图 4-4 为安装面板。当您准备好开始安装所选产品时,请单击执行。

img/460910_1_En_4_Fig4_HTML.jpg

图 4-4

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

安装开始后,你会看到每个产品的进度,如图 4-5 所示。

img/460910_1_En_4_Fig5_HTML.jpg

图 4-5

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

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

img/460910_1_En_4_Fig6_HTML.jpg

图 4-6

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

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

img/460910_1_En_4_Fig7_HTML.jpg

图 4-7

安装完成(MySQL 安装程序)

MySQL 安装程序提供的一个非常好的附加功能是能够更新要安装的产品目录。如果有更新的包可用,MySQL 安装程序会提供更新它们的选项。回想一下欢迎面板,如果我们愿意,我们可以手动这样做。但是,在安装结束时,安装程序会提示您进行更新,如图 4-8 所示。如果要连接到互联网并更新目录,请单击执行。如果没有,您可以勾选此时不更新复选框并继续。让我们看看目录是如何更新的。

img/460910_1_En_4_Fig9_HTML.jpg

图 4-9

更新目录-完成(MySQL 安装程序)

img/460910_1_En_4_Fig8_HTML.jpg

图 4-8

更新目录-初始化(MySQL 安装程序)

安装程序将连接到互联网,下载目录更改,然后将它们集成到安装程序中,以便进行下一次安装操作。请注意,这与升级现有安装不同;它只是更新安装程序目录。更新完成后,单击“下一步”完成升级。

img/460910_1_En_4_Fig10_HTML.jpg

图 4-10

安装程序欢迎面板-安装后(MySQL 安装程序)

当所有操作完成后,安装程序将返回到欢迎面板,显示所有已安装产品的列表,如图 4-10 所示。完成后,您可以关闭安装程序,或者添加、修改、升级或移除其他产品。

现在已经安装了 MySQL Shell,我们需要配置 X 插件。

启用 X 插件

如果您在系统上安装了 MySQL,那么您已经安装了 X 插件。如果您有 8.0.11 或更高版本,X 插件已经安装并启用。但是,默认情况下,旧的安装包不会设置或启用 X 插件。因此,您可能需要启用插件来使用 shell 连接到您的服务器。尽管您仍然可以使用 shell 通过经典会话对象进行连接,但是在启用 X 插件之前,您将无法使用 X 协议会话对象。如果需要启用 X 插件,至少可以从其他两种方法中选择:可以使用新的 MySQL Shell,也可以使用旧的客户端。下面演示了每个选项。

小费

如果在新安装的 MySQL 上连接到 MySQL 服务器有问题,请确保启用 X 插件,如本节所示。

使用 MySQL Shell 启用 X 插件

要通过 MySQL Shell 启用 X 插件,通过使用用户和主机的单独选项以及指定--mysql--dba enableXProtocol选项来启动经典会话,如下所示。我们使用经典的会话对象,因为我们还没有启用 X 协议。

$ mysqlsh -uroot -hlocalhost --mysql --dba enableXProtocol
Enter password: ****
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 13
Server version: 8.0.11 MySQL Community Server - GPL
No default schema selected; type \use <schema> to set one.
enableXProtocol: Installing plugin mysqlx...
enableXProtocol: done

使用 MySQL 客户端启用 X 插件

要通过旧的 MySQL 客户端启用 X 插件,您必须连接到服务器并手动安装插件。没有新的魔法命令选项来打开它。这涉及到使用INSTALL PLUGIN SQL 命令,如清单 4-4 所示。

$ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 343
Server version: 8.0.11 MySQL Community Server (GPL)

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

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

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

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

mysql> SHOW PLUGINS \G
*************************** 1\. row ***************************
   Name: keyring_file
 Status: ACTIVE
   Type: KEYRING
Library: keyring_file.so
License: GPL
...
*************************** 43\. row ***************************
   Name: mysqlx
 Status: ACTIVE
   Type: DAEMON
Library: mysqlx.so
License: GPL
43 rows in set (0.00 sec)

Listing 4-4Enabling the X Plugin Using the MySQL Client

注意,我使用了SHOW PLUGINS SQL 命令来列出该命令前后安装的插件。为了清楚起见,我省略了一些冗长的输出。

有趣的是,您也可以使用如下的UNINSTALL PLUGIN SQL 命令卸载插件。如果您需要通过使用 X 协议来诊断连接,或者想要通过仅使用经典会话对象来测试 MySQL Shell 的脚本,这可能会很有帮助。

mysql> UNINSTALL PLUGIN mysqlx;
Query OK, 0 rows affected (0.80 sec)

现在,让我们通过演示 MySQL Shell 的基本特性来看看它的运行情况。

辅导的

以下部分演示了如何使用 MySQL Shell。该示例使用了world_x数据库,旨在提供一个概述,而不是深入探讨。在第 5 章中,你会看到 MySQL Shell 与 InnoDB 集群一起使用。如果您对 MySQL 文档存储或 JSON 数据一无所知,不要绝望;本教程旨在演示如何使用 MySQL Shell,因为 Shell 旨在用于 JSON 文档,所以我们将这样做。然而,在第 5 章中,您将看到 AdminAPI 用于配置 InnoDB 集群。

本教程的目标是在world_x数据库中插入新数据,然后执行搜索以检索满足包含新数据的标准的行。我将使用一个关系表来说明这些概念,因为这对我们这些熟悉“普通”数据库操作的人来说更容易。

在开始我们的旅程之前,让我们花点时间安装我们将需要的示例数据库,Oracle 的world_x示例 MySQL 数据库。

安装示例数据库

Oracle 提供了几个示例数据库,供您在测试和开发应用时使用。样本数据库可以从 http://dev.mysql.com/doc/index-other.html 下载。我们想要使用的示例数据库被命名为world_x,以表明它包含 JSON 文档,并打算用 X DevAPI、shell 等进行测试。继续前进,导航到该页面并下载数据库。示例数据库包含几个关系表(countrycitycountrylanguage)以及一个集合(countryinfo)。

下载完文件后,解压缩并记下文件的位置。当您导入它时,您将需要它。接下来,启动 MySQL Shell 并连接到您的服务器。使用\sql shell 命令切换到 SQL 模式,然后使用\source shell 命令读取world_x.sql文件并处理其所有语句。

我们还将使用SHOW DATABASES命令列出服务器上的所有数据库(以确保添加了新的数据库)。我们使用USE命令选择默认数据库,使用SHOW TABLES命令查看world_x数据库中的表。最后,我们还将通过使用EXPLAIN命令来查看city表的模式(布局)。如果您自己运行这些命令,您可能会用SHOW DATABASES命令得到一个不同的数据库列表。这没关系,因为您的数据库可能比教程中使用的机器少(或多)。

清单 4-5 显示了您应该看到的命令和响应的摘录。我在输出中突出显示了命令和一行,以表明这个 world 数据库确实允许在一个表中存储 JSON 文档。

 MySQL  JS > \connect root@localhost:33060
Creating a session to 'root@localhost:33060'
Enter password:
Your MySQL connection id is 9 (X protocol)
Server version: 8.0.11 MySQL Community Server (GPL)
No default schema selected; type \use <schema> to set one.
 MySQL  localhost:33060+ ssl  JS > \sql
Switching to SQL mode... Commands end with ;
 MySQL  localhost:33060+ ssl  SQL > \source /Users/cbell/Downloads/world_x-db/world_x.sql
...
Query OK, 0 rows affected (0.00 sec)

MySQL  localhost:33060+ ssl  SQL > SHOW DATABASES;

+--------------------+
| Database           |
+--------------------+
| animals            |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
| world_x            |
+--------------------+
7 rows in set (0.00 sec)
 MySQL  localhost:33060+ ssl  SQL > USE world_x;
Query OK, 0 rows affected (0.00 sec)
 MySQL  localhost:33060+ ssl  SQL > SHOW TABLES;
+-------------------+
| Tables_in_world_x |
+-------------------+
| city              |
| country           |
| countryinfo       |
| countrylanguage   |
+-------------------+
4 rows in set (0.00 sec)

MySQL  localhost:33060+ ssl  SQL > EXPLAIN city;

+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| ID          | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name        | char(35) | NO   |     |         |                |
| CountryCode | char(3)  | NO   |     |         |                |
| District    | char(20) | NO   |     |         |                |
| Info        | json     | YES  |     | NULL    |                |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

Listing 4-5Installing the world_x Database (SQL Mode)

注意,\source shell 命令是一种加载文件并批量执行命令的方式。这是一种重放常用命令序列的流行方法,它也适用于 JavaScript 和 Python 命令。

小费

如果文件的路径中有空格,应该用双引号将路径括起来。

您还可以使用命令行上的--recreate-schema选项来安装示例数据库,如下所示。请注意,如果数据库已经存在,这将删除并重新创建数据库。这是批处理运行 SQL 命令的另一个例子。

$ mysqlsh -uroot -hlocalhost --sql --recreate-schema --schema=world_x < ~/Downloads/world_x-db/world_x.sql
Enter password:
Recreating schema world_x...

当然,您可以使用 similar source 命令在旧客户机上安装 sample 数据库,但是这有什么意思呢?

现在,让我们看看如何插入数据。

插入数据

我们希望通过在每一行中添加一个 JSON 文档来将两行插入到city表中,然后只从表中读取那些有额外数据的行。更具体地说,我们将向表中添加一个名胜古迹列表,以便我们稍后可以询问哪些城市有名胜古迹。你可以把它当作一种方式,来添加你自己对那些你觉得有趣并会推荐给他人的城市中你去过的地方的评论。

因为本练习是一个示例,所以您还将看到如何删除我们添加的数据,以便我们将数据库恢复到其原始状态。如果您计划按照这些示例进行操作,以便完成一个示例不会影响下一个示例的尝试,那么这样做也是有帮助的。

接下来,我们插入一些数据。我们将在表中插入两行:我最近去过的每个城市一行(北卡罗来纳州的夏洛特和佛罗里达州的代托纳)。在这一步中,我们将使用INSERT SQL 命令来插入数据。回想一下前面的内容,我们需要仔细格式化 JSON 文档,这样我们就不会遇到错误。具体来说,我们希望添加包括姓名、国家代码和地区的结构化数据,但是我们还希望添加一个 JSON 文档,其中包含人口和名胜古迹的列表(数组)。下面显示了我们将用来插入行的每个命令:

INSERT INTO world_x.city (Name, CountryCode, District, Info) VALUES ('Charlotte', 'USA', 'North Carolina', '{"Population": 792862, "Places_of_interest": [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]}');

INSERT INTO world_x.city (Name, CountryCode, District, Info) VALUES ('Daytona', 'USA', 'Florida', '{"Population": 590280, "Places_of_interest": [{"name": "Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name": "Daytona Motor Speedway"}]}');

警告

不要在 JSON 文档的键名中使用空格。SQL 函数无法正确识别包含空格的键。

尽管这看起来有点混乱(确实如此),但是如果您仔细阅读这些语句,您会看到 JSON 文档被编码为一个字符串。例如,第一次插入的 JSON 文档的格式良好的版本如下所示。很明显,这更容易阅读。您可以使用如下格式输入语句,但是显示的结果没有额外的格式。

注意,我们保留了表中其他行的 population 键(选择一些并查看),我们还添加了一个名为Places_of_interest的数组来列出我们可能想去的地方。

{
  "Population": 792862,
  "Places_of_interest": [
    {
      "name": "NASCAR Hall of Fame"
    },
    {
      "name": "Charlotte Motor Speedway"
    }
  ]
}

注意,为了简洁起见,我从示例中截断了表格格式行(虚线)。

选择数据

现在,让我们看看如果使用一个SELECT SQL 语句,数据会是什么样子。在这种情况下,我们将只按城市名选择两行,因为它们在表中是唯一的。以下是调查结果的摘录:

MySQL  localhost:33060+ ssl  SQL > SELECT * FROM city WHERE Name in ('Charlotte', 'Daytona') \G
*************************** 1\. row ***************************
         ID: 3818
       Name: Charlotte
CountryCode: USA
   District: North Carolina
       Info: {"Population": 540828}
*************************** 2\. row ***************************
         ID: 4080
       Name: Charlotte
CountryCode: USA
   District: North Carolina
       Info: {"Population": 792862, "Places_of_interest": [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]}
*************************** 3\. row ***************************
         ID: 4081
       Name: Daytona
CountryCode: USA
   District: Florida
       Info: {"Population": 590280, "Places_of_interest": [{"name": "Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name": "Daytona Motor Speedway"}]}

很有意思,但是没有回答我们想问的问题:哪些城市有名胜古迹?为此,我们需要使用一些为 JSON 数据类型设计的特殊函数。所有函数都以名称JSON_*开头。让我们依次来看每一个,从在 JSON 文档中搜索具有特定键的行开始。在这种情况下,我们选择有兴趣地点的行的所有数据。

为了确定 JSON 文档是否有特定的键,我们使用了JSON_CONTAINS_PATH()函数。回想一下,路径是文档中键的解析。在这种情况下,我们想知道 JSON 文档是否包含Places_of_interest的路径。因为函数在没有匹配时返回 0,在至少有一个匹配时返回 1,所以我们检查它是否等于 1。你可以省略等式,但是在试验新的特性和命令时最好是学究式的。我们还使用all选项告诉函数返回所有匹配(值),而one只返回第一个匹配。你也可以使用稍微正确一点的IS NOT NULL比较。

MySQL  localhost:33060+ ssl  SQL > SELECT * FROM city WHERE JSON_CONTAINS_PATH(info, 'all', '$.Places_of_interest') = 1 \G
*************************** 1\. row ***************************
         ID: 4080
       Name: Charlotte
CountryCode: USA
   District: North Carolina
       Info: {"Population": 792862, "Places_of_interest": [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]}
*************************** 2\. row ***************************
         ID: 4081
       Name: Daytona
CountryCode: USA
   District: Florida
       Info: {"Population": 590280, "Places_of_interest": [{"name": "Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name": "Daytona Motor Speedway"}]}
2 rows in set (0.00 sec)

现在,假设我们只想查看那些感兴趣的地方,而不是整个 JSON 文档。在这种情况下,我们需要使用JSON_EXTRACT()函数从文档中提取值。具体来说,我们希望在 info 列中搜索数组Places_of_interest中的所有值。尽管这看起来很复杂,但还不算太糟,正如你在这里看到的:

MySQL  localhost:33060+ ssl  SQL > SELECT Name, District, JSON_EXTRACT(info, '$.Places_of_interest') as Sights FROM city WHERE JSON_EXTRACT(info, '$.Places_of_interest') IS NOT NULL \G
*************************** 1\. row ***************************
    Name: Charlotte
District: North Carolina
  Sights: [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]
*************************** 2\. row ***************************
    Name: Daytona
District: Florida
  Sights: [{"name": "Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name": "Daytona Motor Speedway"}]
2 rows in set (0.00 sec)

现在,如果我们只想检索Places_of_interest数组的值呢?在这种情况下,我们可以使用特殊格式的 JSON access 从数组中获取这些值。下面演示了这种技术。请注意以粗体突出显示的部分:

MySQL  localhost:33060+ ssl  SQL > SELECT Name, District, JSON_EXTRACT(info, '$.Places_of_interest[*].name') as Sights FROM city WHERE JSON_EXTRACT(info, '$.Places_of_interest') IS NOT NULL \G
*************************** 1\. row ***************************
    Name: Charlotte
District: North Carolina
  Sights: ["NASCAR Hall of Fame", "Charlotte Motor Speedway"]
*************************** 2\. row ***************************
    Name: Daytona
District: Florida
  Sights: ["Daytona Beach", "Motorsports Hall of Fame of America", "Daytona Motor Speedway"]
2 rows in set (0.00 sec)

好了,现在看起来容易多了,不是吗?这也是一个混乱的 SQL 命令。如果这一切看起来有点痛苦,你是对的,的确如此。在 SQL 中处理 JSON 数据需要借助 JSON 函数,但是这需要一个额外的步骤,并且可能会使用令人困惑的语法。关于每个JSON_*函数的完整解释,请参见在线 MySQL 参考手册。

如果您经常使用旧的 MySQL 客户端来查询具有宽行的数据,那么您可能已经使用了\G选项来以垂直格式显示结果,这使得读取数据更加容易。有了 shell,我们可以通过使用--json选项来显示数据。虽然这个选项更容易阅读,但是它有点冗长。清单 4-6 展示了使用--json选项的 shell 查询。

$ mysqlsh root:root@localhost --json --sql
mysqlsh: [Warning] Using a password on the command line interface can be insecure.
{
    "info": "Creating a session to 'root@localhost'"
}
{
    "info": "Fetching schema names for autocompletion... Press ^C to stop."
}
{
    "info": "Your MySQL connection id is 17 (X protocol) Server version: 8.0.11 MySQL Community Server - GPL No default schema selected; type \\use <schema> to set one."
}
{
    "info": "MySQL Shell 8.0.11 Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners

."
}

{
    "info": "Type '\\help' or '\\?' for help; '\\quit' to exit."
}

MySQL  localhost:33060+ ssl  SQL > SELECT * FROM world_x.city WHERE Name in ('Charlotte', 'Daytona');
{
    "executionTime": "0.0060 sec",
    "warningCount": 0,
    "warnings": [],
    "rows": [
        {
            "ID": 3818,
            "Name": "Charlotte",
            "CountryCode": "USA",
            "District": "North Carolina",
            "Info": "{\"Population\": 540828}"
        },
        {
            "ID": 4080,
            "Name": "Charlotte",
            "CountryCode": "USA",
            "District": "North Carolina",
            "Info": "{\"Population\": 792862, \"Places_of_interest\": [{\"name\": \"NASCAR Hall of Fame\"}, {\"name\": \"Charlotte Motor Speedway\"}]}"
        },
        {
            "ID": 4081,
            "Name": "Daytona",
            "CountryCode": "USA",
            "District": "Florida",
            "Info": "{\"Population\": 590280, \"Places_of_interest\": [{\"name\": \"Daytona Beach\"}, {\"name\": \"Motorsports Hall of Fame of America\"}, {\"name\": \"Daytona Motor Speedway\"}]}"
        }
    ],
    "hasData": true,
    "affectedRowCount": 0,
    "autoIncrementValue": 0
}

 MySQL  localhost:33060+ ssl  SQL > \q
Bye!

Listing 4-6Using the JSON Option (MySQL Shell)

请注意,输出更加详细,甚至来自 shell 的消息也是 JSON 格式的,但是它确实有助于更好地读取 JSON 数据。

最后,我们可以用DELETE SQL 命令删除这些行:

MySQL  localhost:33060+ ssl  SQL > DELETE FROM city WHERE Name in ('Charlotte', 'Daytona');
Query OK, 3 rows affected (0.00 sec)

摘要

MySQL Shell 对于 MySQL 客户端来说是一个巨大的技术飞跃。它不仅设计为以更智能的方式使用 MySQL 中的 SQL,还支持 JavaScript 和 Python 的原型。您可以使用任何您想要的语言,并在它们之间轻松切换,而不必重新启动应用或断开连接。多酷啊。

如果这还不够的话,X DevAPI 和内置对象的额外好处是允许使用 shell 作为文档存储的前端,因此您不必编写单独的应用来管理您的数据。您只需选择适合您需求的模式(语言),切换到该语言,然后执行任务。正如您在第 1 章中所了解到的,shell 还构成了最新特性的前端,包括 InnoDB Cluster,为您提供了满足所有 MySQL 管理、编程和高可用性需求的一站式客户端。

在本章中,您学习了如何使用 MySQL Shell。您回顾了启动选项、shell 命令、连接、会话,甚至学习了如何使用 interactive SQL。虽然这一章没有提供 MySQL Shell 所有特性的详尽介绍,但它提供了一个广泛的教程,说明如何使用它来完成最常见的任务。

在下一章中,您将探索通过使用 MySQL Shell 和 AdminAPI 建立一个实验性 InnoDB 集群的概述。

五、沙箱中的高可用性

现在,您已经了解了什么是 InnoDB 集群以及构成该特性的组件,包括组复制和 MySQL Shell,您已经有足够的知识来设置一个小型的实验性 InnoDB 集群。您将通过 MySQL Shell 使用新的 AdminAPI 来实现这一点。

接下来是部署三台服务器的演示,并在新的 MySQL Shell 中使用 X AdminAPI 通过组复制将它们配置为一个集群。虽然这听起来很费力,但实际上并不是。其实真的很简单。

让我们从 AdminAPI 的概述开始。

注意

您还必须在我们的目标机器上至少安装 MySQL Server 和 MySQL Shell。如果您还没有安装服务器和 shell,请分别参考第 2 和第 4 章。

AdminAPI 入门

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

什么是沙箱?

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

回想一下第 2 章中的,AdminAPI 有两个主要的类:dbacluster。让我们来看看每一个的细节。

注意

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

dba 类

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

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

表 5-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 中可用于这些方法和其他方法的选项取决于方法本身,因为每个方法都允许一个或多个选项。表 5-2 显示了表 5-1 中方法可用的选项。

表 5-2

沙箱方法的选项(dba 类)

|

功能

|

[计]选项

|

描述

| | --- | --- | --- | | delete_sandbox_instance | sandboxDir | 将部署新实例的路径 | | deploy_sandbox_instance | portx | 新实例将侦听 X 协议连接的端口 | | sandboxDir | 将部署新实例的路径 | | password | 新实例上 MySQL root 用户的密码 | | allowRootFrom | 创建远程 root 帐户,仅限于给定的地址模式(例如,%) | | 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'})

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

表 5-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 ) | 当所有成员脱机时,使群集重新联机 |

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

  • 通用:一些方法的通用选项。

    • 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:为user的别名。

    • password:连接时使用的密码。

    • dbPassword:同password

    • host:要在 TCP 连接上使用的主机名或 IP 地址。

    • port:TCP 连接中使用的端口。

    • socket:通过 UNIX 套接字连接时使用的套接字文件名。

    • schema:连接完成后要选择的模式。

该类还有一个名为verbose的属性,它允许开发者在提供服务器(在沙箱中部署服务器)的过程中设置调试和相关语句输出的详细级别。不建议将此属性设置为生产使用。verbose设置如下:

  • 0:禁用mysqlprovision详细度

  • 1:启用mysqlprovision详细度

  • >1:大于或等于 2 的值启用mysqlprovision调试详细度。

集群类

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

因为这个类用于直接处理实例和集群,所以大多数方法都设计为处理通过dba类检索的集群的特定实例。表 5-4 列出了cluster类中的方法。

表 5-4

Cluster 类的方法

|

返回

|

功能

|

描述

| | --- | --- | --- | | None | add_instance(InstanceDef instance, dict options) | 向群集添加实例 | | dict | check_instance_state(InstanceDef instance, str password) | 验证与集群相关的实例 GTID 状态 | | str | describe() | 描述群集的结构 | | None | disconnect() | 断开群集对象使用的所有内部会话 | | None | dissolve(Dictionary options) | 溶解群集 | | None | force_quorum_using_partition_of(InstanceDef instance, str password) | 从仲裁丢失中恢复群集 | | str | get_name() | 检索群集的名称 | | None | rejoin_instance(InstanceDef instance, dict options) | 将实例重新加入集群 | | None | remove_instance(InstanceDef instance, dict options) | 从集群中删除实例 | | None | rescan() | 重新扫描集群 | | str | status() | 描述群集的状态 |

请注意,我们有添加、移除和重新加入实例的方法。在管理集群中的实例时,我们会经常用到它们。还有几种方法可以获取信息和状态,并强制更新元数据,例如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 中的类和方法有了一个简要的概述,让我们来看看它的实际应用吧!

示范

本节简要演示了如何通过 MySQL Shell 和 AdminAPI 使用沙箱部署方法创建 InnoDB 集群。我们将创建一个 InnoDB 集群,在本地机器上运行四个实例。我们不仅将看到如何设置要使用的集群,还将看到集群如何处理故障转移,最后,我们将看到如何设置 DevOps 脚本来快速设置和关闭实验集群。

设置和配置

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

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

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

如果您计划以后重用该集群,您可能希望通过使用sandboxDir选项来指定一个特定的文件夹。例如,您可以将字典指定为{'sandboxDir':'c://idc_sandbox'}和 AdminAPI。但是,该文件夹必须存在,否则当您调用deploy_sandbox_instance()方法时会得到一个错误。清单 5-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

04/23/2018  04:18 PM    <DIR>          .
04/23/2018  04:18 PM    <DIR>          ..
04/23/2018  04: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

04/23/2018  04:19 PM    <DIR>          .
04/23/2018  04:19 PM    <DIR>          ..
04/23/2018  04:19 PM                 6 3311.pid
04/23/2018  04:18 PM               726 my.cnf
04/23/2018  04:18 PM    <DIR>          mysql-files
04/23/2018  04:18 PM    <DIR>          sandboxdata
04/23/2018  04:18 PM               147 start.bat
04/23/2018  04:18 PM               207 stop.bat
               4 File(s)          1,086 bytes

               4 Dir(s)  172,557,893,632 bytes free

Listing 5-1Creating a Directory for the Sandbox

注意

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

下面的演示使用 Python 模式下的 MySQL Shell。所示的命令也可以在 JavaScript 模式下工作,但是一些方法名的拼写可能略有不同(比如使用下划线和首字母大写)。这样做是为了让 AdminAPI 符合特定于语言的命名约定和惯例。 1

创建 InnoDB 集群的沙箱部署需要几个步骤:

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

  2. 创建集群:创建集群类的对象实例。

  3. 向集群添加实例:向集群添加沙箱实例。

  4. 检查集群状态:检查集群健康状况。

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

在沙箱中创建和部署实例

让我们从使用 AdminAPI 启动 shell 并部署四台服务器开始。在这种情况下,我们将使用端口 3311–3314 和dba对象中的deploy_sandbox_instance()方法为每个服务器创建新的实例。所有这些都将在我们的本地主机上运行,在这个例子中是 Windows 相应地调整路径,以便在其他系统上使用。清单 5-2 展示了如何部署四台服务器。使用的命令以粗体突出显示,有助于从消息中识别命令。请注意,我以 Python 模式启动了 shell。

小费

没有必要导入dba类。每当您使用\py命令(或--py命令行选项)切换到 Python 模式,或使用\js命令(或--js命令行选项)切换到 JavaScript 模式时,MySQL Shell 都可以使用它。

C:\idc_sandbox>mysqlsh --py

MySQL Shell 8.0.11

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

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

.

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

 MySQL  Py > dba.deploy_sandbox_instance(3311, {'sandboxDir':'c://idc_sandbox'})
A new MySQL sandbox instance will be created on this host in
c://idc_sandbox\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.

 MySQL  Py > dba.deploy_sandbox_instance(3312, {'sandboxDir':'c://idc_sandbox'})
A new MySQL sandbox instance will be created on this host in
c://idc_sandbox\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.

 MySQL  Py > dba.deploy_sandbox_instance(3313, {'sandboxDir':'c://idc_sandbox'})
A new MySQL sandbox instance will be created on this host in
c://idc_sandbox\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

.

 MySQL  Py > dba.deploy_sandbox_instance(3314, {'sandboxDir':'c://idc_sandbox'})
A new MySQL sandbox instance will be created on this host in
c://idc_sandbox\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.

 MySQL  Py >

Listing 5-2Creating Local Server Instances

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

小费

JavaScript 是区分大小写的,所以要确保对变量、对象和方法使用正确的拼写。名为abc的变量与名为Abc的变量不同。

创建集群

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

我们还将在单主模式下设置集群。将有一个主要角色为(读/写)的实例,所有其他实例都是只读的。为此,我们必须将multiMaster选项设置为False。注意清单 5-3 中是如何做到的。

MySQL  Py > \connect root@localhost:3311

Creating a session to 'root@localhost:3311'
Enter password: ****
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 12
Server version: 8.0.11 MySQL Community Server - GPL

No default schema selected; type \use <schema> to set one.

 MySQL  localhost:3311 ssl  Py > my_cluster = dba.create_cluster('MyCluster', {'multiMaster':False})

A new InnoDB cluster will be created on instance 'root@localhost:3311'.ster', {'multiMaster':False})

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 DESKTOP-JBL081L

Instance configuration is suitable.
Creating InnoDB cluster 'MyCluster' 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.

 MySQL  localhost:3311 ssl  Py >

Listing 5-3Creating a Cluster in InnoDB Cluster

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

注意

如果退出 shell,可以用get_cluster()方法检索正在运行的集群。

将实例添加到集群

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

 MySQL  localhost:3311 ssl  Py > 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.

Please provide the password for 'root@localhost:3312': ****
Adding instance to the cluster ...

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 DESKTOP-JBL081L

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

 MySQL  localhost:3311 ssl  Py > 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.

Please provide the password for 'root@localhost:3313': ****
Adding instance to the cluster ...

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 DESKTOP-JBL081L

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

 MySQL  localhost:3311 ssl  Py > 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.

Please provide the password for 'root@localhost:3314': ****
Adding instance to the cluster ...

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 DESKTOP-JBL081L

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

 MySQL  localhost:3311 ssl  Py >

Listing 5-4Adding Instances to the Cluster

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

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

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

检查集群的状态

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

C:\idc_sandbox>mysqlsh --py
MySQL Shell 8.0.11

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

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

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

 MySQL  Py > \connect root@localhost:3311
Creating a session to 'root@localhost:3311'
Enter password: ****
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 55
Server version: 8.0.11 MySQL Community Server - GPL

No default schema selected; type \use <schema> to set one.

 MySQL  localhost:3311 ssl  Py > my_cluster = dba.get_cluster('MyCluster')
 MySQL  localhost:3311 ssl  Py > my_cluster.status()
{
    "clusterName": "MyCluster",
    "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"
            },
            "localhost:3312": {
                "address": "localhost:3312",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"

            }
        }
    },
    "groupInformationSourceMember": "mysql://root@localhost:3311"
}

 MySQL  localhost:3311 ssl  Py >

Listing 5-5Getting the Status of the Cluster

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

故障切换

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

MySQL  localhost:3311 ssl  Py > dba.kill_sandbox_instance(3311, {'sandboxDir':'c://idc_sandbox'})

The MySQL sandbox instance on this host in
c://idc_sandbox\3311 will be killed

Killing MySQL instance...

Instance localhost:3311 successfully killed.

 MySQL  localhost:3311 ssl  Py > my_cluster.status()
Traceback (most recent call last):
  File "<string>", line 1, in <module>
SystemError: RuntimeError: Cluster.status: Unable to detect target instance state. Please check account privileges.

MySQL  localhost:3311 ssl  Py > \connect root@localhost:3312

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

MySQL  localhost:3312 ssl  Py > my_cluster = dba.get_cluster('MyCluster')

 MySQL  localhost:3312 ssl  Py > my_cluster.status()
{
    "clusterName": "MyCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "localhost:3312",
        "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": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "(MISSING)"
            },
            "localhost:3312": {

                "address": "localhost:3312",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    },
    "groupInformationSourceMember": "mysql://root@localhost:3312"
}

 MySQL  localhost:3312 ssl  Py >

Listing 5-6Failover Demonstration

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

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

MySQL  localhost:3312 ssl  Py > my_cluster.remove_instance('root@localhost:3311', {'force':True})
The instance will be removed from the InnoDB cluster. Depending on the
instance being the Seed or not, the Metadata session might become invalid.
If so, please start a new session to the Metadata Storage R/W instance

.

The instance 'root@localhost:3311' was successfully removed from the cluster.

 MySQL  localhost:3312 ssl  Py > my_cluster.status()
{
    "clusterName": "MyCluster",
    "defaultReplicaSet": {
        "name": "default",
        "primary": "localhost:3312",
        "ssl": "REQUIRED",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "localhost:3312": {
                "address": "localhost:3312",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3313": {
                "address": "localhost:3313",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "localhost:3314": {
                "address": "localhost:3314",
                "mode": "R/O",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    },
    "groupInformationSourceMember": "mysql://root@localhost:3312"
}

 MySQL  localhost:3312 ssl  Py >

Listing 5-7Removing the Downed Instance from the Cluster

DevOps 脚本

现在,让我们创建 DevOps 脚本,用于设置和关闭 InnoDB 集群。幸运的是,我们在这里不需要发明太多,因为我们将使用在演示中使用的相同命令。唯一的区别是我们将添加print语句以获得更好的反馈,并用来自shel l 类的方法替换 shell 命令,该类是 MySQL API 的一部分。

第一个脚本在沙箱中设置了一个 InnoDB 集群。我们遵循的步骤与之前使用的步骤相同。清单 5-8 展示了用 Python 编写的完整脚本。请随意研究该脚本,以确保您看到 Python 命令如何与前面的演示相匹配。如果您喜欢这个脚本,您可以创建一个名为setup_idc_sandbox.py的文件并保存在您的系统上。

# Introducing InnoDB Cluster
#
# This Python script is designed to set up an InnoDB Cluster in a sandbox.
#
# Note: Change the cluster directory to match your preferred directory setup.
#
# The steps include:
# 1) create the sandbox directory
# 2) deploy instances
# 3) create the cluster
# 4) add instances to the cluster
# 5) show the cluster status
#
# Dr. Charles Bell, 2018
#
import os
import time

# Method to deploy sandbox instance
def deploy_instance(port):
    try:
        dba.deploy_sandbox_instance(port, {'sandboxDir':'c://idc_sandbox', 'password':'root'})
    except:
        print("ERROR: cannot setup the instance in the sandbox.")
    time.sleep(1)

# Add instance to cluster
def add_instance(cluster, port):
    try:
        cluster.add_instance('root:root@localhost:{0}'.format(port))
    except:
        print("ERROR: cannot add instance to cluster.")
    time.sleep(1)

print("##### STEP 1 of 5 : CREATE SANDBOX DIRECTORY #####")
os.mkdir('c://idc_sandbox')

print("##### STEP 2 of 5 : DEPLOY INSTANCES #####")
deploy_instance(3311)
deploy_instance(3312)
deploy_instance(3313)
deploy_instance(3314)

print("##### STEP 3 of 5 : CREATE CLUSTER #####")

shell.connect('root:root@localhost:3311')
my_cluster = dba.create_cluster('MyCluster', {'multiMaster':False})
time.sleep(1)

print("##### STEP 4 of 5 : ADD INSTANCES TO CLUSTER #####")
add_instance(my_cluster, 3312)
add_instance(my_cluster, 3313)
add_instance(my_cluster, 3314)

print("##### STEP 5 of 5 : SHOW CLUSTER STATUS #####")
shell.connect('root:root@localhost:3311')
time.sleep(1)
my_cluster = dba.get_cluster('MyCluster')
time.sleep(1)
status = my_cluster.status()
print(status)

Listing 5-8DevOps Script to Set Up the InnoDB Cluster (Sandbox)

为了执行脚本,我们对 shell 使用了-f选项,提供了脚本的名称。这告诉 shell 加载并执行脚本:

mysqlsh -f setup_idc_sandbox.py

清单 5-9 显示了运行脚本的输出摘录。为了简洁起见,省略了重复的部分。

##### STEP 1 of 5 : CREATE SANDBOX DIRECTORY #####
##### STEP 2 of 5 : DEPLOY INSTANCES #####
Deploying new MySQL instance...

Instance localhost:3311 successfully deployed and started.
Use shell.connect('root@localhost:3311'); to connect to the instance.
...
##### STEP 3 of 5 : CREATE CLUSTER #####
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 DESKTOP-JBL081L

Instance configuration is suitable.
Creating InnoDB cluster 'MyCluster' 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.

##### STEP 4 of 5 : ADD INSTANCES TO CLUSTER #####
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 ...

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 DESKTOP-JBL081L

Instance configuration is suitable.
The instance 'root@localhost:3312' was successfully added to the cluster.
...
##### STEP 5 of 5 : SHOW CLUSTER STATUS #####
{"clusterName": "MyCluster", "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"}, "localhost:3312": {"address": "localhost:3312", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}, "localhost:3313": {"address": "localhost:3313", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}, "localhost:3314": {"address": "localhost:3314", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}}}, "groupInformationSourceMember": "mysql://root@localhost:3311"}

Listing 5-9Setup Script Output

现在,让我们创建一个脚本来关闭集群。在这种情况下,我们将编写一个脚本来关闭所有实例并删除沙箱目录。为此,我们首先尝试从集群中删除实例;然后我们删除实例,最后删除目录。清单 5-10 显示了完整的关机脚本。如果您喜欢这个脚本,您可以创建一个名为shutdown_idc_sandbox.py的文件并保存在您的系统上。

# Introducing InnoDB Cluster
#
# This Python script is designed to perform an orderly shutdown of an InnoDB Cluster.
#
# Note: Change the cluster directory to match your preferred directory setup.
#
# The steps include:
# 1) connect to one of the instances
# 2) retrieve the cluster
# 3) remove the instances from the cluster
# 4) kill all instances
# 5) delete the sandbox directory
#
# Dr. Charles Bell, 2018
#
import shutil
import time

# Method to remove instance
def remove_instance(cluster, port):
    try:
        cluster.remove_instance('root@localhost:{0}'.format(port), {'password':'root', 'force':True})
    except:
        pass
    time.sleep(1)

# Method to kill the instance
def kill_instance(port):
    try:
        dba.kill_sandbox_instance(port, {'sandboxDir':'c://idc_sandbox'})
    except:
        pass
    time.sleep(1)

my_cluster = None
try:
    print("##### STEP 1 of 5 : CONNECT TO ONE INSTANCE (3314) #####")
    shell.connect('root:root@localhost:3314')
    print("##### STEP 2 of 5 : GET THE CLUSTER #####")
    my_cluster = dba.get_cluster('MyCluster')
    time.sleep(1)
except:
    print("ERROR: cannot connect to or remove instances from cluster.")
if my_cluster:
    print("##### STEP 3 of 5 : REMOVE INSTANCES FROM THE CLUSTER #####")
    remove_instance(my_cluster, 3311)
    remove_instance(my_cluster, 3312)
    remove_instance(my_cluster, 3313)
    remove_instance(my_cluster, 3314)

print("##### STEP 4 of 5 : KILL THE INSTANCES #####")
kill_instance(3311)
kill_instance(3312)
kill_instance(3313)

kill_instance(3314)

print("##### STEP 5 of 5 : REMOVE THE SANDBOX DIRECTORY #####")
try:
    shutil.rmtree('c://idc_sandbox')
except:
    print("Cannot remove directory!")

Listing 5-10DevOps Script to Shut Down InnoDB Cluster (Sandbox)

我们使用以下命令以与安装脚本相同的方式运行该脚本:

mysqlsh -f shutdown_idc_sandbox.py

清单 5-11 显示了运行脚本的输出摘录。为了简洁起见,省略了重复的部分。

##### STEP 1 of 5 : CONNECT TO ONE INSTANCE (3314) #####
##### STEP 2 of 5 : GET THE CLUSTER #####
##### STEP 3 of 5 : REMOVE INSTANCES FROM THE CLUSTER #####
The instance will be removed from the InnoDB cluster. Depending on the
instance being the Seed or not, the Metadata session might become invalid.
If so, please start a new session to the Metadata Storage R/W instance.

The instance 'root@localhost:3311' was successfully removed from the cluster.

##### STEP 4 of 5 : KILL THE INSTANCES #####
The MySQL sandbox instance on this host in
c://idc_sandbox\3311 will be killed

Killing MySQL instance...

Instance localhost:3311 successfully killed.
...
##### STEP 5 of 5 : REMOVE THE SANDBOX DIRECTORY #####

Listing 5-11Shutdown Script Output

在沙箱中使用 InnoDB 集群的演示到此结束。

摘要

MySQL Shell 是 MySQL 的游戏规则改变者,这听起来像是炒作,但现在应该开始看起来更像事实了。在前一章中我们谈到了 MySQL Shell 的一小部分,在这一章中你会看到更多。在本例中,我们看了一下用于在沙箱中创建 InnoDB 集群的 AdminAPI。

如果您阅读本章或其他介绍如何设置 InnoDB 集群的文章,您可能不会看到或欣赏 MySQL Shell 和 AdminAPI 在用户友好性方面向前迈出的巨大一步。另一方面,如果您曾经使用过 MySQL 复制,尤其是组复制,并且学会了忍受完成所有工作所需的特定命令和操作,您将会看到 MySQL Shell 和 AdminAPI 带来的强大功能。

简而言之,InnoDB Cluster 使得使用组复制成为学习一些 API 类和方法的简单事情。最好的一点是,它为 InnoDB 集群的开发操作和自动化打开了大门——到目前为止,这需要昂贵的定制工具。是的,InnoDB 集群更易于管理和自动化。

但是,您还没有完成对 InnoDB 集群的学习。在下一章中,您将看到 InnoDB 集群的最后一部分:MySQL 路由。您将看到什么是 MySQL 路由以及如何使用它。第 7 章展示了 MySQL 路由的使用。

Footnotes [1](#Fn1_source)

JavaScript 专家和 Pythonistas 都会喜欢这个特性。

 

六、MySQL 路由

现在,您已经了解了 InnoDB Cluster 的工作原理,并看到了如何通过 MySQL Shell 使用 AdminAPI 快速配置测试集群的简短演示,为了使您的应用真正具有高可用性,您还需要 InnoDB Cluster 的一个部分。

考虑一下,如果我们连接到集群,而我们所连接的机器离线,应用会做什么。我们知道集群可以从这样的损失中恢复(假设组中的服务器数量足够(参见第 3 章)),但是我们对我们的应用做些什么呢?如果服务器离线,我们无法知道哪一个(或者是否)另一个服务器已经接管。

一些开发者可能会尝试在他们的应用中构建重试连接的能力,或者在与当前服务器的连接失败时重试预先确定的不同连接的能力。虽然这可以得到您所需要的,但是它是脆弱的,需要将集群中服务器的所有主机名、端口等嵌入或提供给应用。显然,一定有更好的方法。Oracle 用 MySQL 路由回应了这一呼吁。

本章讨论 MySQL 路由,包括如何设置和配置路由。本章最后给出了修改应用以充分利用路由的建议。

概观

MySQL 路由是 MySQL InnoDB 集群的透明连接路由服务,提供负载平衡、应用连接故障转移和客户端路由。路由的连接路由特性意味着我们可以编写应用来连接到路由,并让 MySQL Router 通过使用一种支持的路由策略来处理到正确服务器的连接路由。路由成为应用和集群之间的中介服务。

其他连接路由应用和服务器可能会检查路由到正确服务器的数据包(或除此之外),但 MySQL 路由(因此,路由)不会进行这种检查。您的通信数据包未被打开、检查或更改;它们只是根据几个选项之一被转发到正确的服务器。

虽然这种简单性意味着路由是轻量级的,需要很少的资源,但是路由的配置有一些挑战。更具体地说,单个写集群的简单设置和配置是容易的。事实上,MySQL 安装程序有一个自动配置步骤,使在 Windows 上安装路由成为一件简单的事情。然而,对于更复杂的配置,您可能希望花一些时间用可能的策略和其他选项来配置和测试您的应用。您将在后面的章节中看到更多关于配置路由的内容。

对于那些希望增强其诊断或调试工作的人,路由还支持记录消息,包括关于连接如何路由、状态、错误和警告等的声明。这只是完全可定制的几个关键功能之一。

该路由可用于多种用例,包括为 MySQL 服务器提供高可用性甚至可伸缩性。在这种情况下,高可用性是通过自动故障转移功能实现的,如果群集中指定(选定)的服务器出现故障,该功能会自动路由客户端连接。

当与 MySQL InnoDB Cluster(通过底层组复制)一起使用以跨多个服务器复制数据库,同时在服务器出现故障时执行自动故障转移时,路由充当代理来隐藏网络上的多个 MySQL 实例,并将数据请求映射到其中一个集群实例。如果有足够的在线副本并且可靠的网络通信是可能的,那么使用该路由的应用将能够联系剩余的服务器之一。路由通过让应用连接到 MySQL 路由而不是直接连接到特定的 MySQL 服务器来实现这一点。图 6-1 显示了路由相对于您的应用和 InnoDB 集群所处位置的逻辑视图。

img/460910_1_En_6_Fig1_HTML.jpg

图 6-1

使用 MySQL 路由的应用架构(Oracle 公司出品)

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

小费

您可以在一台或多台机器上运行多个 MySQL Router 实例,在路由点提供一定程度的容错。您不需要将路由隔离到一台机器上。这是可能的,因为路由与其主机没有亲缘关系。

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

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

最后,该路由使开发者能够通过使用定制用例的插件来扩展 MySQL 路由。如果您的应用需要不同的路由策略,或者您想要在解决方案中构建数据包检测,您可以使用自定义插件来扩展路由。尽管为路由构建定制插件超出了本章的范围,也没有可供研究的示例,但请务必查看 MySQL 开发者网站( https://dev.mysql.com )和 MySQL 工程博客( https://mysqlserverteam.com /)以获取最新的信息和示例。

现在,您已经了解了什么是路由以及它应该放在基础设施中的什么位置,下面让我们来看看如何安装和配置路由。

装置

安装 MySQL 路由很容易。Oracle 为 MySQL 服务器支持的所有平台提供路由安装包。路由也包含在 Windows 的 MySQL 安装程序中。

在本节中,您将学习如何在 Windows 上安装 MySQL Router,并观看 MySQL 安装程序中提供的示例配置步骤的演示。您还将简要了解如何为其他平台安装路由。您将在后面的章节中学习如何手动配置路由。让我们先来看看 MySQL 安装程序。

MySQL Installer (Windows)

如果您已经按照前面的章节安装了 MySQL Server、MySQL Shell 和其他组件,那么本节中的信息将会很熟悉。但是,如果这是您第一次在 Windows 上使用路由,让我们一步一步来安装。

小费

如果您的环境不是同构的,并且您的应用服务器是一台 Windows 机器,您将希望使用本节作为在您的 Windows 应用服务器上设置路由的指南。

使用 MySQL 安装程序安装 MySQL 路由遵循与安装 MySQL Shell 相同的模式。但是,因为安装程序已经在系统中,我们只需再次启动它,并添加我们想要的 MySQL 产品(如路由)。当您启动安装程序时,会出现一个欢迎面板,其中包含已安装产品的列表。图 6-2 显示了 MySQL Shell 安装后 MySQL 安装程序的欢迎面板。

img/460910_1_En_6_Fig2_HTML.jpg

图 6-2

安装程序欢迎面板-安装后(MySQL 安装程序)

请注意,我们可以选择添加(添加… )新产品,修改(修改… )已安装产品的安装或配置,从目录(安装程序)中升级(升级… )具有较新版本的已安装产品,或者移除已安装产品(移除… )。请注意,还有一个名为 Catalog… 的按钮,它允许您更新安装程序中的产品目录。这允许您用新版本更新产品。

对于本教程,我们希望安装 MySQL 路由和连接器/Python 数据库连接器。我们将通过编写一个基本的连接示例来使用数据库连接器测试路由安装,这意味着我们还需要安装 Python。如果您的 Windows 机器上没有安装 Python,请参见 https://www.python.org/downloads/windows/ 下载并安装最新版本(版本 2.7 或 3.6 或更高版本)。

回想一下,我们单击“添加”继续。然后您将看到产品选择面板,如图 6-3 所示。只需导航左侧的树找到 MySQL 路由,选择它,然后单击绿色箭头将其添加到右侧的列表中。重复上述步骤,选择与您的 Python 安装相匹配的连接器/Python 版本。添加完两者后,单击“下一步”按钮继续。

小费

MySQL 安装程序将灰显任何与您的 Python 安装不匹配的版本。如果您不确定您安装了哪个版本的 Python,您可以从命令提示符下运行python --version

img/460910_1_En_6_Fig3_HTML.jpg

图 6-3

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

6-4 中显示的下一个面板是一个安装摘要,允许您确认是否有正确的产品列出进行安装。该面板还会指示状态,以便您可以观察安装进度。当您准备好开始安装所选产品时,请单击执行。

img/460910_1_En_6_Fig4_HTML.jpg

图 6-4

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

安装开始后,你会看到每个产品的进度,如图 6-5 所示。

img/460910_1_En_6_Fig5_HTML.jpg

图 6-5

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

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

img/460910_1_En_6_Fig6_HTML.jpg

图 6-6

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

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

在这一步中,我们将配置路由用于沙箱安装。如果您尚未将 InnoDB 集群配置为在沙箱中运行,请参见第 5 章了解详细信息。在使用 MySQL 安装程序配置路由之前,必须运行 InnoDB 集群。

img/460910_1_En_6_Fig7_HTML.jpg

图 6-7

产品配置(MySQL 安装程序)

这一步开始 MySQL 路由配置。请注意,在图 6-8 中,安装程序正在询问集群中某个服务器的连接信息。回想一下第 5 章,我们使用端口 3311 作为主端口。因此,我们在端口文本框中输入 3311,并在密码文本框中提供根密码。我们将使用传统协议端口的默认值。准备好后,单击下一步。

img/460910_1_En_6_Fig8_HTML.jpg

图 6-8

MySQL 路由配置(MySQL 安装程序)

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

img/460910_1_En_6_Fig9_HTML.jpg

图 6-9

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

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

img/460910_1_En_6_Fig10_HTML.jpg

图 6-10

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

当产品配置完成后,面板会发生变化,显示已配置产品的摘要,如图 6-11 所示。准备好后,请单击“下一步”按钮继续。

img/460910_1_En_6_Fig11_HTML.jpg

图 6-11

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

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

img/460910_1_En_6_Fig12_HTML.jpg

图 6-12

安装完成(MySQL 安装程序)

当所有操作完成后,安装程序将返回到欢迎面板,显示所有已安装产品的列表,如图 6-13 所示。完成后,您可以关闭安装程序,或者添加、修改、升级或移除其他产品。您还可以通过单击“重新配置”链接来重新配置任何已安装的产品。

img/460910_1_En_6_Fig13_HTML.jpg

图 6-13

安装程序欢迎面板-安装后(MySQL 安装程序)

配置路由时出现问题

如果您已经安装了 MySQL 路由,但是配置步骤失败了,这很可能是因为 root 用户的密码错误。这也可能是由于对 InnoDB 集群中的服务器使用了错误的端口(通常,这是单主服务器设置中的主服务器)造成的。如果您更正了这些信息,但仍然无法完成配置,请尝试连接到您的 InnoDB 集群,如第 5 章所述。当您可以成功连接到集群时,路由的配置应该会成功。如果您想再次运行配置,只需重新启动 MySQL 安装程序并单击 Reconfigure 链接即可重新运行配置。

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

清单 6-1 展示了一个通过路由连接到 InnoDB 集群的简单 Python 脚本。回想一下,我们在 Windows 机器上安装了路由,因此这个脚本(为了一致性,如果不是练习的话)应该在同一台机器上执行。花点时间检查一下代码。即使您从未使用过 Connector/Python 或编写过 Python,也应该很清楚发生了什么。

#
# Introducing MySQL InnoDB Cluster
#
# 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, 2018
#
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("\nRetrieve 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 6-1Router Connection Test

代码的第一部分导入连接器并定义一个连接术语字典——在本例中,是路由的用户、密码、主机和端口。我们使用的是端口号 6446,如 MySQL 安装程序中路由配置期间所示(参见图 6-8 )。

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

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

python ./router_connect_test.py

运行后,您将看到如下输出:

Listing the databases on the server.
('information_schema',)
('mysql',)
('mysql_innodb_cluster_metadata',)
('performance_schema',)
('sys',)

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

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

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

Listing the databases on the server.
('information_schema',)
('mysql',)
('mysql_innodb_cluster_metadata',)
('performance_schema',)
('sys',)

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

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

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

其他平台

如前所述,如果不是使用 Windows,仍然可以使用 MySQL 路由;路由不需要使用 Windows。然而,在其他平台上设置路由实际上需要更多的手动操作。

在其他平台上安装 MySQL 路由最好使用第 2 章中描述的特定于平台的存储库。本节演示如何在 Ubuntu 上使用 MySQL APT 库安装 shell。前提条件是您已经安装了存储库。

在安装了存储库并用sudo apt-get update更新了系统之后,您可以简单地发出sudo apt-get install mysql-router命令,如清单 6-2 所示。

$ sudo apt-get install mysql-router
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libevent-core-2.0-5 libllvm4.0 libqmi-glib1 snap-confine
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  mysql-router
0 upgraded, 1 newly installed, 0 to remove and 38 not upgraded.
Need to get 2,388 kB of archives.
After this operation, 15.3 MB of additional disk space will be used.
Get:1 http://repo.mysql.com/apt/ubuntu xenial/mysql-tools amd64 mysql-router amd64 8.0.11-1ubuntu16.04 [2,388 kB]
Fetched 2,388 kB in 20s (115 kB/s)
Selecting previously unselected package mysql-router.
(Reading database ... 309484 files and directories currently installed.)
Preparing to unpack .../mysql-router_8.0.11-1ubuntu16.04_amd64.deb ...
Unpacking mysql-router (8.0.11-1ubuntu16.04) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
/sbin/ldconfig.real: /usr/lib/libmysqlcppconn.so.7 is not a symbolic link

Processing triggers for systemd (229-4ubuntu21.2) ...
Processing triggers for ureadahead (0.100.0-19) ...
Setting up mysql-router (8.0.11-1ubuntu16.04) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
/sbin/ldconfig.real: /usr/lib/libmysqlcppconn.so.7 is not a symbolic link

Processing triggers for systemd (229-4ubuntu21.2) ...
Processing triggers for ureadahead (0.100.0-19) ...

Listing 6-2Installing the MySQL Router (Ubuntu)

现在路由已经安装好了,回想一下,我们还希望安装 Connector/Python,以便像在上一节中一样测试路由。我们使用清单 6-3 中所示的sudo apt-get install mysql-connector-python命令来安装连接器/Python。

$ sudo apt-get install mysql-connector-python
[sudo] password for cbell:
Reading package lists... Done
Building dependency tree
Reading state information... Done

The following packages were automatically installed and are no longer required:
  libevent-core-2.0-5 libllvm4.0 libqmi-glib1 snap-confine
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  mysql-connector-python
0 upgraded, 1 newly installed, 0 to remove and 38 not upgraded.
Need to get 174 kB of archives.
After this operation, 1,339 kB of additional disk space will be used.
Get:1 http://repo.mysql.com/apt/ubuntu xenial/mysql-tools amd64 mysql-connector-python all 8.0.11-1ubuntu16.04 [174 kB]
Fetched 174 kB in 6s (25.7 kB/s)
Selecting previously unselected package mysql-connector-python.
(Reading database ... 309396 files and directories currently installed.)
Preparing to unpack .../mysql-connector-python_8.0.11-1ubuntu16.04_all.deb ...
Unpacking mysql-connector-python (8.0.11-1ubuntu16.04) ...
Setting up mysql-connector-python (8.0.11-1ubuntu16.04) ...

Listing 6-3Installing the MySQL Connector/Python (Ubuntu)

如上所述,以这种方式安装 MySQL 路由不会像在 Windows 上演示的那样运行自定义配置步骤。要在其他平台上使用路由或进行自定义安装,我们必须手动配置路由以匹配我们的集群。

配置

配置 MySQL 路由并不难,但是配置项的数量可能会让它看起来很难。本节给出了一个简单的例子,说明如何配置 MySQL 路由,以便与运行在沙箱中的 InnoDB 集群一起使用;本节演示了使路由工作所需的手动步骤。我们还将使用上一节中显示的相同的简单 Python 脚本来测试路由设置。

在沙箱中设置 InnoDB 集群

让我们花点时间来回顾一下我们是如何在沙箱中设置 InnoDB 集群的。如果您没有尝试过上一章中的示例,或者您没有在 Windows 上使用路由,或者之前没有设置过路由,这在这一点上可能会有所帮助。回想一下第 5 章,我们有两个脚本通过 MySQL Shell 使用 Python 命令来设置和关闭一个示例集群。

在这种情况下,我们将使用第 5 章中所示的相同脚本来设置一个集群,运行一个写(主)和三个只读(辅助)服务器。但是,因为该脚本是为 Windows 编写的,所以我们必须对其稍加修改,以更改集群数据的默认目录。清单 6-4 显示了setup_idc_sandbox.py文件的修改版本,其中的变化以粗体显示。

# Introducing InnoDB Cluster

#
# This Python script is designed to set up an InnoDB Cluster in a sandbox.
#
# Note: Change the cluster directory to match your preferred directory setup.
#
# The steps include:
# 1) create the sandbox directory
# 2) deploy instances
# 3) create the cluster
# 4) add instances to the cluster
# 5) show the cluster status
#
# Dr. Charles Bell, 2018
#
import os
import time

# Method to deploy sandbox instance
def deploy_instance(port):
    try:
        dba.deploy_sandbox_instance(port, {'sandboxDir':'/home/cbell/idc_sandbox', 'password':'secret'})
    except:
        print("ERROR: cannot setup the instance in the sandbox.")
    time.sleep(1)

# Add instance to cluster

def add_instance(cluster, port):
    try:
        cluster.add_instance('root:secret@localhost:{0}'.format(port))
    except:
        print("ERROR: cannot add instance to cluster.")
    time.sleep(1)

print("##### STEP 1 of 5 : CREATE SANDBOX DIRECTORY #####")
os.mkdir('/home/cbell/idc_sandbox')

print("##### STEP 2 of 5 : DEPLOY INSTANCES #####")
deploy_instance(3311)
deploy_instance(3312)
deploy_instance(3313)
deploy_instance(3314)

print("##### STEP 3 of 5 : CREATE CLUSTER #####")
shell.connect('root:secret@localhost:3311')
my_cluster = dba.create_cluster('MyCluster', {'multiMaster':False})
time.sleep(1)

print("##### STEP 4 of 5 : ADD INSTANCES TO CLUSTER #####")
add_instance(my_cluster, 3312)
add_instance(my_cluster, 3313)
add_instance(my_cluster, 3314)

print("##### STEP 5 of 5 : SHOW CLUSTER STATUS #####")
shell.connect('root:secret@localhost:3311')
time.sleep(1)
my_cluster = dba.get_cluster('MyCluster')
time.sleep(1)
status = my_cluster.status()

print(status)

Listing 6-4Setup InnoDB Cluster Script (Ubuntu)

注意

您还必须更改脚本中的密码和路径,以匹配您的配置。

清单 6-5 显示了运行在 Ubuntu 上的这个脚本的摘录。回想一下,因为脚本使用的是 AdminAPI,所以我们必须使用 MySQL Shell 来执行它。

$ mysqlsh -f setup_idc_sandbox.py
##### STEP 1 of 5 : CREATE SANDBOX DIRECTORY #####
##### STEP 2 of 5 : DEPLOY INSTANCES #####
Deploying new MySQL instance...

Instance localhost:3311 successfully deployed and started.
Use shell.connect('root@localhost:3311'); to connect to the instance.
...
##### STEP 3 of 5 : CREATE CLUSTER #####
A new InnoDB cluster will be created on instance 'root@localhost:3311'.
...
##### STEP 4 of 5 : ADD INSTANCES TO CLUSTER #####
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 ...

Validating instance at localhost:3312...
Instance detected as a sandbox.
...
##### STEP 5 of 5 : SHOW CLUSTER STATUS #####
{"clusterName": "MyCluster", "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"}, "localhost:3312": {"address": "localhost:3312", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}, "localhost:3313": {"address": "localhost:3313", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}, "localhost:3314": {"address": "localhost:3314", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE"}}}, "groupInformationSourceMember": "mysql://root@localhost:3311"}

Listing 6-5Setting Up the InnoDB Cluster in a Sandbox

修改配置文件

MySQL 路由将其初始配置存储在一个文件中。该文件设置路由与集群配合工作的参数,包括故障转移协议、路由信息、为应用通告(监听)的端口以及集群本身的连接元数据等。

小费

参见在线 MySQL 路由文档( https://dev.mysql.com/doc/mysql-router/8.0/en/ )了解 MySQL 路由所有选项和配置项的完整说明。

尽管路由没有任何平台关联性(它在所有平台上都运行良好),但配置文件的位置可能会有所不同。对于 Windows,配置文件位于名为mysqlrouter.confC:\ProgramData\MySQL\MySQL Router文件夹中。在 Linux 上,配置文件位于名为mysqlrouter.conf/etc/mysqlrouter/文件夹中。

您可以通过运行命令mysqlrouter --help立即找到文件的位置以及大量其他信息,该命令不仅记录了所有选项,还显示了文件的位置。清单 6-6 显示了输出的摘录。

$ mysqlrouter --help
MySQL Router v8.0.11 on Linux (64-bit) (GPL community edition)
Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
...
Configuration read from the following files in the given order (enclosed
in parentheses means not available for reading):
  /etc/mysqlrouter/mysqlrouter.conf
  (/home/cbell/.mysqlrouter.conf)
Plugins Path:
  /usr/lib/x86_64-linux-gnu/mysqlrouter
Default Log Directory:
  /var/log/mysqlrouter
Default Persistent Data Directory:
  /var/lib/mysqlrouter
Default Runtime State Directory:
  /run/mysqlrouter

...

Listing 6-6MySQL Router Help (Ubuntu)

现在我们知道集群正在运行,并且安装了 MySQL 路由,让我们看看路由的默认配置文件。清单 6-7 显示了典型 Linux 安装的配置文件。

 [DEFAULT]
logging_folder = /var/log/mysqlrouter/
plugin_folder = /usr/lib/x86_64-linux-gnu/mysqlrouter
runtime_folder = /var/run/mysqlrouter
config_folder = /etc/mysqlrouter

[logger]
level = INFO

# If no plugin is configured that starts a service, keepalive
# will make sure MySQL Router will not immediately exit. It is
# safe to remove after Router is configured.
[keepalive]
interval = 60

Listing 6-7Default Router Configuration File

请注意文件中的最后几行。当我们完成配置时,我们将看到这些被删除。还要注意,文件中没有关于集群配置的信息。完成路由配置需要两个基本组件。首先,我们必须设置正确的路径,以确保路由能够访问正确的密码加密机制。其次,我们必须在初始配置中为每台服务器配置所有路由参数和策略。虽然您可以自己手动操作,但使用--bootstrap选项可以快速启动。

使用引导选项进行配置

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

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

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

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

  • --user <username>:以指定名称的用户身份运行mysqlrouter(在 Windows 上不可用)。你也可以使用快捷键-u

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

sudo mysqlrouter --bootstrap root:secret@localhost:3311 --name sandbox --user cbell

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

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

Bootstrapping system MySQL Router instance...
Modulenot registered with logger - logging the following message as 'main' instead
MySQL Router 'sandbox' has now been configured for the InnoDB cluster 'MyCluster'.

The following connection information can be used to connect to the cluster.

Classic MySQL protocol connections to cluster 'MyCluster':
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
X protocol connections to cluster 'MyCluster':
- Read/Write Connections: localhost:64460
- Read/Only Connections: localhost:64470

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

Listing 6-8Configuration with the Bootstrap Option

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

使用引导配置文件

bootstrap 选项创建的配置文件包含在应用和集群中使用路由所需的所有信息。它使用所有设置的默认值和集群中的值来设置队列和端口。经典协议的默认端口为 6446、6447,X 协议的默认端口为 64460、64470。

清单 6-9 显示了清单 6-8 中所示的执行所产生的配置文件。

# File automatically generated during MySQL Router bootstrap
[DEFAULT]
name=sandbox
user=cbell
keyring_path=/var/lib/mysqlrouter/keyring
master_key_path=/etc/mysqlrouter/mysqlrouter.key
connect_timeout=30
read_timeout=30

[logger]
level = INFO

[metadata_cache:MyCluster]
router_id=10
bootstrap_server_addresses=mysql://localhost:3311,mysql://localhost:3312,mysql://localhost:3313,mysql://localhost:3314
user=mysql_router10_r7dqvu1t52bj
metadata_cluster=MyCluster
ttl=5

[routing:MyCluster_default_rw]
bind_address=0.0.0.0
bind_port=6446
destinations=metadata-cache://MyCluster/default?role=PRIMARY
routing_strategy=round-robin
protocol=classic

[routing:MyCluster_default_ro]
bind_address=0.0.0.0
bind_port=6447
destinations=metadata-cache://MyCluster/default?role=SECONDARY
routing_strategy=round-robin
protocol=classic

[routing:MyCluster_default_x_rw]
bind_address=0.0.0.0
bind_port=64460
destinations=metadata-cache://MyCluster/default?role=PRIMARY
routing_strategy=round-robin
protocol=x

[routing:MyCluster_default_x_ro]
bind_address=0.0.0.0
bind_port=64470
destinations=metadata-cache://MyCluster/default?role=SECONDARY
routing_strategy=round-robin
protocol=x

Listing 6-9Bootstrap Configuration File

哇,这与我们之前看到的简短默认配置文件非常不同。这看起来可能很复杂,但实际上并不复杂。让我们看看配置文件中的每个部分。更具体地说,该文件的格式类似于许多其他配置文件:方括号用于定义节,每个节中有一个或多个带有赋值的关键字(变量)(有时称为键/值对)。

[默认]

默认部分是放置路由实例的所有常规设置的地方,即路由正确执行所需的所有参数。下面总结了示例中出现的变量及其用法:

  • name:引导选项中为集群提供的名称

  • user:用于访问路由实例的配置文件和元数据的用户名

  • keyring_path:密匙环安全文件的路径

  • master_key_path:key ring 主密钥文件的路径

  • connect_timeout:尝试连接时超时的秒数

  • read_timeout:等待读取请求时超时的秒数

如您所见,bootstrap 步骤为所有这些变量提供了默认值,除了 name 和 user,它们是在命令行上指定的。

[记录者]

logger 部分没有修改默认文件。在这种情况下,它只记录信息性消息。要了解有关记录选项的更多信息,包括如何自定义记录的内容,请参见在线参考手册中的“使用记录功能”一节( https://dev.mysql.com/doc/mysql-router/8.0/en/mysql-router-server-logging.html )。

[元数据 _ 缓存:我的群集]

本节定义了集群的初始元数据。此示例使用以下变量:

  • router_id:和server_id一样,这是路由实例的唯一值,每个路由实例都应该有自己的 ID 值。

  • bootstrap_server_addresses:初始队列中的服务器列表。

  • user:使用密匙环服务连接到服务器的自动生成用户。

  • metadata_cluster:集群的名称。

  • ttl:元数据高速缓存中信息的生存时间(秒)。

在本节中,您应该了解更多的两个关键变量是bootstrap_server_addressesuserbootstrap_server_addresses变量需要集群中每个服务器的host:port值的逗号分隔列表。因为引导操作连接到群集,所以它为我们检索信息。这里,列表包括集群中的所有服务器。这里的user变量是一个自动生成的用户,用于密匙环协议。你不需要改变这个。

如果手动构建配置文件,bootstrap_server_addresses是获得正确结果的最关键的值。确保包括群集中所有已知的服务器。请记住,路由会随着集群拓扑的变化自动更新其缓存,但它需要一个稳定的起点,这个变量提供了该数据。

[路由: ]

此部分是连接路由部分,用于定义路由为应用提供的连接路由。路由按类型组织,如读/写和只读。对于我们想要定义的每种类型的路线,该部分重复一次。在这种情况下,我们有四个路由:一个用于使用传统(经典)协议的读/写,另一个用于只读,一个用于使用 X 协议的读/写,还有一个用于使用 X 协议的只读。对于每个部分,我们指定以下变量。每个部分名称必须以routing:开头,后跟唯一的名称标签。在这种情况下,引导操作选择描述每个连接的读/写状态和所用协议的名称。

  • bind_address:路由绑定的地址,如果没有定义端口,也使用bind_port

  • bind_port:默认端口bind_address使用

  • destinations:以逗号分隔的 MySQL 服务器列表的形式路由目的地

  • routing_strategy:路由策略(可选),路由如何选择目的 MySQL 服务器

  • protocol:用于值为classic的连接的协议(也称为传统协议),或者简称为 X 协议的x

bind_addressbind_port变量特定于用于定义连接的服务器。类似地,protocol让我们可以选择用于连接的协议。因此,我们看到读/写和只读路由的两个连接路由:一个用于 classic,另一个用于 X 协议。此外,指定的端口是路由侦听连接路由的端口,而不是路由将路由定向到的服务器的端口。这可能是配置连接路由时需要掌握的最重要的概念。

这里最有趣的是destinations变量。此变量为建立连接提供主机信息。它接受逗号分隔的目标地址列表或指向群集的元数据缓存链接。引导操作生成元数据缓存选项。该字符串定义如下:

destinations=metadata-cache://mycluster/default?role=PRIMARY

角色可以是PRIMARYSECONDARYPRIMARY_AND_SECONDARY。这决定了连接可用的实例类型。

最后,routing_strategy可以用来改变路由选择队列中下一个服务器的方式。默认值为round-robin,但也可以是以下值之一:

  • first-available:新连接被路由到目的地列表中第一个可用的服务器。如果失败,将使用下一个可用的服务器。这个循环一直持续到所有服务器都不可用。

  • next-available:与first-available类似,新连接被路由到目的地列表中第一个可用的服务器。与first-available不同,如果一台服务器被标记为不可达,它就会被丢弃,并且永远不会再被用作目的地。

  • 为了负载平衡,每个新连接都以循环方式连接到下一个可用的服务器。

  • round-robin-with-fallback:为了负载平衡,每个新连接都以循环方式连接到下一个可用的辅助服务器。如果辅助服务器不可用,则以循环方式使用主列表中的服务器。

花点时间再次浏览文件,看看每个连接路由是如何配置的。一旦你习惯了这些术语,就不会觉得奇怪了。

等等,其他服务器的连接在哪里?

如果您想知道为什么集群中的其他服务器没有连接路由,您必须记住,路由被设计为查询集群中的元数据并自动选择服务器。不需要为每个服务器指定特定的连接路由。相反,我们为每种类型的服务器定义路由:读/写、只读等等。

现在,您对如何配置路由有了更多的了解,让我们开始测试吧。

启动路由

最后,我们可以使用以下命令启动路由:

$ mysqlrouter &

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

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

测试新配置

为了测试路由,我们将使用清单 6-1 (名为router_connect_test.py)中的 Python 脚本。回想一下,这是一个包含 Python 中 AdminAPI 调用的脚本。我们必须从 MySQL Shell 运行这个脚本。幸运的是,它不需要任何改变就可以在 Ubuntu 上运行。但是,如果您遵循前面的示例,您应该更改连接字典以连接到读/写端口 6446,如下所示:

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

回想一下,我们使用python ./router_connect_test.py命令告诉 shell 加载 Python 脚本并执行它。当您这样做时,您应该会看到如下所示的输出:

$ python ./router_connect_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,这是主(读/写)服务器的端口。酷!

演示如何手动安装和配置路由到此结束。对于大多数安装,这是使路由为您的应用工作所需要的。但是,如果您需要更高级的路由或特定选项,您可以查看所有可用选项的在线参考手册,如果您计划为多个单主模式配置您的集群,或者您想要在多个应用服务器上部署路由的多个实例,强烈建议您查看该手册。例如,如果您想要使用 SSL 连接运行路由,请参见以--ssl*开头的选项。

小费

要了解有关配置路由的更多信息,包括设置不同的路由策略,请参见在线参考手册 https://dev.mysql.com/doc/mysql-router/8.0/en/mysql-router-configuration.html

下一节将介绍在应用中使用路由的一些方面,包括修改应用以充分利用路由的技巧和建议。

在应用中使用路由

至此,我们有了一个基本的工作路由实例,它将连接路由到我们的 InnoDB 集群。您已经看到了我们如何使用应用中路由配置中列出的端口连接到集群。具体来说,我们有以下可用端口,它们映射到路由配置文件中定义的连接路由:

  • 6446:用于读/写操作的经典协议连接(例如,PRIMARY)

  • 6447:只读操作的经典协议连接(例如,SECONDARY)

  • 64460:用于读/写操作的 X 协议连接(例如,PRIMARY

  • 64470:只读操作的 X 协议连接(如SECONDARY

太棒了,对吧?但是这对我们的应用意味着什么呢?让我们后退一步,考虑一下在我们的应用中使用路由的条件和后果。

首先,理解 MySQL 路由不需要特定的库或接口是很重要的。它是自包含的,没有任何先决条件或依赖性,例如需要服务器实例才能工作。这对于规划您的应用部署来说是个好消息。您可以在您的应用服务器上部署路由,而不用担心依赖性冲突或者甚至性能影响。

其次,在应用中使用路由时,您应该始终连接到连接路由中定义的端口,而不要直接连接到集群服务器本身。此外,您应该为您的连接建立一个重试机制。这是必要的,因为当路由检测到服务器脱机时,它可能会断开连接,并与下一台服务器重新建立连接。更具体地说,由于 MySQL 路由在尝试连接时重定向连接,并且不读取数据包或执行分析,因此如果 MySQL 服务器出现故障,路由会将连接错误返回给应用。因此,应该编写应用来测试连接错误,如果遇到错误,就重试连接。幸运的是,开发者通常将这种机制构建到他们的应用中,因此您可能只需将连接更改为路由的连接即可。

让我们考虑一些在您的应用中实现路由的用例。当然,路由的使用方式有很多,下面仅列出了一些较为常见的使用案例:

  • 我希望我的应用连接到一个服务,这样默认情况下,它可以连接到组复制集群的当前主服务器。

  • 我想设置多个服务,所以 MySQL 路由监听每个高可用性副本集(集群)的不同端口。

  • 我希望能够在端口 3306 上运行连接路由服务,这样对用户或应用来说就更加透明了。

  • 我想为每个连接路由服务配置一个模式,这样我就可以指定返回主服务还是辅助服务。

最后,让我们讨论一下路由的工作流程,这样您就可以了解它如何适合规划您的应用。以下绝不是唯一的工作流,但它是大多数使用案例的典型:

  1. 应用连接到 MySQL 路由,例如连接到端口 6446。

  2. 路由检查可用的 MySQL 服务器。

  3. 路由打开到合适的 MySQL 服务器的连接。

  4. 路由在应用和 MySQL 服务器之间来回转发数据包。

  5. 如果连接的 MySQL 服务器出现故障,路由会断开应用。

  6. 然后,应用可以重试连接到路由,路由选择一个不同的可用 MySQL 服务器。

在下一章的典型部署场景中,我们将探索如何使用 InnoDB 集群,同时我们将考虑在我们的应用中使用 MySQL 路由的更多含义。

摘要

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

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

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

由于路由体积小、重量轻,您甚至可以通过让多个实例运行单独的连接路由,在路由中构建冗余。MySQL 路由有什么不喜欢的地方?不多。这是许多高可用性解决方案似乎缺少的一部分。

下一章将介绍如何在一组机器上部署 MySQL InnoDB 集群,并使用一个简单的应用配置路由,以展示如何为自己的应用实现高可用性目标。