Redis 集群

https://blueprints.launchpad.net/trove/+spec/redis-cluster

Redis 是一种 NoSQL 数据库,专为高性能缓存和键/值数据持久化而设计。本文档概述了为 Redis 实现集群的提案。

问题描述

为 Redis 实现集群。

提议的变更

Redis 集群功能将努力实现用户在 Trove 环境中实现 Redis 集群所需的最低功能。虽然 Trove 将提供功能以支持无法直接通过 Redis API 实现的操作,但尽可能将功能留给用户通过 Redis API 执行。做出此决定的原因是,通过 Web 界面提供所有必需的功能将非常困难,并且 Redis 用户将熟悉 Redis 命令集。

配置

以下配置值将在 Redis 配置组中实现

cfg.BoolOpt('cluster_support', default=True,
            help='Enable clusters to be created and managed.'),
cfg.StrOpt('api_strategy',
           default='trove.common.strategies.cluster.experimental.'
           'redis.api.RedisAPIStrategy',
           help='Class that implements datastore-specific API logic.'),
cfg.StrOpt('taskmanager_strategy',
           default='trove.common.strategies.cluster.experimental.redis.'
           'taskmanager.RedisTaskManagerStrategy',
           help='Class that implements datastore-specific task manager '
                'logic.'),
cfg.StrOpt('guestagent_strategy',
           default='trove.common.strategies.cluster.experimental.'
           'redis.guestagent.RedisGuestAgentStrategy',
           help='Class that implements datastore-specific Guest Agent API '
                'logic.'),

数据库

没有更改。

REST API

创建集群

cluster-create 命令将允许用户使用指定的 master 节点数量创建集群。数据槽将均匀地分配到创建的节点之间。

请求

POST /v1.0/<tenant_id>/clusters
{
  "cluster": {
    "name": "redis-clstr",
    "datastore": {
      "type": "redis",
      "version": "3.0"
    },
    "instances": [
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      },
    ]
  }
}

响应

{
  "cluster": {
    "id": "edaac9ca-b5e1-4028-adb7-fa7653e11224",
    "task": {
      "id": 2,
      "name": "BUILDING",
      "description": "Building the initial cluster."
    },
    "name": "redis-clstr",
    "created": "2015-01-29T20:19:23",
    "updated": "2015-01-29T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "redis",
      "version": "3.0"
    },
    "ip": [],
    "instances": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "name": "redis-clstr-member-1",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
        "name": "redis-clstr-member-2",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
      {
        "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
        "name": "redis-clstr-member-3",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "name": "redis-clstr-member-4",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
    ]
  }
}

HTTP 状态码

202 - Accepted.
400 - BadRequest. Server could not understand request.
403 - Forbidden. Local storage not specified in flavor ID: <ID>.
403 - Forbidden. A flavor is required for each instance in the cluster.
404 - Not Found. Flavor not found.

扩展集群

向集群添加节点。添加的节点将是空的 master 节点,并且不会分配任何槽位给它们。

请求

POST /v1.0/<tenant_id>/clusters/edaac9ca-b5e1-4028-adb7-fa7653e11224/action
{
    "grow": [
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      },
      {
        "flavorRef": "2",
        "volume": {
          "size": 2
        }
      }
    ]
}

响应

{
  "cluster": {
    "id": "edaac9ca-b5e1-4028-adb7-fa7653e11224",
    "task": {
      "id": 2,
      "name": "BUILDING",
      "description": "Building the initial cluster."
    },
    "name": "redis-clstr",
    "created": "2015-01-29T20:19:23",
    "updated": "2015-01-29T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "redis",
      "version": "3.0"
    },
    "ip": [],
    "instances": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "name": "redis-clstr-member-5",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
        "name": "redis-clstr-member-6",
        "status": "BUILD",
        "ip": [],
        "links": [{...}],
        "flavor": {
          "id": "2",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        }
      },
    ]
  }
}

HTTP 状态码

202 - Accepted.
400 - BadRequest. Server could not understand request.
403 - Forbidden. Local storage not specified in flavor ID: <ID>.
403 - Forbidden. A flavor is required for each instance in the cluster.
404 - Not Found. Flavor not found.

缩减集群

从集群中删除指定的节点。预计所有数据槽都已从节点中删除 - 否则 shrink 操作将失败。

请求

POST /v1.0/<tenant_id>/clusters/<cluster_id>/action
    "shrink": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
      },
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
      }
    ]
}

响应

N/A

HTTP 代码

202 - Accepted.
403 - Forbidden.  One or more nodes have data slots assigned.
404 - Not found.  Instance <id> does not exist.

显示集群

请求

GET /v1.0/<tenant_id>/clusters/edaac9ca-b5e1-4028-adb7-fa7653e11224

响应

{
  "cluster": {
    "id": "edaac9ca-b5e1-4028-adb7-fa7653e11224",
    "task": {
      "id": 1,
      "name": "NONE",
      "description": "No tasks for the cluster."
    },
    "name": "redis-clstr",
    "created": "2015-01-29T20:19:23",
    "updated": "2015-01-29T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "redis",
      "version": "3.0"
    },
    "ip": ["10.0.0.1", "10.0.0.2", "10.0.0.3", "10.0.0.4",],
    "instances": [
      {
        "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
        "name": "redis-clstr-member-1",
        "status": "ACTIVE",
        "ip": ["10.0.0.1"],
        "links": [{...}],
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        },
      }
      {
        "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
        "name": "redis-clstr-member-2",
        "status": "ACTIVE",
        "links": [{...}],
        "flavor": {
        "ip": ["10.0.0.2"],
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        },
      },
      {
        "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
        "name": "redis-clstr-member-3",
        "status": "BUILD",
        "ip": ["10.0.0.3"],
        "links": [{...}],
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        },
      },
      {
        "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
        "name": "redis-clstr-member-4",
        "status": "BUILD",
        "ip": ["10.0.0.4"],
        "links": [{...}],
        "flavor": {
          "id": "7",
          "links": [{...}]
        },
        "volume": {
          "size": 2
        },
      }
    ]
  }
}

HTTP 状态码

200 - OK.
404 - Not Found. Cluster not found.

显示实例

请求

GET /v1.0/<tenant_id>/clusters/edaac9ca-b5e1-4028-adb7-fa7653e11224/instances/416b0b16-ba55-4302-bbd3-ff566032e1c1

响应

{
  "instance": {
    "status": "ACTIVE",
    "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
    "cluster_id": "edaac9ca-b5e1-4028-adb7-fa7653e11224",
    "name": "redis-clstr-member-1",
    "created": "2015-01-29T20:19:23",
    "updated": "2015-01-29T20:19:23",
    "links": [{...}],
    "datastore": {
      "type": "redis",
      "version": "3.0"
    },
    "ip": ["10.0.0.1"],
    "flavor": {
      "id": "7",
      "links": [{...}],
    },
    "volume": {
      "size": 2,
      "used": 0.17
    }
  }
}

HTTP 状态码

200 - OK.
404 - Not Found. Cluster not found.
404 - Not Found. Instance not found.

列出集群

请求

GET /v1.0/<tenant_id>/clusters

响应

{
  "clusters": [
    {
      "id": "edaac9ca-b5e1-4028-adb7-fa7653e11224",
      "task": {
        "id": 1,
        "name": "NONE",
        "description": "No tasks for the cluster."
      },
      "name": "redis-clstr",
      "created": "2015-01-29T20:19:23",
      "updated": "2015-01-29T20:19:23",
      "links": [{...}],
      "datastore": {
        "type": "redis",
        "version": "3.0"
      },
      "instances": [
        {
          "id": "416b0b16-ba55-4302-bbd3-ff566032e1c1",
          "name": "redis-clstr-member-1",
          "links": [{...}],
        }
        {
          "id": "965ef811-7c1d-47fc-89f2-a89dfdd23ef2",
          "name": "redis-clstr-member-2",
          "links": [{...}],
        },
        {
          "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
          "name": "redis-clstr-member-3",
          "links": [{...}],
        },
        {
          "id": "3642f41c-e8ad-4164-a089-3891bf7f2d2b",
          "name": "redis-clstr-member-4",
          "links": [{...}],
        }
      ]
    },
    ...
  ]
}

HTTP 状态码

200 - OK.

删除集群

请求

DELETE /v1.0/<tenant_id>/clusters/<cluster_id>

响应

N/A

HTTP 代码

202 - Accepted.
404 - Not found

公共 API

没有公共 API 变更。

公共 API 安全

n/a

Python API

无 Python API 更改。

CLI (python-troveclient)

无 CLI 更改。

内部 API

预计不会对 guestagent api 进行任何更改,除了实现现有的 API 方法。

Guest Agent

以下方法将在 RedisGuestAgentAPI 中实现

def get_node_ip(self):
    LOG.debug("Retrieve ip info from node.")
    return self._call("get_node_ip",
                      guest_api.AGENT_HIGH_TIMEOUT, self.version_cap)

def get_node_id_for_removal(self):
    LOG.debug("Validating cluster node removal.")
    return self._call("get_node_id_for_removal",
                      guest_api.AGENT_HIGH_TIMEOUT, self.version_cap)

def remove_nodes(self, node_ids):
    LOG.debug("Removing nodes from cluster.")
    return self._call("remove_nodes", guest_api.AGENT_HIGH_TIMEOUT,
                      self.version_cap, node_ids=node_ids)

def cluster_meet(self, ip, port):
    LOG.debug("Joining node to cluster.")
    return self._call("cluster_meet", guest_api.AGENT_HIGH_TIMEOUT,
                      self.version_cap, ip=ip, port=port)

def cluster_addslots(self, first_slot, last_slot):
    LOG.debug("Adding slots %s-%s to cluster.", first_slot, last_slot)
    return self._call("cluster_addslots",
                      guest_api.AGENT_HIGH_TIMEOUT, self.version_cap,
                      first_slot=first_slot, last_slot=last_slot)

def cluster_complete(self):
    LOG.debug("Notifying cluster install completion.")
    return self._call("cluster_complete", guest_api.AGENT_HIGH_TIMEOUT,
                      self.version_cap)

备选方案

n/a

实现

负责人

主要负责人

vgnbkr

里程碑

完成目标里程碑

Liberty-3

工作项

  • 为 Redis 实现集群

为 Redis 实现新的 Taskmanager 集群策略,实现 python API 和 shell 用于 shrink/grow(这可能已经通过 cluster-scaling bp 实现完成),如果缺少缩放实现,则将 grow/shrink 添加到集群策略中,实现 guest agent 支持加入/离开集群,根据需要实现单元测试,如果那时已经确定了执行此操作的机制,则实现集成测试

升级影响

由于这是一个新的实现,因此预计不会产生升级影响。

依赖项

测试

  • MongoDB 和 Cassandra 的集群集成测试仍在进行中。预计 Redis 将实现/运行类似的集成测试。

文档影响

  • 需要更新 Redis 的数据存储文档以反映集群支持。