Apache Cassandra 是一个分布式 NoSQL 数据库,在开发者社区中享有广泛的流行度。从 Ably 到 Yelp,Cassandra 通常被部署,因为它能够快速处理 PB 级数据上的查询,并扩展到数百或数千个节点。Cassandra 可以相对轻松地部署到任何环境中,它可以无缝地向上和向外扩展,并且在分布式模式下运行良好。它在存储数据方面也很灵活,可以处理高容量而不会影响性能和速度。它是开源的,因此当需要发布修复程序时,迭代周期很快,而 Cassandra 查询语言 (CQL) 对于任何使用过 SQL 语法的人来说都很容易学习。
Cassandra 通常用于写入密集型数据模型,例如指标/时间序列数据、历史浏览页面、出租车跟踪等。在使用 Cassandra 时,人们最重视的是拥有适合用例的正确数据模型。当然,还要确保正确调整 JVM,以便获得愉快的 Cassandra 体验。
Cassandra 有几种不同的版本
- Apache 版本是 Cassandra 的原始开源版本,由 Meta/Facebook 开发。它包含运行 Cassandra 所需的所有核心功能,但支持是基于社区的。您必须熟悉命令行工具才能管理和操作集群。
- Datastax 版本的 Cassandra 构建于开源版本之上,但侧重于企业安全性和可支持性。例如,它提供的一个很酷的功能是 OpsCenter,这是一个基于浏览器的控制台 UI,显示集群的状态,并可用于执行操作任务。
Cassandra 有多种部署方式:裸机、虚拟机、容器等。今天,我们将借助 K8ssandra 将其部署到 Kubernetes 集群中。这将为我们的 Cassandra 集群设置所有必要的脚手架,使其能够立即启动并运行。
无论您使用哪种方法部署 Cassandra,将其与云原生 对象存储 配对都是有意义的,以便充分利用它。MinIO 是 Cassandra/K8ssandra 的完美补充,因为它具有业界领先的性能和可扩展性。MinIO 的可扩展性和高性能相结合,使每个数据密集型工作负载(不仅仅是 Cassandra)都能轻松实现。MinIO 能够提供强大的性能 - 最近的基准测试 在仅使用 32 个现成的 NVMe SSD 节点的情况下,GET 操作的吞吐量达到 325 GiB/s(349 GB/s),PUT 操作的吞吐量达到 165 GiB/s(177 GB/s)。
MinIO 旨在成为 Kubernetes 原生 和云原生,并能够从 TB 到 EB 及更高水平无缝扩展。MinIO 租户在其自己的命名空间中完全相互隔离。通过遵循 Kubernetes 插件和操作符范例,MinIO 可以无缝地融入现有的 DevOps 实践和工具链,从而可以自动化 Cassandra 备份操作。MinIO 为 Cassandra 备份提供了安全的家园。写入 MinIO 的数据是 不可变的、版本化的 并受 擦除编码 保护。让我们看看如何快速备份和恢复数据以最大程度地减少 MinIO 的停机时间。

先决条件
在开始之前,您需要为我们的安装准备一些先决条件。
- Helm
- Kubernetes 集群(Minikube、Kind 等)
在本指南中,我们将使用 Minikube 作为我们选择的 Kubernetes 集群,但任何正确配置的 Kubernetes 集群都可以使用。
Cassandra
我们可以通过多种方式安装 Apache Cassandra。在本例中,我们将使用 K8ssandra 以半自动方式部署 Cassandra。
配置
我们将部署一个简单的 Cassandra 集群,其规格如下,将此 yaml 保存为 k8ssandra.yaml
。
cassandra: version: "3.11.10" cassandraLibDirVolume: storageClass: local-path size: 5Gi allowMultipleNodesPerWorker: true heap: size: 1G newGenSize: 1G resources: requests: cpu: 1000m memory: 2Gi limits: cpu: 1000m memory: 2Gi datacenters: - name: dc1 size: 1 racks: - name: default kube-prometheus-stack: grafana: adminUser: admin adminPassword: admin123 stargate: enabled: true replicas: 1 heapMB: 256 cpuReqMillicores: 200 cpuLimMillicores: 1000 medusa: enabled: true storage: s3_compatible storage_properties: host: minio port: 9000 secure: "False" bucketName: k8ssandra-medusa storageSecret: medusa-bucket-key |
我们不会详细介绍整个规格,但将在下面介绍一些关键组件
存储类
您可以使用几种不同的 存储类,但主要要求是 VOLUMEBINDINGMODE
应为 WaitForFirstConsumer
。
默认存储类模式不受支持,因此让我们创建一个 rancher local-path
存储类。
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE standard (default) k8s.io/minikube-hostpath Delete Immediate false 4m33s |
现在您应该会看到第二个具有正确配置的存储类
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE local-path rancher.io/local-path Delete WaitForFirstConsumer false 20s standard (default) k8s.io/minikube-hostpath Delete Immediate false 6m30s |
Medusa
Medusa 是 Apache Cassandra 生态系统的一个组件。其核心功能是编排 Cassandra 集群的备份和恢复。
我们尤其关注以下字段:
host
port
storageSecret
bucketName
这些字段允许您连接到 MinIO 以执行备份和恢复操作。
存储密钥 (Storage Secret)
存储密钥是一个 Kubernetes 密钥 (Secret),我们将使用它来创建连接到 MinIO 的凭据。将以下内容放入名为 minio-medusa-secret.yaml
的文件中:
apiVersion: v1 kind: Secret metadata: name: medusa-bucket-key type: Opaque stringData: medusa_s3_credentials: |- [default] aws_access_key_id = miniok8ssandra_key aws_secret_access_key = miniok8ssandra_secret |
metadata.name
必须与 k8ssandra.yaml
文件中 storageSecret
字段匹配。aws_access_key_id
和 aws_secret_access_key
必须分别与 MinIO 的 accessKey
和 secretKey
匹配。
在集群中应用 minio-medusa-secret.yaml
资源。
kubectl apply -f minio-medusa-secret.yaml
secret/medusa-bucket-key 创建成功 |
- 使用以下命令验证:
kubectl get secret medusa-bucket-key
名称 类型 数据 年龄 medusa-bucket-key 不透明 1 12秒 |
安装
添加 K8ssandra Helm 仓库并更新 Helm
- 添加仓库:
helm repo add k8ssandra https://helm.k8ssandra.io/stable
- 使用以下命令验证:
helm repo list
- 运行
helm repo update
获取最新更新
使用 K8ssandra 安装 Apache Cassandra,确保 secret medusa-bucket-key 存在。
helm install -f k8ssandra.yaml k8ssandra k8ssandra/k8ssandra
以上命令将执行以下操作:
- 创建一个名为
k8ssandra
的 Cassandra 集群。 - 将集群部署到 Kubernetes 的
default
命名空间。
等待至少 5 分钟,直到集群完全上线。如果运行 kubectl get pods
,您应该看到所有 Pod 都处于 Running 状态。
NAME READY STATUS RESTARTS AGE k8ssandra-cass-operator-699b8c4cbc-ptbtk 1/1 Running 0 3m35s k8ssandra-dc1-default-sts-0 2/3 CrashLoopBackOff 4 (14s ago) 3m23s k8ssandra-dc1-stargate-556ddcc5-8rb7v 0/1 Init:0/1 0 3m34s k8ssandra-grafana-795f9865fc-7v9lq 2/2 Running 0 3m35s k8ssandra-kube-prometheus-operator-9544bb7bf-b8m6k 1/1 Running 0 3m35s k8ssandra-medusa-operator-66d8969ff9-knkd6 1/1 Running 0 3m35s k8ssandra-reaper-operator-77554f9458-zd5mh 1/1 Running 0 3m35s prometheus-k8ssandra-kube-prometheus-prometheus-0 2/2 Running 0 3m31s |
让我们借此机会探索调试方法。这超出了入门教程的范围,但在长期运行中将有所帮助。
调试
让我们描述 Pod 以查看它卡在哪里
kubectl describe pod k8ssandra-dc1-default-sts-0
medusa …… 状态: 等待 原因: CrashLoopBackOff 最后状态: 终止 原因: 错误 退出代码: 1 …… |
从以上描述输出中可以看到,medusa
容器存在问题,让我们查看其 日志
以确定问题所在
kubectl logs k8ssandra-dc1-default-sts-0 -c medusa
[2022-07-06 14:06:18,778] DEBUG: 启动 新的 HTTP 连接 (1): minio:9000 ... socket.gaierror: [Errno -2] 名称 或 服务 未知 ... |
啊哈!看起来连接到 MinIO 服务时出现问题。这很有道理,因为我们集群中没有运行名为 minio
的服务。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE k8ssandra-dc1-additional-seed-service ClusterIP None <none> <none> 3h26m k8ssandra-dc1-all-pods-service ClusterIP None <none> 9042/TCP,8080/TCP,9103/TCP 3h26m k8ssandra-dc1-service ClusterIP None <none> 9042/TCP,9142/TCP,8080/TCP,9103/TCP,9160/TCP 3h26m k8ssandra-dc1-stargate-service ClusterIP 10.110.1.67 <none> 8080/TCP,8081/TCP,8082/TCP,8084/TCP,8085/TCP,9042/TCP 3h27m k8ssandra-grafana ClusterIP 10.100.244.68 <none> 80/TCP 3h27m k8ssandra-kube-prometheus-operator ClusterIP 10.96.25.118 <none> 443/TCP 3h27m k8ssandra-kube-prometheus-prometheus ClusterIP 10.104.105.81 <none> 9090/TCP 3h27m k8ssandra-reaper-reaper-service ClusterIP 10.98.35.86 <none> 8080/TCP 3h26m k8ssandra-seed-service ClusterIP None <none> <none> 3h26m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5h3m prometheus-operated ClusterIP None <none> 9090/TCP 3h26m |
提示:如果您在备份/恢复方面遇到任何问题,并且需要其他调试信息,则 medusa 容器是您找到大多数详细信息的地方。
MinIO
正如我们发现的那样,要使 medusa 容器启动,我们首先需要使 MinIO 在线。我们也将使用 Helm 来设置 MinIO。
安装
添加 MinIO Helm 仓库并更新 Helm
- 添加仓库:
helm repo add minio https://helm.min.io/
- 使用以下命令验证:
helm repo list
- 运行
helm repo update
获取最新更新
使用 helm 命令安装 MinIO
helm install --set accessKey=miniok8ssandra_key,secretKey=miniok8ssandra_secret,defaultBucket.enabled=true,defaultBucket.name=k8ssandra-medusa minio minio/minio
accessKey
和 secretKey
必须分别与 minio-medusa-secret.yaml
中的 aws_access_key_id
和 aws_secret_access_key
匹配。defaultBucket.name
必须与 k8ssandra.yaml
中的 bucketName
匹配。
以上命令将执行以下操作:
- 创建一个名为
minio
的部署和服务。 - 将 MinIO 部署到 Kubernetes 的
default
命名空间。
如果等待几分钟并运行 kubectl get pods,您应该看到所有 Pod 都处于 Running
状态。但是,如果您像我一样不耐烦,并且希望尽快看到 medusa 容器启动,只需删除 k8ssandra-dc1-default-sts-0 pod
。
kubectl delete pod k8ssandra-dc1-default-sts-0
大约一分钟后,您应该看到所有 Pod 都处于 Running 状态
kubectl get po NAME READY STATUS RESTARTS AGE k8ssandra-cass-operator-699b8c4cbc-s7qqz 1/1 Running 0 3h46m k8ssandra-dc1-default-sts-0 3/3 Running 0 3h34m k8ssandra-dc1-stargate-556ddcc5-mz2fp 1/1 Running 0 3h46m k8ssandra-grafana-795f9865fc-95pwc 2/2 Running 0 3h46m k8ssandra-kube-prometheus-operator-9544bb7bf-f6nxb 1/1 Running 0 3h46m k8ssandra-medusa-operator-66d8969ff9-svbbw 1/1 Running 0 3h46m k8ssandra-reaper-679fd4fc7d-lbjhw 1/1 Running 0 3h33m k8ssandra-reaper-operator-77554f9458-zkdcl 1/1 Running 0 3h46m minio-5fb8f49576-l2s7l 1/1 Running 0 3h37m prometheus-k8ssandra-kube-prometheus-prometheus-0 2/2 Running 0 3h46m |
验证 Bucket
我们如何检查 Medusa 是否能够连接到 MinIO?嗯,有一个非常简单的方法。如果我们转发 MinIO 控制台的端口并登录,我们应该看到一个名为 k8ssandra-medusa
的 Bucket。
kubectl port-forward service/minio 39000:9000
- 使用浏览器访问 `http://localhost:39000`。
- 使用 `accessKey` 作为用户名,`secretKey` 作为密码进行登录。
- 如果可以看到存储桶,则表示 Medusa 已成功连接到 MinIO。

备份
为了测试备份,需要满足一些前提条件。
- cqlsh:用于与 Cassandra 集群交互的工具。
- 测试数据,我们可以对其进行填充、删除和恢复以展示功能。
安装 cqlsh
为了与 Cassandra 交互,我们将使用名为 cqlsh 的工具。
使用 pip 安装 cqlsh
获取 Cassandra 超级用户凭据
kubectl get secret k8ssandra-superuser -o jsonpath="{.data.username}" | base64 --decode ; echo
kubectl get secret k8ssandra-superuser -o jsonpath="{.data.password}" | base64 --decode ; echo
打开端口转发,以便 cqlsh 访问我们的 Cassandra 集群
kubectl port-forward svc/k8ssandra-dc1-stargate-service 8080 8081 8082 9042
登录 cqlsh
填充数据
登录后,您应该会看到如下提示
将以下代码块复制粘贴到 REPL 中并运行它
CREATE KEYSPACE medusa_test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; USE medusa_test; CREATE TABLE users (email text primary key, name text, state text); insert into users (email, name, state) values ('alice@example.com', 'Alice Smith', 'TX'); insert into users (email, name, state) values ('bob@example.com', 'Bob Jones', 'VA'); insert into users (email, name, state) values ('carol@example.com', 'Carol Jackson', 'CA'); insert into users (email, name, state) values ('david@example.com', 'David Yang', 'NV'); |
运行完上述代码块后,让我们验证数据是否已正确输入。
SELECT * FROM medusa_test.users;
email | name | state -------------------+---------------+------- alice@example.com | Alice Smith | TX bob@example.com | Bob Jones | VA david@example.com | David Yang | NV carol@example.com | Carol Jackson | CA
(4 rows) |
现在,我们可以使用以下命令将数据备份到 MinIO,因为这是一个小型数据集,所以应该不会花费太长时间。
helm install demo-backup k8ssandra/backup --set name=backup1,cassandraDatacenter.name=dc1
请务必记下备份的名称,稍后在本教程中恢复数据时需要用到。
验证备份的状态。如果以下命令返回时间戳,则表示备份成功。
kubectl get cassandrabackup backup1 -o jsonpath={.status.finishTime}
您也应该在 MinIO 控制台中验证备份是否已创建。
- 设置端口转发 `kubectl port-forward service/minio 39000:9000`
- 访问 MinIO 控制台 `http://localhost:39000`

恢复
现在我们已经确认备份成功,作为 SRE/DevOps 工程师,您还需要测试确保能够恢复备份。使用整个数据集测试恢复,以确保能够恢复所有内容。
删除数据
仍在 `cqlsh>` REPL 中,删除现有数据。
TRUNCATE medusa_test.users;
验证数据是否已成功删除
SELECT * FROM medusa_test.users;
email | name | state -------+------+-------
(0 rows) |
之前数据有 4 行,现在为 0 行。
获取备份
与运行备份的方式类似,我们也将使用 helm 进行恢复。
helm install demo-restore k8ssandra/restore --set name=restore-backup1,backup.name=backup1,cassandraDatacenter.name=dc1
在上述命令中,`backup.name` 应与原始备份的名称匹配。
检查备份的状态
kubectl get cassandrarestore restore-backup1 -o jsonpath={.status}
当您在输出中看到 `finishTime` 时,表示恢复已成功完成。另一种验证方法是再次获取用户列表。
SELECT * FROM medusa_test.users;
email | name | state -------------------+---------------+------- alice@example.com | Alice Smith | TX bob@example.com | Bob Jones | VA david@example.com | David Yang | NV carol@example.com | Carol Jackson | CA
(4 rows) |
总结
就是这样!让我们回顾一下我们做了什么。
- 使用 K8ssandra 将 Cassandra 部署到 Kubernetes。
- 我们部署了 MinIO 对象存储。
- 我们成功地将 Apache Cassandra 中的数据备份到 MinIO 对象存储并恢复。
您可以更进一步,执行灾难恢复场景,从头开始创建新的集群,将 Medusa 连接到 MinIO,并开始从之前备份的数据副本中恢复。尝试一下,并告诉我们结果如何!
如果您有任何关于如何设置此功能的问题,请务必加入我们的 Slack 频道 这里。