实现 Galera 集群配置

为了在 Trove 中运行生产工作负载时建立用户信任,数据库实例的高可用性至关重要。除了复制之外,集群还通过允许从集群中的任何节点访问数据来确保部署的高可用性。它增强了系统正常运行时间,防止数据丢失,并使架构更具可扩展性,以适应未来的增长。目前 Trove 支持 MongoDB 集群和 Percona 集群。Trove 中 MariaDB 数据存储的集群将基于 Galera 集群,这是一种同步多主数据库集群。

Launchpad 蓝图:https://blueprints.launchpad.net/trove/+spec/mariadb-clustering

问题描述

MariaDB 数据存储不支持集群。添加集群实现将允许用户创建、读取和写入可扩展且高可用的部署。

提议的变更

Galera 集群将利用 Trove 中现有的基础集群实现,通过创建可插拔和可配置的策略来实现。

要求

  • Galera 集群的实例由一系列节点组成,最好是三个或更多节点。

  • 初始集群创建将从 3 个或更多节点开始。

  • 集群检查将返回所有节点的 IP 地址,以便随时允许对任何节点进行读写操作。

  • 每个实例的名称将自动生成。

  • 集群应允许调整集群节点的卷和风味大小。如果用户调整实例的卷或风味大小,将不会进行验证。

以下内容将被更改

  • 将在 common/strategies/cluster/experimental/galera_common/{api,taskmanager,guestagent}.py 中添加 Percona 集群和 Galera 集群的基础类。

  • Percona 集群的特化将在 common/strategies/cluster/experimental/pxc/{api,taskmanger,guestagent}.py 下实现。这包含用于 Percona 集群配置的 API、任务管理器策略和客户机代理策略。

  • Galera 集群的特化将被添加到 common/strategies/cluster/experimental/mariadb/{api,taskmanager,guestagent}.py。这包含用于 Galera 集群配置的 API、任务管理器策略和客户机代理策略。

  • 单元和集成测试

配置

将添加一个新的数据存储配置部分。此初始实现将不添加任何 Galera 集群特定的配置选项。

数据库

此实现将利用现有的集群数据库模式。

公共 API

创建/删除集群的 API 请求将保持不变。但是,响应会有一些细微的差异。与 Percona 实现一样,Galera 集群将返回其所有节点的 IP 地址。这将用于希望扩展读/写操作的用户。

创建集群

请求

POST /v1.0/<tenant_id>/clusters
{
  "cluster": {
    "name": "products",
    "datastore": {
      "type": "mariadb",
      "version": "10"
    },
    "instances": [
      {
        "flavorRef": "2",
        "volume": {
          "size": 100
        },
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 100
        },
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 100
        },
      }
    ],
  }
}

响应

{
  "cluster": {
    "id": "c33385b2-6c2a-491e-b44e-bcbb4af24136",
    "task": {
      "id": 2,
      "name": "BUILDING",
      "description": "Building the initial cluster."
    },
    "name": "products",
    "created": "2015-12-14T20:19:23",
    "updated": "2015-12-14T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "mariadb",
      "version": "10"
    },
    "instances": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "status": "BUILD",
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
      },
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
        "status": "BUILD",
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
      },
      {
        "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
        "status": "BUILD",
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
      }
    ],
  }
}

显示集群

请求

GET /v1.0/<tenant_id>/clusters/c33385b2-6c2a-491e-b44e-bcbb4af24136

响应

{
  "cluster": {
    "id": "c33385b2-6c2a-491e-b44e-bcbb4af24136",
    "task": {
      "id": 1,
      "name": "NONE",
      "description": "No tasks for the cluster."
    },
    "name": "products",
    "created": "2015-12-14T20:19:23",
    "updated": "2015-12-14T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "mariadb",
      "version": "10"
    },
    "instances": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "status": "ACTIVE",
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
        "ip": "10.0.0.1"
      }
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
        "status": "ACTIVE",
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
        "ip": "10.0.0.2"
      },
      {
        "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
        "status": "BUILD",
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 100
        },
        "ip": "10.0.0.3"
      }
    ],
  }
}

显示实例

请求

GET /v1.0/<tenant_id>/clusters/c33385b2-6c2a-491e-b44e-bcbb4af24136/instances/416b0b16-ba55-4302-bbd3-ff566032e1c1

响应

{
  "instance": {
    "status": "ACTIVE",
    "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
    "cluster_id": "dfbbd9ca-b5e1-4028-adb7-f78643e17998",
    "name": "products-1",
    "created": "2014-04-25T20:19:23",
    "updated": "2014-04-25T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "mariadb",
      "version": "10"
    },
    "ip": ["10.0.0.1"],
    "flavor": {
      "id": "7",
      "links": [{...}],
    },
    "volume": {
      "size": 100,
      "used": 0.17
    },
  }
}

列出集群

请求

GET /v1.0/<tenant_id>/clusters

响应

{
  "clusters": [
    {
      "id": "c33385b2-6c2a-491e-b44e-bcbb4af24136",
      "task": {
        "id": 1,
        "name": "NONE",
        "description": "No tasks for the cluster."
      },
      "name": "products",
      "created": "2014-04-25T20:19:23",
      "updated": "2014-04-25T20:19:23",
      "links": [{...}],
      "ip": ["10.0.0.1", "10.0.0.2", "10.0.0.3"],
      "datastore": {
        "type": "mariadb",
        "version": "10"
      },
      "instances": [
        {
          "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
          "status": "ACTIVE",
          "flavor": {
            "id": "7",
            "links": [{...}]
          },
          "volume": {
            "size": 100
          },
          "ip": "10.0.0.1",
        }
        {
          "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
          "status": "ACTIVE",
          "flavor": {
            "id": "7",
            "links": [{...}]
          },
          "volume": {
            "size": 100
          },
          "ip": "10.0.0.2",
        },
        {
          "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
          "status": "ACTIVE",
          "flavor": {
            "id": "7",
            "links": [{...}]
          },
          "volume": {
            "size": 100
          },
          "ip": "10.0.0.3",
        }
      ]
    },
    ...
  ]
}

删除集群

请求

DELETE /v1.0/<tenant_id>/clusters/c33385b2-6c2a-491e-b44e-bcbb4af24136

响应

HTTP 202 (Empty Body)

公共 API 安全

Python API

CLI (python-troveclient)

与 Percona 集群相同的 CLI 将用于与 Galera 集群交互。主要功能如下访问:

创建集群

$ trove help cluster-create

usage: trove cluster-create <name> <datastore> <datastore_version>
                            [--instance <instance>]

Creates a new cluster.

Positional arguments:
  <name>                Name of the cluster.
  <datastore>           A datastore name or UUID.
  <datastore_version>   A datastore version name or UUID.

Optional arguments:

  --instance <flavor_id=flavor_id,volume=volume>
                        Create an instance for the cluster. Specify
                        multiple times to create multiple instances.

请求

$ trove cluster-create products mariadb "10" \
  --instance flavor_id=7,volume=2 \
  --instance flavor_id=7,volume=2 \
  --instance flavor_id=7,volume=2

响应

+-------------------+--------------------------------------+
| Property          | Value                                |
+-------------------+--------------------------------------+
| created           | 2015-12-14T01:46:51                  |
| datastore         | mariadb                              |
| datastore_version | 10                                   |
| id                | aa6ef0f5-dbef-48cd-8952-573ad881e717 |
| name              | products                             |
| task_description  | Building the initial cluster.        |
| task_name         | BUILDING                             |
| updated           | 2015-12-14T01:46:51                  |
+-------------------+--------------------------------------+

cluster-create 命令将创建一个具有相同实例的集群。Trove 将选择一个实例来启动 –wsrep-new-cluster 选项,然后按顺序启动其余实例。当所有实例都已启动并且数据库可用时,集群将被标记为 ACTIVE。

显示集群

$ trove help cluster-show

usage: trove cluster-show <cluster>

Shows details of a cluster.

Positional arguments:
  <cluster>  ID or name of the cluster.

请求

$ trove cluster-show aa6ef0f5-dbef-48cd-8952-573ad881e717

响应

+-------------------+--------------------------------------+
| Property          | Value                                |
+-------------------+--------------------------------------+
| created           | 2015-12-14T01:46:51                  |
| datastore         | mariadb                              |
| datastore_version | 10                                   |
| id                | aa6ef0f5-dbef-48cd-8952-573ad881e717 |
| ip                | 10.0.0.2, 10.0.0.1, 10.0.0.3         |
| name              | products                             |
| task_description  | No tasks for the cluster.            |
| task_name         | NONE                                 |
| updated           | 2015-12-14T01:59:33                  |
+-------------------+--------------------------------------+

显示集群实例

$ trove help cluster-instances

usage: trove cluster-instances <cluster>

Lists all instances of a cluster.

Positional arguments:
  <cluster>  ID or name of the cluster.

请求

$ trove cluster-instances aa6ef0f5-dbef-48cd-8952-573ad881e717

响应

+-------------------------------------+----------------+-----------+------+
| ID                                  | Name           | Flavor ID | Size |
+-------------------------------------+----------------+-----------+------+
| 45532fc4-661c-4030-8ca4-18f02a2b337 | products-1     | 7         |    2 |
| 7458a98d-6f89-4dfd-bb61-5cf1d65c121 | products-2     | 8         |    2 |
| 1557208f-5c23-4537-a9f2-52a9db38d3a | products-3     | 7         |    2 |
+-------------------------------------+----------------+-----------+------+

列出集群

$ trove help cluster-list

usage: trove cluster-list [--limit <limit>] [--marker <ID>]

Lists all the clusters.

Optional arguments:
  --limit <limit>  Limit the number of results displayed.
  --marker <ID>    Begin displaying the results for IDs greater than the
                   specified marker. When used with --limit, set this to
                   the last ID displayed in the previous run.

请求

$ trove cluster-list

响应

+--------+----------+-----------+-----------+----------+-----------+
| ID     | Name     | Datastore | DsVersion | IP       | Task Name |
+--------+----------+-----------+-----------+----------+-----------+
| uuid-1 | products | mariadb   | 10        | ip1      | NONE      |
| uuid-2 | items    | percona   | 5.5       | ip2, ip3 | BUILDING  |
+--------+----------+-----------+-----------+----------+-----------+

删除集群

$ trove help cluster-delete

usage: trove cluster-delete <cluster>

Deletes a cluster.

Positional arguments:
  <cluster>  ID of the cluster.

请求

$ trove cluster-delete aa6ef0f5-dbef-48cd-8952-573ad881e717

响应

(None)

内部 API

Guest Agent

备选方案

尚未定义。

Dashboard 影响 (UX)

必须将数据存储启用为集群数据存储。

实现

负责人

主要负责人
  • vkmc

  • tellesnobrega

里程碑

完成目标里程碑
  • Mitaka-3

工作项

  • Trove 集成更改以添加对 mariadb-galera-server 的支持

  • API 策略实现

  • 任务管理器策略实现

  • 客户机代理策略实现

  • 单元和集成测试

升级影响

为了启用 MariaDB 集群支持,需要在客户机实例上安装与默认值不同的软件包。可以通过更新数据存储版本上安装的软件包来解决此问题,但建议构建并加载具有所需软件包的新镜像。

依赖项

测试

  • 将添加单元测试以覆盖非平凡的代码路径。

  • 将添加集成测试以测试端到端集群功能。

文档影响

由于 Galera 集群的特性,API 响应看起来会不同。具体来说,视图将包含所有实例的 IP 地址。这将用于希望扩展读/写操作的用户。

参考资料

除了现有的 API 之外,还将有新的 API 来扩展/缩小集群,这些将在后续规范中处理。

Trove 不会监控集群实例的状态。如果集群中的实例与 PRIMARY 实例断开连接,用户有责任检测到这种情况并采取纠正措施。如果实例无法在 Incremental State Transfer (IST) 或 State Snapshot Transfer (SST) 发生时重新连接到集群,用户需要删除该实例并向集群添加新节点。这将以后由扩展/缩小集群功能替代。

如果 Nova 计算节点重新启动,节点将自动重新启动,并且只要节点能够确定 PRIMARY 组件可以正确恢复,集群将自动恢复。如果无法恢复 PRIMARY 组件,则需要操作员干预才能手动重新启动集群。

附录