我们经常遇到 Apache Cassandra 数据库以及在基于 Kubernetes 的基础设施中操作它的需要。 在本材料中,我们将分享将 Cassandra 迁移到 K8s 的必要步骤、标准和现有解决方案(包括运营商概述)的愿景。
“谁能统治女人,谁就能统治国家”
卡桑德拉是谁? 它是一个分布式存储系统,旨在管理大量数据,同时确保高可用性,无单点故障。 该项目几乎不需要长篇大论的介绍,因此我将仅给出与特定文章上下文相关的 Cassandra 的主要功能:
- Cassandra 是用 Java 编写的。
- Cassandra 拓扑包括几个级别:
- 节点 - 一个已部署的 Cassandra 实例;
- Rack 是一组 Cassandra 实例,通过某种特征联合起来,位于同一个数据中心;
- 数据中心 - 位于一个数据中心的所有 Cassandra 实例组的集合;
- 集群是所有数据中心的集合。
- Cassandra 使用 IP 地址来标识节点。
- 为了加速写入和读取操作,Cassandra 将一些数据存储在 RAM 中。
现在 - 实际可能迁移到 Kubernetes。
转让清单
谈到Cassandra向Kubernetes的迁移,我们希望通过迁移,管理起来会更加方便。 为此需要什么,什么会对此有帮助?
1. 数据存储
正如已经澄清的那样,Cassanda 将部分数据存储在 RAM 中 - 内存表。 但数据的另一部分以以下形式保存到磁盘: SS表。 一个实体被添加到此数据中 提交日志 — 所有交易的记录,也保存到磁盘上。
在 Cassandra 中编写事务图
在 Kubernetes 中,我们可以使用 PersistentVolume 来存储数据。 得益于经过验证的机制,在 Kubernetes 中处理数据每年都变得更加容易。
我们将为每个 Cassandra pod 分配我们自己的 PersistentVolume
值得注意的是,Cassandra 本身就意味着数据复制,为此提供了内置机制。 因此,如果您要从大量节点构建 Cassandra 集群,则无需使用 Ceph 或 GlusterFS 等分布式系统进行数据存储。 在这种情况下,使用以下方法将数据存储在主机磁盘上是合乎逻辑的: hostPath
.
另一个问题是您是否想为每个功能分支的开发人员创建一个单独的环境。 在这种情况下,正确的方法是建立一个 Cassandra 节点并将数据存储在分布式存储中,即提到的 Ceph 和 GlusterFS 将是您的选择。 那么开发人员就能确保即使其中一个 Kubernetes 集群节点丢失,他也不会丢失测试数据。
2. 监控
在 Kubernetes 中实现监控几乎毫无争议的选择是 Prometheus (我们在
Grafana for Cassandra 中图表的外观示例
我们为自己选择第一个,因为:
- JMX Exporter 正在不断成长和发展,而 Cassandra Exporter 却一直未能获得足够的社区支持。 Cassandra Exporter 仍然不支持大多数版本的 Cassandra。
- 您可以通过添加标志将其作为 javaagent 运行
-javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180
. - 有一个适合他的
足够的仪表板 ,与 Cassandra Exporter 不兼容。
3. 选择 Kubernetes 原语
根据上面的 Cassandra 集群结构,我们尝试将其中描述的所有内容翻译成 Kubernetes 术语:
- Cassandra 节点 → Pod
- Cassandra Rack → StatefulSet
- Cassandra 数据中心 → StatefulSets 的池
- 卡桑德拉集群 → ???
事实证明,缺少一些额外的实体来立即管理整个 Cassandra 集群。 但如果有些东西不存在,我们可以创造它! Kubernetes 有一个为此目的定义自己的资源的机制 -
声明日志和警报的附加资源
但自定义资源本身并没有什么意义:毕竟它需要 调节器。 您可能需要寻求帮助
4. pod 的识别
在上一段中,我们一致认为 XNUMX 个 Cassandra 节点相当于 Kubernetes 中的 XNUMX 个 Pod。 但 Pod 的 IP 地址每次都会不同。 而Cassandra中节点的标识是基于IP地址的……事实证明,每次移除一个pod后,Cassandra集群都会添加一个新的节点。
有一条出路,但不仅仅是一条:
- 我们可以通过主机标识符(唯一标识 Cassandra 实例的 UUID)或 IP 地址来保存记录,并将其全部存储在某些结构/表中。 该方法有两个主要缺点:
- 如果两个节点同时失败,则存在竞争条件发生的风险。 崛起后,Cassandra节点会同时从表中请求IP地址,竞争同一资源。
- 如果 Cassandra 节点丢失了数据,我们将无法再识别它。
- 第二个解决方案看起来像是一个小技巧,但尽管如此:我们可以为每个 Cassandra 节点创建一个带有 ClusterIP 的服务。 此实现的问题:
- 如果 Cassandra 集群中有很多节点,我们就必须创建很多服务。
- ClusterIP 功能是通过 iptables 实现的。 如果 Cassandra 集群有许多(1000 个……甚至 100 个?)节点,这可能会成为问题。 虽然
基于IPVS的均衡 可以解决这个问题。
- 第三种解决方案是通过启用以下设置,为 Cassandra 节点使用节点网络,而不是专用的 Pod 网络
hostNetwork: true
。 这种方法有一定的局限性:- 更换单位。 新节点必须与前一个节点具有相同的IP地址(在AWS、GCP等云中这几乎是不可能做到的);
- 使用集群节点网络,我们开始争夺网络资源。 因此,在一个集群节点上放置多个带有 Cassandra 的 Pod 将会出现问题。
5. 备份
我们希望按计划保存单个 Cassandra 节点数据的完整版本。 Kubernetes 提供了一个方便的功能
让我提醒您,Cassandra 将一些数据存储在内存中。 要进行完整备份,您需要内存中的数据(内存表)移动到磁盘(SS表)。 此时,Cassandra 节点停止接受连接,从集群中完全关闭。
此后,备份将被删除(快照)并且该方案被保存(键空间)。 然后事实证明,仅仅备份并不能给我们带来任何东西:我们需要保存 Cassandra 节点负责的数据标识符 - 这些是特殊的令牌。
分配令牌以确定 Cassandra 节点负责哪些数据
在 Kubernetes 中从 Google 获取 Cassandra 备份的示例脚本可以在以下位置找到:
set -eu
if [[ -z "$1" ]]; then
info "Please provide a keyspace"
exit 1
fi
KEYSPACE="$1"
result=$(nodetool snapshot "${KEYSPACE}")
if [[ $? -ne 0 ]]; then
echo "Error while making snapshot"
exit 1
fi
timestamp=$(echo "$result" | awk '/Snapshot directory: / { print $3 }')
mkdir -p /tmp/backup
for path in $(find "/var/lib/cassandra/data/${KEYSPACE}" -name $timestamp); do
table=$(echo "${path}" | awk -F "[/-]" '{print $7}')
mkdir /tmp/backup/$table
mv $path /tmp/backup/$table
done
tar -zcf /tmp/backup.tar.gz -C /tmp/backup .
nodetool clearsnapshot "${KEYSPACE}"
用于从一个 Cassandra 节点进行备份的 bash 脚本示例
Kubernetes 中 Cassandra 的现成解决方案
目前在 Kubernetes 中部署 Cassandra 所用的是什么?其中哪一个最适合给定的要求?
1.基于StatefulSet或Helm图表的解决方案
使用基本的 StatefulSets 函数来运行 Cassandra 集群是一个不错的选择。 使用 Helm 图表和 Go 模板,您可以为用户提供灵活的界面来部署 Cassandra。
这通常工作正常......直到发生意外情况,例如节点故障。 标准 Kubernetes 工具根本无法考虑上述所有功能。 此外,这种方法对于更复杂用途的扩展程度非常有限:节点更换、备份、恢复、监控等。
代表:
两个图表都同样好,但都存在上述问题。
2、基于Kubernetes Operator的解决方案
这些选项更有趣,因为它们为管理集群提供了充足的机会。 对于设计 Cassandra 操作符,就像任何其他数据库一样,一个好的模式看起来像 Sidecar <-> Controller <-> CRD:
精心设计的 Cassandra 运算符中的节点管理方案
让我们看看现有的运营商。
1.来自 instaclustr 的 Cassandra 运算符
-
GitHub上 - 准备状态:阿尔法
- 许可证:Apache 2.0
- 实现语言:Java
这确实是一个非常有前途且正在积极开发的项目,来自一家提供托管 Cassandra 部署的公司。 如上所述,它使用通过 HTTP 接受命令的 sidecar 容器。 它是用 Java 编写的,有时缺乏 client-go 库的更高级功能。 此外,运营商不支持一个数据中心使用不同的机架。
但该操作员具有诸如支持监控、使用 CRD 进行高级集群管理,甚至提供备份文档等优势。
2.Jetstack 的导航器
-
GitHub上 - 准备状态:阿尔法
- 许可证:Apache 2.0
- 实现于:Golang
旨在部署数据库即服务的声明。 目前支持两种数据库:Elasticsearch 和 Cassandra。 它有一些有趣的解决方案,例如通过 RBAC 进行数据库访问控制(为此它有自己独立的 navigator-apiserver)。 这是一个有趣的项目,值得仔细研究,但最后一次提交是在一年半前,这显然降低了它的潜力。
3. Cassandra 运算符,作者:vgkowski
-
GitHub上 - 准备状态:阿尔法
- 许可证:Apache 2.0
- 实现于:Golang
他们并没有“认真”地考虑它,因为最后一次提交到存储库已经是一年多前了。 Operator 开发被放弃:据报道支持的 Kubernetes 最新版本是 1.9。
4. Rook 的 Cassandra 运算符
-
GitHub上 - 准备状态:阿尔法
- 许可证:Apache 2.0
- 实现于:Golang
运营商的发展进展没有我们希望的那么快。 它具有用于集群管理的深思熟虑的 CRD 结构,解决了使用 ClusterIP 服务识别节点的问题(相同的“hack”)……但目前仅此而已。 目前没有开箱即用的监控或备份(顺便说一句,我们是为了监控
注意:我们在一个项目中使用了这个运算符,并进行了一些小的修改。 在整个运行期间(运行约 4 个月),操作员的工作没有发现任何问题。
5.来自Orange的CassKop
-
GitHub上 - 准备状态:阿尔法
- 许可证:Apache 2.0
- 实现于:Golang
名单上最年轻的操作员:第一次提交于 23 年 2019 月 XNUMX 日进行。 现在它的武器库中已经包含了我们列表中的大量功能,更多详细信息可以在项目存储库中找到。 该operator是在流行的operator-sdk的基础上构建的。 支持开箱即用的监控。 与其他操作符的主要区别在于使用
发现
将 Cassandra 移植到 Kubernetes 的方法和可能选项的数量不言而喻:这个主题很受欢迎。
在此阶段,您可以尝试上述任何一种方法,但后果自负:没有开发人员保证其解决方案在生产环境中 100% 运行。 但许多产品看起来已经有望在开发平台中尝试使用。
我想以后船上这个女人一定会派上用场的!
PS
另请阅读我们的博客:
- «
MongoDB 无缝迁移到 Kubernetes “; - «
RabbitMQ 无缝迁移到 Kubernetes “; - «
数据库和 Kubernetes(评论和视频报告) “; - «
K8s 提示和技巧:加快大型数据库的引导速度 “。
来源: habr.com