cassandra 集群
Apache Cassandra是一个经过验证的可容错且可扩展的分散式NoSQL数据库,适用于当今的应用程序。 您可以在Docker容器上部署Cassandra或通过Kubernetes管理Cassandra。
在本教程中,您将学习如何使用Kubernetes跨多个数据中心(在地理上相距甚远)建立一个Cassandra集群。 数据中心可能位于不同的国家或地区。 使用此设置的一些原因是:
- 执行实时备份,其中将写入一个数据中心的数据异步复制到另一个数据中心。
- 一个位置(例如,美国)中的用户连接到该位置或附近的数据中心,而另一个位置(例如,印度)中的用户连接到该位置或附近的数据中心,以确保更快的性能。
- 如果一个数据中心发生故障,您仍然可以从另一数据中心提供Cassandra数据。
- 如果一个数据中心中的几个节点发生故障,则Cassandra数据仍然可用而不会中断。
使用开源Kubernetes平台管理的Docker容器实现了这一目标。
建立
要完成本教程中的步骤,您将使用Kubernetes概念pod , StatefulSet , headless服务和PersistentVolume 。 这是您需要的:
- Kubernetes集群在至少两个单独的数据中心中具有节点。 确保Kubernetes是V1.8.x或更高版本
- 每个数据中心至少有三个节点,Kubernetes可以在其中部署Pod
图1显示了在每个数据中心具有五个节点的设置。 每个Kubernetes节点都部署一个代表Cassandra节点的Cassandra Pod。 应用程序Pod部署在每个数据中心上,它们使用无头服务访问数据中心本地的Cassandra节点。 写入一个数据中心中任何节点的数据将异步复制到其他数据中心中的节点。
图1.一个Cassandra集群分布在两个数据中心中,每个数据中心中有五个节点
这个主意
创建两个StatefulSet
,每个站点一个。 StatefulSet
管理一组吊舱的部署和扩展,并提供有关这些吊舱的顺序和唯一性的保证。 StatefulSet
定义了节点相似性,因此来自一个StatefulSet
的Pod仅部署在一个数据中心的节点上。 这是通过在每个节点上设置标签来实现的。 将数据中心1中的所有节点标记为dc=DC1
并将数据中心2中的所有节点标记为dc=DC2
。 每个数据中心将有一个Cassandra种子节点,但是如果您有五个节点,则建议两个种子节点。 将适当的标签添加到Kubernetes节点。
通过数据中心标记节点
kubectl label nodes nodea1 dc=DC1
kubectl label nodes nodea2 dc=DC1
kubectl label nodes nodea3 dc=DC1
kubectl label nodes nodeb1 dc=DC2
kubectl label nodes nodeb2 dc=DC2
kubectl label nodes nodeb3 dc=DC2
那个行动
本教程中使用的所有代码都可以在GitHub上找到 。 克隆存储库或从那里复制YAML文件。
1.创建名称空间
首先,创建一个新的名称空间,您将在其中进行所有工作。
kubectl create namespace c7a
2.创建无头服务
kubectl -n c7a create -f service.yaml
无头服务允许应用程序Pod通过服务名称连接到Cassandra Pod。 使用两项无头服务,一项无头服务为一个数据中心的Cassandra荚服务,另一项为另一数据中心的Cassandra荚服务。 每个数据中心中部署的应用程序容器可以利用环境变量来选择要连接到其数据中心本地的Cassandra服务。
3.创建持久卷
Cassandra节点将数据存储在持久卷中。 由于Cassandra首选每个节点的所有本地存储,因此您可以提前配置存储。 总共有六个节点。 首先,在每个节点上创建一个目录以存储Cassandra数据。 例如/data/cass/
。 确保每个节点上此目录中有10 GB的可用存储空间。 在每个站点的三个节点中的每个节点上创建此目录。
然后使用GitHub中提供的YAML文件创建所有六个PersistentVolumes。 您可以根据需要调整此文件中目录的容量和位置。
kubectl -n c7a create -f local_pvs.yaml
4.创建StatefulSet
在StatefulSet
中定义的持久卷声明消耗了持久卷。 创建两个StatefulSet
(每个站点一个)。 请记住,第一个数据中心上的每个节点都用dc=DC1
标签标记,而第二个数据中心上的每个节点都用dc=DC2
标签标记。 StatefulSet
名为cassandra-a的节点关联性规范可确保将Pod仅配置到DC1数据中心节点。 同样,cassandra-b StatefulSet
已将亲和力设置为DC2数据中心,因此,使用该StatefulSet
所有Pod仅部署到DC2数据中心。
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: dc
operator: In
values:
- DC1
StatefulSet
是Kubernetes中的强大构造。 要了解Pod部署和联网的工作原理,您需要了解其一些基本约定。
吊舱名称
按顺序创建StatefulSet
中的StatefulSet
,从第一个的名称开始,以零结束。 吊舱名称遵循以下语法: <statefulset name>-<ordinal index>.
。 在本教程中,DC1中的Pod分别命名为cassandra-a-0,cassandra-a-1和cassandra-a-2。 DC2中的Pod被命名为cassandra-b-0,依此类推。
网络地址
StatefulSet
可以使用无头服务来控制其pod的域。 此服务管理的域的格式$(service name).$(namespace).svc.cluster.local
,其中cluster.local
是群集域。 创建每个Pod时,它将获得一个匹配的DNS子域,格式$(podname).$(service name).$(namespace).svc.cluster.local
。 在本教程中,DC1中的第一个Pod名称为cassandra-a-0.cassandra-a.c7a.svc.cluster.local
,其他Pod遵循相同的约定。
数量索赔
批量声明模板在StatefulSet
指定为名称cassandra-data
。 由此StatefulSet
生成的结果持久卷声明将以$(volumeClaimTemplate name)-$(pod name)
格式$(volumeClaimTemplate name)-$(pod name)
。 对于这些, StatefulSet
的部署会创建批量声明,例如cassandra-data-cassandra-a-0
和cassandra-data-cassandra-b-0
。 批量声明与相应的广告连播匹配。 因为使用了静态卷配置,所以声明会选择他们想要的卷。
Cassandra配置
通过由特定Cassandra Docker映像公开的环境变量来完成与Cassandra配置有关的StatefulSet
中的更多详细信息。 一个重要方面是卡桑德拉种子的规格。 建议从每个数据中心至少指定一个种子节点。 因此,每个数据中心中的第一个Pod被指定为种子节点。 注意种子节点的标准节点名称。 另一个显着区别是数据中心规范; StatefulSet
cassandra-a位于DC1中,而StatefulSet
cassandra-b位于DC2数据中心中。
现在是时候创建两个StatefulSet
并确保它们创建成功了:
kubectl -n c7a create -f statefulset-a.yaml
kubectl -n c7a create -f statefulset-b.yaml
kubectl -n c7a get statefulsets
5.验证Cassandra种子节点
在本教程中,每个StatefulSet
定义中都指定了一个副本,因此对于每个StatefulSet
,每个数据中心中只会创建一个Pod。 这些豆荚将被命名为cassandra-a-0
和cassandra-b-0
。 只需列出豆荚以确认:
kubectl -n c7a get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
cassandra-a-0 1/1 Running 0 4m 10.244.0.6 iops15
cassandra-b-0 1/1 Running 2 3m 10.244.1.2 kube-vm1
如果Pod成功且它们处于运行状态,请检查Cassandra的nodetool
状态。 您应该从每个数据中心看到一个节点:
kubectl -n c7a exec -ti cassandra-a-0 -- nodetool status
Data center: DC1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.2.22 127.33 KiB 256 100% 59b4e526-3a3c-4252-84b7-2c6c5de05e13 Rack1
Data center: DC2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.5.6 108.63 KiB 256 100% cb86a5e6-2666-445e-ba96-88640b0e7848 Rack1
如果两个种子节点容器中的任何一个有错误,请检查日志以找出问题所在。 您可以使用kubectl -n c7a logs cassandra-a-0
获得cassandra-a- kubectl -n c7a logs cassandra-a-0
。
6.使用StatefulSet
缩放
到目前为止,每个数据中心仅创建了一个Cassandra节点。 现在该使用StatefulSet
缩放StatefulSet
。 将每个StatefulSet
的副本数设置为3:
kubectl -n c7a scale --replicas=3 statefulset/cassandra-a
kubectl -n c7a scale --replicas=3 statefulset/cassandra-b
现在,每个StatefulSet
都缩放为具有三个副本。 您可以有更多的副本,但需要确保事先已相应地设置了永久卷。
7.验证其他Cassandra节点
几分钟后,其余的Pod已启动并运行,并已加入Cassandra集群。 使用此nodetool
实用程序验证所有Cassandra节点的状态:
kubectl -n c7a exec -ti cassandra-a-0 -- nodetool status
Data center: DC1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.2.22 127.33 KiB 256 29.7% 59b4e526-3a3c-4252-84b7-2c6c5de05e13 Rack1
UN 10.244.1.24 108.62 KiB 256 32.9% 7749be9d-4b66-4c9f-8afc-55d484d7404f Rack1
UN 10.244.1.25 218.27 KiB 256 32.6% bfd26111-21e3-42a9-bdf6-b2068c1bd1c5 Rack1
Data center: DC2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.244.5.6 108.63 KiB 256 35.7% cb86a5e6-2666-445e-ba96-88640b0e7848 Rack1
UN 10.244.5.7 196.67 KiB 256 33.8% 1a0b6ba5-a9fd-4d67-bb5f-9cdc97b5433e Rack1
UN 10.244.5.8 127.42 KiB 256 35.4% 09fa301d-d057-4b2d-a44f-7ab57d7e5197 Rack1
上面的输出显示六个节点(每个数据中心三个)已启动并正在运行。
8.使用复制配置创建Cassandra密钥空间
现在创建一个keyspace
并指定每个数据中心需要多少个副本。 每个数据中心中有多个副本有助于解决本地节点故障,因为如果节点发生故障,仍然可以从副本中提供数据。
kubectl -n c7a exec -ti cassandra-a-0 -- cqlsh
Connected to Cassandra at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.1 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh> create keyspace hr_keyspace with replication ={'class' : 'NetworkTopologyStrategy', 'DC1':2, 'DC2':2};
上面的代码显示Cassandra Shell会话( cqlsh
)已在cassandra-a-0节点上启动。 然后创建一个名为hr_keyspace
的keyspace
。 创建keyspace
,需要指定复制策略。 当涉及多个数据中心时,通常使用NetworkTopologyStrategy
的复制策略。 有一个选项可以指定每个数据中心需要多少个副本。 在上面的示例中,为数据中心DC1指定了两个副本,为数据中心DC2指定了两个副本。
接下来,创建一个表并添加一些数据:
cqlsh> use hr_keyspace;
cqlsh> CREATE TABLE employee( emp_id int PRIMARY KEY, emp_name text, emp_city text, emp_sal varint, emp_phone varint);
#For asynchronous writes to other data center, set the #consistency level to LOCAL_QUORUM
cqlsh:hr_keyspace> consistency LOCAL_QUORUM
Consistency level set to LOCAL_QUORUM.
cqlsh:hr_keyspace> INSERT INTO employee (emp_id, emp_name, emp_city,emp_sal,emp_phone) VALUES(1,'David', 'San Francisco', 50000, 983210987);
cqlsh:hr_keyspace> INSERT INTO employee (emp_id, emp_name, emp_city,emp_sal,emp_phone) VALUES(2,'Robin', 'San Jose', 55000, 9848022339);
cqlsh:hr_keyspace> INSERT INTO employee (emp_id, emp_name, emp_city,emp_sal,emp_phone) VALUES(3,'Bob', 'Austin', 45000, 9848022330);
cqlsh:hr_keyspace> INSERT INTO employee (emp_id, emp_name, emp_city,emp_sal,emp_phone) VALUES(4, 'Monica','San Jose', 55000, 9458022330);
请注意LOCAL_QUORUM
的一致性级别。 它确保将数据首先写入本地节点,然后异步复制到远程数据中心节点。 这很重要,因为它告诉Cassandra将数据异步复制到远程数据中心。
现在尝试从任何节点检索该数据。
cqlsh:hr_keyspace> select * from employee;
emp_id | emp_city | emp_name | emp_phone | emp_sal
--------+---------------+----------+------------+---------
1 | San Francisco | David | 983210987 | 50000
2 | San Jose | Robin | 9848022339 | 55000
4 | San Jose | Monica | 9458022330 | 55000
3 | Austin | Bob | 9848022330 | 45000
cqlsh:hr_keyspace> quit;
9.模拟站点故障
如果来自一个数据中心的所有Cassandra吊舱都不可用,则可以模拟站点故障。 为此,请删除一个StatefulSet
。 如果删除一个StatefulSet
则该数据中心的三个Pod将消失,从而模拟站点故障。 如果发生这种情况,您仍然可以从其他站点检索数据。
kubectl -n c7a delete statefulset cassandra-a
statefulset "cassandra-a" deleted
kubectl -n c7a get pods -o wide
这将删除StatefulSet cassandra-a
及其所有吊舱。 现在,仅剩下三个Cassandra吊舱,全部来自数据中心DC2。 连接到任何一个并尝试检索数据:
kubectl -n c7a exec -ti cassandra-b-1 – cqlsh
Connected to Cassandra at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.1 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh> use hr_keyspace;
cqlsh:hr_keyspace> select * from employee;
emp_id | emp_city | emp_name | emp_phone | emp_sal
--------+---------------+-----------+-------------+---------
1 | San Francisco | David | 983210987 | 50000
2 | San Jose | Robin | 9848022339 | 55000
4 | San Jose | Monica | 9458022330 | 55000
3 | Austin | Bob | 9848022330 | 45000
(4 rows)
cqlsh:hr_keyspace> quit;
这表明数据仍然可以从其他数据中心节点获得。 请注意,上面的示例显示了直接与Cassandra节点的连接。 但是实际上,使用Cassandra的应用程序将通过为其创建的无头服务将其连接,如上面的图1所示。
10.清理
要删除c7a名称空间中Kubernetes集群上的所有内容,请使用以下命令:
kubectl –n c7a delete statefulset,pvc,pv,svc -l app=cassandra
结论
在本教程中,您了解了如何在Kubernetes平台上设置多数据中心Cassandra集群。 此设置对于执行实时备份以及防止站点或数据中心故障很有用。 对Cassandra群集的站点位置感知访问也减少了读写延迟。
cassandra 集群