我们有一个基本的2节点Cassandra集群。两个节点都使用最少的配置运行版本3.9以启用群集。其中一个节点发送错误的代,导致另一个节点显示警告
WARN [GossipStage:1] Gossiper.java:1146 - received an invalid gossip generation for peer /10.3.185.234; local time = 1479469393, received generation = 1872927836
导致问题的节点1具有
的输出nodetool gossipinfo
/10.3.185.234
generation: 1872927836
1872927836时代是一个遥远的日期(星期二,2029年5月8日09:43:56 GMT)。节点2合法地丢弃该分组。我能以某种方式修复node-1以发送正确的代吗?
答案 0 :(得分:4)
通过使用cqlsh更改system.local表中的gossip_generation值来解决此问题
(void*)
此更改后重新启动服务
答案 1 :(得分:1)
我不知道手动设置有什么影响,但另一种解决方法是立即重启整个群集。这可能对我们有用。 (经过我们的修复后发现)。
文档说要进行多次滚动重启,直到它被修复(这对我们没用。)然而,重启整个集群的大锤确实有效。所有的代都设置得恰当。
答案 2 :(得分:0)
我们使用scylla(version = 2.1.3-0.20180501.8e33e80ad),并且能够在不重新启动整个群集的情况下解决此问题。
我们的集群最近丢失了节点,因为这些节点已重新启动,并且在启动的八卦阶段不允许加入集群。原因是:状态= UN(正常)的节点发出以下错误,并且在闲聊阶段不允许受影响的节点加入群集。在我们的例子中,错误消息是:
Jul 04 01:54:17 host-10.3.7.77 scylla [30263]:[碎片0]八卦-接收到对等体10.3.7.7的无效八卦;本地生成= 1526993447,收到的生成= 1562158865
现在让我们进入上述错误消息的详细信息和上下文:
gossiper.register (this-> shared_from_this());
auto generation_number = db :: system_keyspace :: increment_and_get_generation()。get0();
_gossiper.start_gossiping(generation_number,app_states,gms :: bind_messaging_port(bool(do_bind)))。get();
int64_t MAX_GENERATION_DIFFERENCE = 86400 * 365;
如果(local_generation> 2 && remote_generation> local_generation + MAX_GENERATION_DIFFERENCE) {//假设某些同位体已损坏内存 并且正在广播有关另一个同伴(或 本身)
logger.warn(“收到对等体.....}的无效八卦消息
auto req = format("SELECT gossip_generation FROM system.{} WHERE key='{}'", LOCAL, LOCAL); return qctx->qp().execute_internal(req).then([] (auto rs) { int generation; if (rs->empty() || !rs->one().has("gossip_generation")) { // seconds-since-epoch isn't a foolproof new generation // (where foolproof is "guaranteed to be larger than the last one seen at this ip address"), // but it's as close as sanely possible generation = service::get_generation_number(); } else { // Other nodes will ignore gossip messages about a node that have a lower generation than previously seen. int stored_generation = rs->one().template get_as<int>("gossip_generation") + 1; int now = service::get_generation_number(); if (stored_generation >= now) { slogger.warn("Using stored Gossip Generation {} as it is greater than current system time {}." "See CASSANDRA-3654 if you experience problems", stored_generation, now); generation = stored_generation; } else { generation = now; } } auto req = format("INSERT INTO system.{} (key, gossip_generation) VALUES ('{}', ?)", LOCAL, LOCAL);
int get_generation_number(){....现在自动= high_resolution_clock :: now()。time_since_epoch();整型 generation_number = duration_cast(now).count(); ....}
因此,节点在启动时生成并发送给种子的世代号通常总是接近当前时间,但是种子UN节点作为本地引用存储的世代号不会改变。
要完全避免集群重新启动:我们在生产中基于上述代码逻辑采用了这种方法。
-根本问题是有问题的本地一代 存储在联合国种子节点中的节点未更改。 (但 每次重新启动时有问题的节点都会发送一个新的发电代号 接近当前时间)
-IDEA:让我们更新存储在UN节点中的有问题节点的本地生成,以便有问题节点发送的远程生成编号将在1年内。
-那么我们如何在UN种子节点中更新此值?我们需要使有问题的节点发送一个Gen编号(纪元),其值落入存储在联合国种子节点中的本地Gen编号的1年窗口中。但是由于代码始终将当前时间作为发电机组编号,并且当前时间是2019年7月,所以我们该怎么办?
-我们将有问题的节点上的TIME更改为1529993447的1年之内的值。在1年窗口的结尾选择一个纪元值,即将系统时间更改为例如2019年3月31日的值,即epoch 1554030000,而不是2018年10月2日并重启节点。该节点将重新启动并发送gen 1554030000(因为它查找system.local表)或当前时间(无论如何是2019年3月31日)作为种子。
-联合国种子节点获得此值并验证有问题的节点发送的远程发电数量在2018年5月22日的1年内,因此,它将继续更新其参考(本地发电)。
else if(remote_generation> local_generation){logger.trace(“将心跳状态的生成从{}的{}更新为{}”,remote_generation,local_generation,ep); //主要状态更改将通过直接插入远程状态来处理更新 this-> handle_major_state_change(ep,remote_state); } ....
-我们已成功更新了存储在UN种子节点中的有问题节点的参考(本地gen)。 -现在我们停止有问题的节点,将有问题的节点上的时间重置为当前时间并重新启动,有问题的节点将发送例如2019年7月4日的最新纪元,即纪元1562215230 -现在时间重置并重新启动之后,由于1562215230(gen使用最新时间发送给有问题的节点)减去1554030000(存储在联合国种子节点中的本地参考)<1年,因此有问题的节点将被允许加入集群。 >
-我们建议您在1年窗口结束时选择一个纪元/日期,但在1年内,越晚越好,因为新的1年窗口从您选择的日期开始,并且此问题已得到缓解大声笑–是的,长时间运行的群集上会出现此问题。这意味着您需要每年不时进行一次滚动重启,以延长1年窗口。
以下是该过程的步骤:
步骤:
如果有问题的节点为10.3.7.7,并且报告说错误 10.3.7.77(UN节点),请确保10.3.7.7的种子为10.3.7.77,这样我们就可以保证与该节点进行通讯,而不必 搜索以找出集群中谁也在讲话。如果种子 7.7节点与报告错误的节点不同,则 查看种子节点打印的错误消息,以确定哪个 太重设了。在我们的案例中,由于我看到了7.77的错误, 将7.7的种子更改为7.77节点。
启动有问题的节点。
Jul 04 01:54:17 host-10.3.7.77 scylla [30263]:[shard 0]八卦– 接收到对等体10.3.7.7的无效八卦生成;本地 世代= 1526993447,收到的世代= 1562158865
cqlsh到有问题的节点10.3.7.7,并在1526993447的1年内将世代号更新为一个纪元,但请在1年窗口结束时选择一个纪元,例如1554030000(2019年3月31日),而不是说7月/ 2018年10月,以便您拥有更长的1年新窗口。
在有问题的节点上,运行命令
5.1'更新system.local设置gossip_generation = 1554030000,其中key ='local';'
5.2'nodetool刷新'
停止有问题的节点
编辑配置文件,并将CQL(native_transport_port)从9042更改为9043,以便客户端无法连接和插入数据–在此阶段插入数据将设置时间戳为3月2019年的记录,这是不正确的,即防止数据损坏。这是一个预防措施
更改系统时间,即“ date -s ’31 MAR 2019 11:03:25′”
将节点声明为UN:
14.1关闭节点
14.2在配置文件中将CQL(native_transport_port)从9043更改回9042。
14.3在包装盒上重置系统时间
14.4验证系统时间是否恢复正常
启动节点。并且该节点仍应为UN。
自白:
故事的道德人:
参考文献:
https://github.com/scylladb/scylla/blob/134b59a425da71f6dfa86332322cc63d47a88cd7/gms/gossiper.cc
您还可以在我的博客中找到上述说明/修复的详细信息 https://mash213.wordpress.com/2019/07/05/scylla-received-an-invalid-gossip-generation-for-peer-how-to-resolve/