我们在Kubernetes集群之间进行Cassandra迁移的经验而不会丢失数据



在过去大约六个月中,我们一直使用Rook运算符与Kubernetes中的Cassandra一起使用但是,当我们需要执行非常琐碎的操作时,就好像是在操作:更改Cassandra配置中的参数时,结果表明操作员没有提供足够的灵活性。要进行更改,必须克隆存储库,更改源并重建操作员(配置内置在操作员本身中,因此Go知识仍然有用)。这一切都需要很多时间。

我们已经对现有的操作员进行了回顾,而这次我们在Orange的CassKop留了下来,它支持必要的功能,尤其是自定义配置和开箱即用的监视。

任务


在后面将要讨论的真实故事中,决定将运营商的变更与将整个客户端基础架构转移到新集群的迫切需求结合起来。从重要应用程序迁移了主要工作负载之后,只剩下Cassandra了,数据丢失当然是不可接受的。

迁移要求:

  • 在将应用程序本身移到新集群的同时,最大空闲时间为2-3分钟,以实际执行此传输。
  • 传输所有数据而不会造成任何损失和头痛(即无需进行任何其他操作)。

如何进行这样的手术?类似于RabbitMQMongoDB,我们决定在新的Kubernetes集群中启动Cassandra的新安装,然后将两个Cassandra合并到不同的集群中并传输数据,通过简单地禁用原始安装来结束整个过程。

但是,由于Kubernetes内部的网络相交这一事实使情况变得复杂,因此配置连接并不是那么容易。需要在每个节点上为每个吊舱注册路由,这非常耗时并且根本不可靠。事实是,IP Pod上的通信仅适用于主服务器,而Cassandra在专用节点上运行。因此,您必须首先配置到主服务器以及已经在主服务器上的路由-到另一个集群。除此之外,重新启动Pod还需要更改IP,这是另一个问题……为什么?在本文稍后阅读。

在本文的后续实际部分中,将使用Cassandra群集的三种符号:

  • Cassandra- new-我们将在新的Kubernetes集群中启动的新安装;
  • Cassandra-current-一种旧的安装,当前可以使用应用程序;
  • Cassandra-temporary是一个临时安装,我们在Cassandra-current旁边运行,仅用于迁移过程本身。

怎样成为?


由于Cassandra-current使用本地存储,因此不可能将其数据简单迁移到新群集(例如,在vSphere磁盘的情况下...)。为了解决这个问题,我们将创建一个临时集群,将其用作迁移的缓冲区。

一般的操作顺序可简化为以下步骤:

  1. 新的运算符在新集群中提高Cassandra-new
  2. 缩放到0 Cassandra-new cluster
  3. , PVC, .
  4. Cassandra-temporary Cassandra-current , Cassandra-new.
  5. Cassandra-temporary 0 ( ) Cassandra-temporary , Cassandra-temporary Cassandra-current. Cassandra - ( Cassandra ).
  6. Cassandra临时数据中心Cassandra当前数据中心之间传输数据
  7. Cassandra-currentCassandra-temporary群集缩放为0,并在新群集中运行Cassandra-new,不要忘记扔磁盘。同时,我们将应用程序滚动到新集群。

由于这样的操作,停机时间将最小。

详细


前三个步骤应该没有任何问题-一切都快速,轻松地完成。

此时,Cassandra当前集群将如下所示:

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

要验证一切是否按预期进行,请在Cassandra-current中创建一个键空间这是在启动Cassandra-temporary之前完成的

create keyspace example with replication ={'class' : 'NetworkTopologyStrategy', 'x1':2};

接下来,创建一个表并用数据填充它:

use example;
CREATE TABLE example(id int PRIMARY KEY, name text, phone varint);
INSERT INTO example(id, name, phone) VALUES(1,'Masha', 983123123);
INSERT INTO example(id, name, phone) VALUES(2,'Sergey', 912121231);
INSERT INTO example(id, name, phone) VALUES(3,'Andrey', 914151617);

运行Cassandra-temporary,请记住,在此之前,在新集群中,我们已经启动了Cassandra-new(步骤1),现在它已关闭(步骤2)。

笔记:

  1. 启动Cassandra-temporary时,必须指定集群的相同名称(使用Cassandra-current)。这可以通过变量来完成CASSANDRA_CLUSTER_NAME
  2. 为了让临时的Cassandra能够看到当前集群,您需要设置种子。这可以通过变量CASSANDRA_SEEDS或配置来完成。

注意!开始移动数据之前,必须确保读写一致性类型设置为LOCAL_ONELOCAL_QUORUM

在启动Cassandra-temporary之后,集群应如下所示(请注意具有3个节点的第二个数据中心的外观):

Datacenter: x1
==============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns    Host ID                               Rack
UN  10.244.6.5  790.7 GiB  256          ?       13cd0c7a-4f91-40d0-ac0e-e7c4a9ad584c  rack1
UN  10.244.7.5  770.9 GiB  256          ?       8527813a-e8df-4260-b89d-ceb317ef56ef  rack1
UN  10.244.5.5  825.07 GiB  256          ?       400172bf-6f7c-4709-81c6-980cb7c6db5c  rack1

Datacenter: x2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address       Load       Tokens       Owns (effective)  Host ID                               Rack
UN  10.244.16.96  267.07 KiB  256          64.4%             3619841e-64a0-417d-a497-541ec602a996  rack1
UN  10.244.18.67  248.29 KiB  256          65.8%             07a2f571-400c-4728-b6f7-c95c26fe5b11  rack1
UN  10.244.16.95  265.85 KiB  256          69.8%             2f4738a2-68d6-4f9e-bf8f-2e1cfc07f791  rack1

现在您可以进行转移了。为此,请首先传输测试键空间-确保一切正常:

ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', x1: 2, x2: 2};


之后,在每个Cassandra临时吊舱中,执行以下命令:

nodetool rebuild -ks example x1

让我们转到Cassandra临时的任何吊舱,并检查数据是否已传输。您还可以向Cassandra-current添加1个条目,以验证新数据已开始复制:

SELECT * FROM example;

 id | name   | phone
----+--------+-----------
  1 |  Masha | 983123123
  2 | Sergey | 912121231
  3 | Andrey | 914151617

(3 rows)

之后,您可以ALTERCassandra-current中执行所有键空间并执行nodetool rebuild

缺乏空间和内存


在此阶段,请记住,在运行重建时,创建的临时文件的大小与键空间的大小相等!我们遇到了一个最大密钥空间为350 GB,可用磁盘空间较少的问题。

由于使用了本地存储,因此无法扩展磁盘。以下命令可以进行救援(在Cassandra-current的每个pod中执行):

nodetool clearsnapshot

这样就释放了该空间:在我们的示例中,获得了500 GB的可用磁盘空间,而不是以前的200 GB。

但是,尽管有足够的空间,但是重建操作不断导致Cassandra临时吊舱重新启动,但出现错误:

failed; error='Cannot allocate memory' (errno=12)

我们通过创建DaemonSet来决定它,它仅向Cassandra临时的节点推出并执行:

sysctl -w vm.max_map_count=262144

最后,所有数据都已迁移!

集群切换


仅需切换Cassandra,分五个阶段进行:

  1. Cassandra-temporaryCassandra-current缩放(不要忘记该操作符仍在这里工作!)到0。
  2. 切换磁盘(归结为为Cassandra-new设置PV )。
  3. 我们启动Cassandra-new,跟踪已连接必要的磁盘。
  4. 我们执行ALTER所有表以删除旧集群:

    ALTER KEYSPACE example WITH replication = {'class': 'NetworkTopologyStrategy', 'x2': 2};
  5. 删除旧群集的所有节点。为此,只需在其中一个容器中运行以下命令:

    nodetool removenode 3619841e-64a0-417d-a497-541ec602a996

Cassandra的总停机时间约为3分钟-这是容器停止和启动的时间,因为磁盘是预先准备的。

与普罗米修斯的最后接触


但是,这并没有到此结束。一个内置Cassandra-new的导出器(请参阅new运算符文档 -我们当然使用了它。发射约1小时后,关于普罗米修斯无法进入的警报开始出现。检查负载后,我们发现使用Prometheus的节点上的内存消耗有所增加。

对该问题的进一步研究表明,收集的指标数量增加了2.5倍(!)。错误是卡桑德拉(Cassandra),仅收集了超过50万个指标。

我们对度量进行了审核,并通过ConfigMap禁用了我们认为不必要的度量(通过配置导出器来配置)。结果是12万个度量标准,并且大大减少了Prometheus的负担(尽管仍然保留了重要的度量标准)。

结论


因此,我们设法将Cassandra转移到另一个集群,实际上没有影响Cassandra的生产安装的功能,也没有干扰客户端应用程序的工作。在此过程中,我们得出的结论是,使用相同的Pod网络不是一个好主意(现在,我们更加注意安装群集的初始计划)。

最后:为什么我们不使用nodetool snapshot上一篇文章中提到的工具事实是,此命令以运行该命令之前的状态创建密钥空间快照。除了:

  • 拍照和传输需要更多时间;
  • 此时在Cassandra中编写的所有内容都将丢失;
  • 在我们的情况下,简单的操作大约需要一个小时-而不是3分钟,而事实证明,这可以成功地将应用程序部署到新集群中。

聚苯乙烯


另请参阅我们的博客:


All Articles