实现 Cassandra 集群配置¶
实现 Cassandra 集群配置。
Launchpad 蓝图:https://blueprints.launchpad.net/trove/+spec/cassandra-cluster
问题描述¶
Cassandra 本质上是一个分布式数据库,由“平等”的节点组成。“平等”意味着集群中的任何节点都可以接收和处理请求。它不像某些其他数据库(MongoDB)那样有查询路由器或配置服务器。它对单个节点的硬件配置没有限制(即,节点可以具有不同的规格)。
当一个节点接收到请求(它成为该请求的协调者)时,它使用分区键(主键的一部分)来计算哪些节点(副本)包含请求的数据(数据是根据分区键的哈希值分布的)。然后,它将请求传递给副本并收集结果。它的工作是组合响应并发送给客户端。数据库中存储的每个字段(值)都伴随着时间戳(或已删除数据的情况下的墓碑标记)。协调者使用这些时间戳将数据的最新视图编译成结果集。因此,节点的时钟同步至关重要。
Cassandra 的设计使其能够在任何给定节点发生故障时仍然可用。这是通过放宽一致性要求来实现的。Cassandra 提供所谓的最终一致性。容错性和一致性都可以进行调整。容错性可以在键空间级别配置(复制因子)。一致性可以在全局级别或每个请求级别控制(一致性级别)。
复制因子确定将持有给定键空间数据的副本数量。Cassandra 可以将副本分组到“机架”中。 “机架”是一组共享共同故障点的节点(副本)。Cassandra 始终尝试跨多个机架分发数据,以便一个机架的故障不会使数据无法访问。
- 示例
假设我们有一个三节点系统(节点 #1、#2 和 #3)和一个复制因子 (RC) 为 2 的键空间。现在假设用户发出一个插入语句,该语句落在节点 #3(协调者)上。协调者使用分区键来确定数据属于哪些节点,假设是 #1。因此,它将数据存储在节点 #1 上,并且因为 RC=2,也在下一个节点 #2 上。现在假设节点 #1 和 #2 共享一个共同的故障点,并被放置在同一个机架中。协调者因此将第二个副本存储在下一个可用不在该机架中的节点上 - 即 #3(自身)。
Cassandra 还具有数据中心的概念。数据中心通常是地理上远离的节点组,它们拥有自己的一组机架。它们的行为非常类似于独立的集群。
- 示例
假设上面的示例发生在数据中心 DC1 中,但所涉及的键空间也配置为复制到 DC2(DC1 的复制因子不必与 DC2 相同)。协调者然后向 DC2 中的一个节点发送异步请求,然后该节点以相同的方式处理它。
请注意,对于特定的数据中心,键空间具有复制因子 RC=0 并不罕见 - 一个原因是法律法规要求某些数据存储在特定的地理区域内。
每个节点都配置了一个集群名称。单个集群中的所有节点必须共享相同的集群名称。集群中的各个节点交换所谓的消息 - 关于集群拓扑的基本信息。新添加的节点以相同的方式了解所有其他节点。只需要提供一组初始消息种子(来自集群内的已激活节点)。建议种子节点来自所有 DC 的多个机架(以防其中一个宕机)。
所有这些配置都存储在标准的 ‘cassandra.yaml’ 文件中,该文件已经由客户代理管理2
节点成员资格(机架/dc)存储在与主配置文件相同的目录中的 ‘cassandra-rackdc.properties’ 文件中。
提议的变更¶
本规范提出了以下与集群相关的操作
创建
扩展
缩减
删除
只有机架支持将作为此补丁的一部分实现。所有节点都将被放置在单个 DC(‘dc1’)中。机架将映射到客户端传递的可用区 (AZ)。如果没有指定 AZ,则节点将被放置在单个默认机架(‘rack1’)中。
创建集群¶
配置请求数量的实例。
等待实例变为活动状态。
选择种子节点。它们应包括每个数据中心和机架中的至少一个节点。
使用种子列表配置每个集群节点。请注意,在新的空集群的初始启动期间,种子节点必须禁用自动引导。配置完所有节点后,一次启动一个种子节点(此时禁用自动引导),然后启动其余节点(自动引导可以启用,因为种子节点已经在运行)。
通过第一个节点创建数据库中的 (‘os_admin’) 用户。其余节点将自动复制数据库中的更改。只需更新其他节点上的本地身份验证文件。
扩展集群¶
配置请求数量的实例。
等待实例变为活动状态。
根据更新的集群几何形状重新计算种子节点,并使用更新的种子列表配置每个集群节点。
从先前存在的节点检索超级用户凭据,并将其保存到新添加的节点上。
首先一次启动一个添加的节点中的任何种子,然后启动其余节点。
在先前存在的每个节点上运行 nodetool cleanup,以删除不再属于这些节点的键(它们现在属于一些添加的节点)。
首先将节点置于 BLOCKED 状态,然后启动清理。清理完成后恢复节点的状态。任务管理器可以轮询节点状态更改,并在准备好时继续到下一个节点。
该操作必须在所有先前存在的节点上按顺序运行,并且可能需要花费大量时间。清理通常可以安全地推迟到低使用率时段。
缩减集群¶
如果删除了任何现有的种子节点,则根据更新的集群几何形状重新计算种子节点。
如果需要,更新剩余节点上的种子列表。
在删除的节点上运行 nodetool decommission。Cassandra 将从停用节点流式传输数据到剩余节点。完成数据传输后关闭数据库。
等待删除的节点进入 SHUTDOWN 状态。
删除停用实例。
配置¶
将在 Cassandra 配置组中实现以下配置值
cfg.BoolOpt('cluster_support', default=True,
help='Enable clusters to be created and managed.'),
cfg.StrOpt('api_strategy',
default='trove.common.strategies.cluster.experimental.'
'cassandra.api.CassandraAPIStrategy',
help='Class that implements datastore-specific API logic.'),
cfg.StrOpt('taskmanager_strategy',
default='trove.common.strategies.cluster.experimental'
'.cassandra.taskmanager.CassandraTaskManagerStrategy',
help='Class that implements datastore-specific task manager '
'logic.'),
cfg.StrOpt('guestagent_strategy',
default='trove.common.strategies.cluster.experimental'
'.cassandra.guestagent.CassandraGuestAgentStrategy',
help='Class that implements datastore-specific Guest Agent API '
'logic.'),
数据库¶
无
公共 API¶
无
公共 API 安全¶
无
Python API¶
无
CLI (python-troveclient)¶
无
内部 API¶
将在 CassandraGuestAgentAPI 中实现以下方法
def get_data_center(self):
LOG.debug("Retrieving the data center for node: %s" % self.id)
return self._call("get_data_center", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def get_rack(self):
LOG.debug("Retrieving the rack for node: %s" % self.id)
return self._call("get_rack", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def set_seeds(self, seeds):
LOG.debug("Configuring the gossip seeds for node: %s" % self.id)
return self._call("set_seeds", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap, seeds=seeds)
def get_seeds(self):
LOG.debug("Retrieving the gossip seeds for node: %s" % self.id)
return self._call("get_seeds", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def set_auto_bootstrap(self, enabled):
LOG.debug("Setting the auto-bootstrap to '%s' for node: %s"
% (enabled, self.id))
return self._call("set_auto_bootstrap", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap, enabled=enabled)
def cluster_complete(self):
LOG.debug("Sending a setup completion notification for node: %s"
% self.id)
return self._call("cluster_complete", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def node_cleanup_begin(self):
LOG.debug("Signaling the node to prepare for cleanup: %s" % self.id)
return self._call("node_cleanup_begin", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def node_cleanup(self):
LOG.debug("Running cleanup on node: %s" % self.id)
return self._cast('node_cleanup', self.version_cap)
def node_decommission(self):
LOG.debug("Decommission node: %s" % self.id)
return self._cast("node_decommission", self.version_cap)
def cluster_secure(self, password):
LOG.debug("Securing the cluster via node: %s" % self.id)
return self._call(
"cluster_secure", guest_api.AGENT_HIGH_TIMEOUT,
self.version_cap, password=password)
def get_admin_credentials(self):
LOG.debug("Retrieving the admin credentials from node: %s" % self.id)
return self._call("get_admin_credentials", guest_api.AGENT_LOW_TIMEOUT,
self.version_cap)
def store_admin_credentials(self, admin_credentials):
LOG.debug("Storing the admin credentials on node: %s" % self.id)
return self._call("store_admin_credentials",
guest_api.AGENT_LOW_TIMEOUT, self.version_cap,
admin_credentials=admin_credentials)
Guest Agent¶
除了上述方法之外,还将实现写入 ‘cassandra-rackdc.properties’ 文件的功能。
节点成员资格(机架/dc)将包含在传递到 prepare 方法的 cluster_info 字典中。
备选方案¶
无
Dashboard 影响 (UX)¶
需要将 Cassandra 启用为集群数据存储。
升级影响¶
无
依赖项¶
此实现严重依赖于以下工作
测试¶
将根据需要添加管理器单元测试。
场景测试已经涵盖了已实现的功能。
文档影响¶
需要更新 Cassandra 数据存储文档以反映集群支持。
参考资料¶
- 1
Cassandra 用户/数据库实现审查:https://review.openstack.org/#/c/206739/
- 2(1,2)
Cassandra 配置审查:https://review.openstack.org/#/c/206740/
- 3
Cassandra 备份/恢复审查:https://review.openstack.org/#/c/206751/
附录¶
无