ALTER CLUSTER <cluster_name> UPDATE nodes 语句将每个节点内的指定集群中的节点列表更新为包括集群中的所有活动节点。有关节点列表的更多信息,请参见加入集群。
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- javascript
- Java
- C#
- Rust
ALTER CLUSTER posts UPDATE nodesPOST /cli -d "
ALTER CLUSTER posts UPDATE nodes
"$params = [
'cluster' => 'posts',
'body' => [
'operation' => 'update',
]
];
$response = $client->cluster()->alter($params);utilsApi.sql('ALTER CLUSTER posts UPDATE nodes')await utilsApi.sql('ALTER CLUSTER posts UPDATE nodes')res = await utilsApi.sql('ALTER CLUSTER posts UPDATE nodes');utilsApi.sql("ALTER CLUSTER posts UPDATE nodes");utilsApi.Sql("ALTER CLUSTER posts UPDATE nodes");utils_api.sql("ALTER CLUSTER posts UPDATE nodes", Some(true)).await;{u'error': u'', u'total': 0, u'warning': u''}{u'error': u'', u'total': 0, u'warning': u''}{"total":0,"error":"","warning":""}例如,当集群最初建立时,用于重新加入集群的节点列表是 10.10.0.1:9312,10.10.1.1:9312。此后,其他节点加入了集群,现在活动节点是 10.10.0.1:9312,10.10.1.1:9312,10.15.0.1:9312,10.15.0.3:9312。然而,用于重新加入集群的节点列表没有更新。
要纠正这一点,可以运行 ALTER CLUSTER ... UPDATE nodes 语句将活动节点列表复制到用于重新加入集群的节点列表。这样,用于重新加入集群的节点列表将包括集群中的所有活动节点。
两个节点列表都可以通过使用 集群状态 语句 (cluster_post_nodes_set 和 cluster_post_nodes_view) 查看。
要从复制集群中移除节点,请按照以下步骤操作:
- 停止节点
- 从已停止节点的
<data_dir>/manticore.json(通常是/var/lib/manticore/manticore.json)中删除集群信息。 - 在集群中的其他节点上运行
ALTER CLUSTER cluster_name UPDATE nodes。
完成这些步骤后,其他节点将忘记已分离的节点,而已分离的节点将忘记集群。此操作不会影响集群中的表或已分离节点上的表。
您可以通过检查节点状态来查看集群状态信息。可以使用节点状态命令来完成,此命令显示关于节点的各种信息,包括集群状态变量。
集群状态变量的输出格式如下:cluster_name_variable_name variable_value。大多数变量已在Galera 文档状态变量中进行了描述。除了这些变量外,Manticore Search 还显示:
cluster_name- 集群名称,定义于复制设置node_state- 节点当前状态:closed、destroyed、joining、donor、syncedindexes_count- 集群管理的表的数量indexes- 集群管理的表名列表nodes_set- 使用CREATE、JOIN或ALTER UPDATE命令定义的集群中的节点列表nodes_view- 当前节点可见的集群实际节点列表state_uuid- 集群的 UUID 状态。如果它与 local_state_uuid 的值匹配,则本地和集群节点同步conf_id- 发生的集群成员变更总数status- 集群组件状态。可能的值为 primary(主组配置,有法定人数)、non_primary(非主组配置,失去法定人数)或 disconnected(未连接到组,正在重试)size- 当前集群中的节点数量local_index- 节点在集群中的索引last_error- 与集群操作相关的最后一条记录错误消息。消息提供问题的高级摘要。有关更详细的上下文,您应查看searchd.log文件。
在状态快照传输(SST)期间,一个节点通过传输完整数据副本为另一个节点提供资源。当新节点加入集群JOIN CLUSTER或添加新表ALTER CLUSTER ADD时,会发生此操作。当 SST 正在进行时,以下额外的状态变量会在供体和加入节点上可用,其进度保持同步。
cluster_name_sst_total- 整个 SST 操作的总体进度,从 0 到 100。是主要的计数器。cluster_name_sst_stage- 当前工作阶段的名称。此过程为每个传输的表循环经过以下阶段:await nodes syncblock checksum calculateanalyze remotesend filesactivate tables
cluster_name_sst_stage_total- 当前阶段的进度,从 0 到 100。cluster_name_sst_tables- SST 中传输的表的总数。cluster_name_sst_table- 当前处理的表的名称和索引(例如,3 (products))。
对于大多数用例,cluster_name_sst_total 就足够了。但其他计数器在调查特定 SST 阶段或特定表的停顿或性能问题时非常有用。
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- javascript
- Java
- C#
- Rust
SHOW STATUSPOST /cli -d "
SHOW STATUS
"$params = [
'body' => []
];
$response = $client->nodes()->status($params);utilsApi.sql('SHOW STATUS')await utilsApi.sql('SHOW STATUS')res = await utilsApi.sql('SHOW STATUS');utilsApi.sql("SHOW STATUS");utilsApi.sql("SHOW STATUS");utils_api.sql("SHOW STATUS", Some(true)).await;+---------------------------------+-------------------------------------------------------------------------------------+
| Counter | Value |
+---------------------------------+-------------------------------------------------------------------------------------+
| cluster_name | post |
| cluster_post_state_uuid | fba97c45-36df-11e9-a84e-eb09d14b8ea7 |
| cluster_post_conf_id | 1 |
| cluster_post_status | primary |
| cluster_post_size | 5 |
| cluster_post_local_index | 0 |
| cluster_post_node_state | donor |
| cluster_post_indexes_count | 2 |
| cluster_post_indexes | pq1,pq_posts |
| cluster_post_nodes_set | 10.10.0.1:9312 |
| cluster_post_nodes_view | 10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication |
| cluster_post_sst_total | 65 |
| cluster_post_sst_stage | send files |
| cluster_post_sst_stage_total | 78 |
| cluster_post_sst_tables | 5 |
| cluster_post_sst_table | 3 (products) |
+---------------------------------+-------------------------------------------------------------------------------------+"
{"columns":[{"Counter":{"type":"string"}},{"Value":{"type":"string"}}],
"data":[
{"Counter":"cluster_name", "Value":"post"},
{"Counter":"cluster_post_state_uuid", "Value":"fba97c45-36df-11e9-a84e-eb09d14b8ea7"},
{"Counter":"cluster_post_conf_id", "Value":"1"},
{"Counter":"cluster_post_status", "Value":"primary"},
{"Counter":"cluster_post_size", "Value":"5"},
{"Counter":"cluster_post_local_index", "Value":"0"},
{"Counter":"cluster_post_node_state", "Value":"donor"},
{"Counter":"cluster_post_indexes_count", "Value":"2"},
{"Counter":"cluster_post_indexes", "Value":"pq1,pq_posts"},
{"Counter":"cluster_post_nodes_set", "Value":"10.10.0.1:9312"},
{"Counter":"cluster_post_nodes_view", "Value":"10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication"},
{"Counter":"cluster_post_sst_total", "Value":"65"},
{"Counter":"cluster_post_sst_stage", "Value":"send files"},
{"Counter":"cluster_post_sst_stage_total", "Value":"78"},
{"Counter":"cluster_post_sst_tables", "Value":"5"},
{"Counter":"cluster_post_sst_table", "Value":"3 (products)"}
],
"total":0,
"error":"",
"warning":""
}(
"cluster_name" => "post",
"cluster_post_state_uuid" => "fba97c45-36df-11e9-a84e-eb09d14b8ea7",
"cluster_post_conf_id" => 1,
"cluster_post_status" => "primary",
"cluster_post_size" => 5,
"cluster_post_local_index" => 0,
"cluster_post_node_state" => "donor",
"cluster_post_indexes_count" => 2,
"cluster_post_indexes" => "pq1,pq_posts",
"cluster_post_nodes_set" => "10.10.0.1:9312",
"cluster_post_nodes_view" => "10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication",
"cluster_post_sst_total" => 65,
"cluster_post_sst_stage" => "send files",
"cluster_post_sst_stage_total" => 78,
"cluster_post_sst_tables" => 5,
"cluster_post_sst_table" => "3 (products)"
){u'columns': [{u'Key': {u'type': u'string'}},
{u'Value': {u'type': u'string'}}],
u'data': [
{u'Key': u'cluster_name', u'Value': u'post'},
{u'Key': u'cluster_post_state_uuid', u'Value': u'fba97c45-36df-11e9-a84e-eb09d14b8ea7'},
{u'Key': u'cluster_post_conf_id', u'Value': u'1'},
{u'Key': u'cluster_post_status', u'Value': u'primary'},
{u'Key': u'cluster_post_size', u'Value': u'5'},
{u'Key': u'cluster_post_local_index', u'Value': u'0'},
{u'Key': u'cluster_post_node_state', u'Value': u'donor'},
{u'Key': u'cluster_post_indexes_count', u'Value': u'2'},
{u'Key': u'cluster_post_indexes', u'Value': u'pq1,pq_posts'},
{u'Key': u'cluster_post_nodes_set', u'Value': u'10.10.0.1:9312'},
{u'Key': u'cluster_post_nodes_view', u'Value': u'10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication'},
{u'Key': u'cluster_post_sst_total', u'Value': u'65'},
{u'Key': u'cluster_post_sst_stage', u'Value': u'send files'},
{u'Key': u'cluster_post_sst_stage_total', u'Value': u'78'},
{u'Key': u'cluster_post_sst_tables', u'Value': u'5'},
{u'Key': u'cluster_post_sst_table', u'Value': u'3 (products)'}],
u'error': u'',
u'total': 0,
u'warning': u''}{u'columns': [{u'Key': {u'type': u'string'}},
{u'Value': {u'type': u'string'}}],
u'data': [
{u'Key': u'cluster_name', u'Value': u'post'},
{u'Key': u'cluster_post_state_uuid', u'Value': u'fba97c45-36df-11e9-a84e-eb09d14b8ea7'},
{u'Key': u'cluster_post_conf_id', u'Value': u'1'},
{u'Key': u'cluster_post_status', u'Value': u'primary'},
{u'Key': u'cluster_post_size', u'Value': u'5'},
{u'Key': u'cluster_post_local_index', u'Value': u'0'},
{u'Key': u'cluster_post_node_state', u'Value': u'donor'},
{u'Key': u'cluster_post_indexes_count', u'Value': u'2'},
{u'Key': u'cluster_post_indexes', u'Value': u'pq1,pq_posts'},
{u'Key': u'cluster_post_nodes_set', u'Value': u'10.10.0.1:9312'},
{u'Key': u'cluster_post_nodes_view', u'Value': u'10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication'},
{u'Key': u'cluster_post_sst_total', u'Value': u'65'},
{u'Key': u'cluster_post_sst_stage', u'Value': u'send files'},
{u'Key': u'cluster_post_sst_stage_total', u'Value': u'78'},
{u'Key': u'cluster_post_sst_tables', u'Value': u'5'},
{u'Key': u'cluster_post_sst_table', u'Value': u'3 (products)'}],
u'error': u'',
u'total': 0,
u'warning': u''}{"columns": [{"Key": {"type": "string"}},
{"Value": {"type": "string"}}],
"data": [
{"Key": "cluster_name", "Value": "post"},
{"Key": "cluster_post_state_uuid", "Value": "fba97c45-36df-11e9-a84e-eb09d14b8ea7"},
{"Key": "cluster_post_conf_id", "Value": "1"},
{"Key": "cluster_post_status", "Value": "primary"},
{"Key": "cluster_post_size", "Value": "5"},
{"Key": "cluster_post_local_index", "Value": "0"},
{"Key": "cluster_post_node_state", "Value": "donor"},
{"Key": "cluster_post_indexes_count", "Value": "2"},
{"Key": "cluster_post_indexes", "Value": "pq1,pq_posts"},
{"Key": "cluster_post_nodes_set", "Value": "10.10.0.1:9312"},
{"Key": "cluster_post_nodes_view", "Value": "10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication"},
{"Key": "cluster_post_sst_total", "Value": "65"},
{"Key": "cluster_post_sst_stage", "Value": "send files"},
{"Key": "cluster_post_sst_stage_total", "Value": "78"},
{"Key": "cluster_post_sst_tables", "Value": "5"},
{"Key": "cluster_post_sst_table", "Value": "3 (products)"}],
"error": "",
"total": 0,
"warning": ""}{columns=[{ Key : { type=string }},
{ Value : { type=string }}],
data : [
{ Key=cluster_name, Value=post},
{ Key=cluster_post_state_uuid, Value=fba97c45-36df-11e9-a84e-eb09d14b8ea7},
{ Key=cluster_post_conf_id, Value=1},
{ Key=cluster_post_status, Value=primary},
{ Key=cluster_post_size, Value=5},
{ Key=cluster_post_local_index, Value=0},
{ Key=cluster_post_node_state, Value=donor},
{ Key=cluster_post_indexes_count, Value=2},
{ Key=cluster_post_indexes, Value=pq1,pq_posts},
{ Key=cluster_post_nodes_set, Value=10.10.0.1:9312},
{ Key=cluster_post_nodes_view, Value=10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication},
{ Key=cluster_post_sst_total, Value=65},
{ Key=cluster_post_sst_stage, Value=send files},
{ Key=cluster_post_sst_stage_total, Value=78},
{ Key=cluster_post_sst_tables, Value=5},
{ Key=cluster_post_sst_table, Value=3 (products)}],
error= ,
total=0,
warning= }{columns=[{ Key : { type=String }},
{ Value : { type=String }}],
data : [
{ Key=cluster_name, Value=post},
{ Key=cluster_post_state_uuid, Value=fba97c45-36df-11e9-a84e-eb09d14b8ea7},
{ Key=cluster_post_conf_id, Value=1},
{ Key=cluster_post_status, Value=primary},
{ Key=cluster_post_size, Value=5},
{ Key=cluster_post_local_index, Value=0},
{ Key=cluster_post_node_state, Value=donor},
{ Key=cluster_post_indexes_count, Value=2},
{ Key=cluster_post_indexes, Value=pq1,pq_posts},
{ Key=cluster_post_nodes_set, Value=10.10.0.1:9312},
{ Key=cluster_post_nodes_view, Value=10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication},
{ Key=cluster_post_sst_total, Value=65},
{ Key=cluster_post_sst_stage, Value=send files},
{ Key=cluster_post_sst_stage_total, Value=78},
{ Key=cluster_post_sst_tables, Value=5},
{ Key=cluster_post_sst_table, Value=3 (products)}],
error="" ,
total=0,
warning="" }{columns=[{ Key : { type=String }},
{ Value : { type=String }}],
data : [
{ Key=cluster_name, Value=post},
{ Key=cluster_post_state_uuid, Value=fba97c45-36df-11e9-a84e-eb09d14b8ea7},
{ Key=cluster_post_conf_id, Value=1},
{ Key=cluster_post_status, Value=primary},
{ Key=cluster_post_size, Value=5},
{ Key=cluster_post_local_index, Value=0},
{ Key=cluster_post_node_state, Value=donor},
{ Key=cluster_post_indexes_count, Value=2},
{ Key=cluster_post_indexes, Value=pq1,pq_posts},
{ Key=cluster_post_nodes_set, Value=10.10.0.1:9312},
{ Key=cluster_post_nodes_view, Value=10.10.0.1:9312,10.10.0.1:9320:replication,10.10.1.1:9312,10.10.1.1:9320:replication},
{ Key=cluster_post_sst_total, Value=65},
{ Key=cluster_post_sst_stage, Value=send files},
{ Key=cluster_post_sst_stage_total, Value=78},
{ Key=cluster_post_sst_tables, Value=5},
{ Key=cluster_post_sst_table, Value=3 (products)}],
error="" ,
total=0,
warning="" }当整个复制集群宕机时,必须首先启动一个节点,以便其他节点知道要加入哪个集群副本。
该首次启动决策基于 grastate.dat,这是一个存储在集群数据目录中的小型复制状态文件。最重要的字段是:
seqno- 该节点已知的最后一个事务编号safe_to_bootstrap- 该节点是否被标记为在干净关闭后可以安全地首先启动
干净关闭后 grastate.dat 的示例内容:
# saved replication state
version: 2.1
uuid: <cluster-uuid>
seqno: 12345
safe_to_bootstrap: 1
在此示例中:
seqno: 12345表示该节点知道的事务序列号最多到 12345safe_to_bootstrap: 1表示该节点被标记为可以安全地首先启动
如果整个集群已干净关闭,请启动最后停止的节点。实际上,这通常是具有:
- 最先进的
seqno safe_to_bootstrap: 1
的节点。首先启动该节点。这会告诉 Manticore 从该节点启动一个新的集群副本。之后,正常启动其余节点,以便它们可以重新加入。
在干净的完整集群关闭后使用此方法。
- Bash
- Systemd
searchd --new-clustermanticore_new_cluster如果其他节点在没有必要干净关闭状态的情况下首先启动,启动将被拒绝,以保护集群不从旧副本恢复。
如果所有节点崩溃或未干净关闭,grastate.dat 可能不再适合用于正常引导选择。在这种情况下,找到具有最新数据的节点,通常是具有最大 seqno 的节点,并使用 --new-cluster-force 启动它。这会覆盖正常保护,强制集群从选定节点启动。
在崩溃或未干净的完整集群关闭后使用此方法。
- Bash
- Systemd
searchd --new-cluster-forcemanticore_new_cluster --force如果复制节点或整个集群变得不可用,正确的恢复程序取决于仍有多少节点可以访问以及关闭是干净的还是突然的。
复制集群应被视为一个逻辑系统,而不是一组无关的服务器。这为您提供了多主写入和一致的数据,但也意味着您必须谨慎恢复法定人数。特别是,在确定缺失的节点确实已消失之前,不要运行恢复存活侧写入的手动恢复命令。该命令在本文后面显示为 SET CLUSTER <name> GLOBAL 'pc.bootstrap' = 1。如果过早运行它,可能会导致脑裂,并最终形成两个独立的集群。
在下面的示例中,除非另有说明,否则假设一个包含节点 A、B 和 C 的集群。
首先确定您处于哪种情况:
- 至少有一个节点仍在在线吗?
- 节点是干净停止,还是发生了崩溃?干净停止意味着
searchd正常关闭并在退出前有时间保存其复制状态。崩溃、断电或kill -9不是干净停止。 - 集群的存活部分是否仍具有法定人数?法定人数意味着足够多的节点仍能相互看到,以安全地保持可写集群。
- 如果所有节点都已关闭,应首先启动哪个节点以恢复集群?
有用的检查:
SHOW STATUS LIKE 'cluster_<name>_status'SHOW STATUS LIKE 'cluster_<name>_size'SHOW STATUS LIKE 'cluster_<name>_node_state'- 如果所有节点都已关闭,请检查
grastate.dat,这是存储在集群数据目录中的小型复制状态文件。特别注意seqno和safe_to_bootstrap:在干净关闭后,通常首选启动的节点是具有最先进seqno和safe_to_bootstrap: 1的节点。有关完整的引导程序,请参阅 重新启动集群。
干净关闭后 grastate.dat 可能的样子示例:
# saved replication state
version: 2.1
uuid: <cluster-uuid>
seqno: 12345
safe_to_bootstrap: 1
在此示例中:
seqno: 12345表示此节点知道到序列号 12345 的事务safe_to_bootstrap: 1表示此节点被标记为可以首先启动
在干净关闭的所有节点都关闭的恢复中,这通常是您使用 --new-cluster 首先启动的节点类型,以恢复集群。
恢复后,等待重新启动的节点报告 cluster_<name>_status=primary 和 cluster_<name>_node_state=synced 后,再将其视为完全可写。您可以使用 SHOW STATUS LIKE 'cluster_<name>_status' 和 SHOW STATUS LIKE 'cluster_<name>_node_state' 检查这一点。在本地测试中,重新启动的节点有时会在达到 synced/primary 之前短暂显示 cluster_<name>_node_state=joining 和 cluster_<name>_status=disconnected。
如果节点 A 正常关闭,节点 B 和 C 会继续处理写入。您可以使用 SHOW STATUS LIKE 'cluster_<name>_status' 和 SHOW STATUS LIKE 'cluster_<name>_size' 确认这些节点上的集群仍然健康。
当节点 A 重新启动时,它会自动重新加入集群。在同步完成之前,不要向该节点发送写入。检查 SHOW STATUS LIKE 'cluster_<name>_status' 和 SHOW STATUS LIKE 'cluster_<name>_node_state',并等待 primary / synced。
如果供体节点 B 或 C 仍然在它们的复制缓存中拥有节点 A 错过的所有事务,节点 A 可以使用增量状态传输 (IST) 进行追赶。IST 代表增量状态传输。这意味着节点仅接收它错过的事务,因此恢复通常更快且更轻量。否则,它将需要快照状态传输 (SST)。SST 代表快照状态传输。这意味着从另一个节点复制表文件,而不是仅仅重放缺失的事务。SST 更重:通常更慢,移动更多数据,并且可能在大型集群上使恢复更具破坏性。
如果节点 A 和 B 被干净关闭,节点 C 保持在线,节点 C 可以继续接受写入。如果您想确认它现在是唯一活动的节点,请在节点 C 上检查 SHOW STATUS LIKE 'cluster_<name>_status' 和 SHOW STATUS LIKE 'cluster_<name>_size'。
当节点 A 和 B 重新启动时,它们会自动重新加入并从节点 C 同步。在它们重新加入时,检查 SHOW STATUS LIKE 'cluster_<name>_status'、SHOW STATUS LIKE 'cluster_<name>_node_state' 和 SHOW STATUS LIKE 'cluster_<name>_size'。等待所有节点显示 primary / synced 并且集群大小符合预期后,再将恢复视为完成。
如果所有节点都正常关闭,集群完全离线,必须以特殊方式重新启动,以便成为集群的第一个运行节点。
在干净关闭时,每个节点将其最后一个事务号写入 grastate.dat。最后关闭的节点是首先启动的最安全节点:
- 它具有最先进
seqno - 它具有
safe_to_bootstrap: 1
使用 --new-cluster 启动该节点。这会告诉 Manticore 从此节点开始一个新的集群副本。如果您通过 Linux 上的 systemd 运行 Manticore,请使用 manticore_new_cluster。它会为您以 --new-cluster 模式启动 Manticore。
之后,正常启动其余节点并让它们重新加入。通过 SHOW STATUS LIKE 'cluster_<name>_status'、SHOW STATUS LIKE 'cluster_<name>_node_state' 和 SHOW STATUS LIKE 'cluster_<name>_size' 验证恢复。
如果您首先引导一个较不先进的节点,一个更先进的节点可能会稍后加入它并从较旧状态接收完整的 SST,这可能会丢弃仅存在于更先进节点上的事务。这就是为什么 safe_to_bootstrap: 1 的节点应是您的首选。
如果节点 A 因崩溃或网络问题消失,节点 B 和 C 会首先尝试重新连接到它。如果失败,它们会将其从集群中移除,重新计算法定人数,并继续作为主集群运行。
在本地测试中,对等节点的移除并非立即发生:存活的节点会在几秒钟内保持旧的集群大小,之后才会丢弃失败的对等节点并切换到较小的主集群。
当节点 A 重新启动时,它会自动重新加入,并以与干净的一节点关闭后相同的方式进行同步。同样,使用 SHOW STATUS LIKE 'cluster_<name>_status'、SHOW STATUS LIKE 'cluster_<name>_node_state' 和 SHOW STATUS LIKE 'cluster_<name>_size' 来确认恢复已完成。
如果节点 A 和 B 都丢失,只剩节点 C 在运行,那么在三个节点的集群中,节点 C 将不再拥有法定人数。它会切换到 non-primary 并拒绝写入。
写入错误是明确的:
ERROR 1064 (42000): cluster '<name>' is not ready, not primary state (synced)
如果节点 A 和 B 仅临时断开连接但仍能互相看到,它们可能会继续接受写入,而节点 C 保持隔离。如果需要查看哪一侧仍可写入,请在每侧使用 SHOW STATUS LIKE 'cluster_<name>_status'。
如果节点 A 和 B 确实崩溃,且节点 C 是唯一希望继续使用的存活副本,请在节点 C 上运行此命令,使其重新变为可写入状态:
如果您已确认其他节点确实离线,请运行:
- SQL
- JSON
SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1POST /cli -d "
SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1
"重要提示:
- 仅在确认其他节点无法到达后运行此命令
- 仅在必须存活的一侧运行
- 引导后,该节点可以再次接受写入,其他节点之后可以从它重新加入
如果所有节点都崩溃,grastate.dat 通常不再适合用于正常引导选择。在本地测试中,所有节点显示:
seqno: -1safe_to_bootstrap: 0
在这种情况下,选择数据最新的节点,并使用--new-cluster-force启动它。这会强制Manticore从该节点启动一个新的集群副本,即使通常的干净关闭元数据不可靠。如果你在Linux上通过systemd运行Manticore,请使用manticore_new_cluster --force。它会为你以--new-cluster-force模式启动Manticore。
然后正常启动其余节点并让它们重新加入。使用 SHOW STATUS LIKE 'cluster_<name>_status'、SHOW STATUS LIKE 'cluster_<name>_node_state' 和 SHOW STATUS LIKE 'cluster_<name>_size' 验证恢复。
偶数大小的集群最容易出现脑裂风险。例如,想象四个节点分裂成两个隔离的对,分布在两个数据中心。每边恰好有原始成员的一半,因此两边都没有法定人数,两边都停止接受写入。
如果在连接恢复前必须恢复写入,请仅选择分裂的一侧,并在该侧运行相同的恢复命令,使该侧重新变为可写入。在执行此操作之前,请在两侧检查 SHOW STATUS LIKE 'cluster_<name>_status',以确定哪一侧当前为非主集群。
选择应保持为可写集群的一侧,然后运行:
- SQL
- JSON
SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1POST /cli -d "
SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1
"永远不要在两侧都执行该语句。如果这样做,您将创建两个独立的主集群,当网络恢复时它们不会自动合并。
在本地测试中,突然失去四节点集群的一半会重现相同的 non-primary 行为,相同的恢复命令使一个存活的一半重新变为 primary。